Git Product home page Git Product logo

lastversion's Introduction

lastversion

Python package PyPI version GitHub Release Documentation Status Codacy Badge Codacy Badge Buy Me a Coffee

Using lastversion in terminal

English | 简体中文

A tiny command-line utility that helps to answer a simple question:

What is the latest stable version for a project?

... and, optionally, download/install it.

lastversion allows finding well-formatted, the latest release version of a project from these supported locations:

  • GitHub
  • GitLab
  • BitBucket
  • PyPI
  • Mercurial
  • SourceForge
  • Wikipedia
  • WordPress plugin directory
  • Arbitrary software sites which publish releases in RSS/ATOM feeds

Why you need lastversion

In general, quite many project authors complicate finding the latest version by:

  • Creating a formal release that is clearly a Release Candidate (rc in tag), but forgetting to mark it as a pre-release

  • Putting extraneous text in release tag e.g. release-1.2.3 or name-1.2.3-2019 anything fancy like that

  • Putting or not putting the v prefix inside release tags. Today yes, tomorrow not. I'm not consistent about it myself :)

  • Switching from one version format to another, e.g. v20150121 to v2.0.1

There is no consistency in human beings.

To deal with all this mess and simply get a well-formatted, last stable version (or download URL!) on the command line, you can use lastversion.

Its primary use is for build systems - whenever you want to watch specific projects for released versions to build packages automatically. Or otherwise require getting the latest version in your automation scripts.

Like I do

lastversion does a little bit of AI to detect if releasers mistakenly filed a beta version as a stable release. It incorporates logic for cleaning up human inconsistency from version information.

Synopsis

lastversion apache/incubator-pagespeed-ngx 
#> 1.13.35.2

lastversion download apache/incubator-pagespeed-ngx 
#> downloaded incubator-pagespeed-ngx-v1.13.35.2-stable.tar.gz

lastversion download apache/incubator-pagespeed-ngx -o pagespeed.tar.gz 
#> downloads with chosen filename

lastversion https://transmissionbt.com/
#> 3.0

lastversion format "mysqld  Ver 5.6.51-91.0 for Linux"
#> 5.6.51

Installation for RPM-based systems

Supported:

  • CentOS/RHEL 7, 8, 9 including clones like AlmaLinux and Rocky Linux
  • Amazon Linux 2
  • Fedora Linux
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install lastversion

Installation for other systems

Installing with pip is easiest:

pip install lastversion

Usage

Typically, you would just pass a repository URL (or repo owner/name to it) as the only argument, e.g.:

lastversion https://github.com/gperftools/gperftools

Equivalently accepted invocation with the same output is:

lastversion gperftools/gperftools

If you're lazy to even copy-paste a project's URL, you can just type its name as argument, which will use repository search API (slower). Helps to answer what is the latest Linux version:

lastversion linux

Or wondering what is the latest version of WordPress?

lastversion wordpress

A special value of self for the main argument, will look up the last release of lastversion itself.

For more options to control output or behavior, see --help output:

usage: lastversion [-h] [--pre] [--sem {major,minor,patch,any}] [-v]
                   [-d [FILENAME]] [--format {version,assets,source,json,tag}]
                   [--assets] [--source] [-gt VER] [-b MAJOR] [--only REGEX]
                   [--exclude REGEX] [--filter REGEX] [--having-asset [ASSET]]
                   [-su] [--even]
                   [--at {github,gitlab,bitbucket,pip,hg,sf,website-feed,local,helm_chart,wiki,system,wp,gitea}]
                   [-y] [--version]
                   [{get,download,extract,unzip,test,format,install,update-spec}]
                   <repo URL or string>

Find the latest software release.

positional arguments:
  {get,download,extract,unzip,test,format,install,update-spec}
                        Action to run. Default: get
  <repo URL or string>  Repository in format owner/name or any URL that
                        belongs to it, or a version string

optional arguments:
  -h, --help            show this help message and exit
  --pre                 Include pre-releases in potential versions
  --sem {major,minor,patch,any}
                        Semantic versioning level base to print or compare
                        against
  -v, --verbose         Will give you an idea of what is happening under the
                        hood, -vv to increase verbosity level
  -d [FILENAME], -o [FILENAME], --download [FILENAME], --output [FILENAME]
                        Download with custom filename
  --format {version,assets,source,json,tag}
                        Output format
  --assets              Returns assets download URLs for last release
  --source              Returns only source URL for last release
  -gt VER, --newer-than VER
                        Output only if last version is newer than given
                        version
  -b MAJOR, --major MAJOR, --branch MAJOR
                        Only consider releases of a specific major version,
                        e.g. 2.1.x
  --only REGEX          Only consider releases containing this text. Useful
                        for repos with multiple projects inside
  --exclude REGEX       Only consider releases NOT containing this text.
                        Useful for repos with multiple projects inside
  --even                Only even versions like 1.[2].x, or 3.[6].x are
                        considered as stable                        
  --filter REGEX        Filters --assets result by a regular expression
  --having-asset [ASSET]
                        Only consider releases with this asset
  -su, --shorter-urls   A tiny bit shorter URLs produced
  --at {github,gitlab,bitbucket,pip,hg,sf,website-feed,local,helm_chart,wiki,system,wp,gitea}
                        If the repo argument is one word, specifies where to
                        look up the project. The default is via internal
                        lookup or GitHub Search
  -y, --assumeyes       Automatically answer yes for all questions
  --version             show program's version number and exit

The --format will affect what kind of information from the last release and in which format will be displayed, e.g.:

  • version is the default. Simply outputs well-formatted version number of the latest release

  • assets will output a newline-separated list of assets URLs (if any), otherwise link to sources archive

  • source will output link to source archive, no matter if the release has some assets added

  • json can be used by external Python modules or for debugging, it is dict/JSON output of an API call that satisfied last version checks

  • tag will emit just the latest release's tag name, which useful if you're constructing download URL yourself or need the tag name otherwise

An asset is a downloadable file that typically represents an executable, or otherwise "ready to launch" project. It's what you see filed under formal releases, and is usually a compiled (for a specific platform), program.

Source files are either tarballs or zipballs of sources for the source code of release.

You can display either assets or source URLs of the latest release, by passing the corresponding --format flag, e.g. --format source

You also simply pass --source instead of --format source, and --assets instead of --format assets, as in:

lastversion --assets mautic/mautic 
#> https://github.com/mautic/mautic/archive/2.15.1/mautic-2.15.1.tar.gz

By default, lastversion filters output of --assets to be OS-specific. Who needs .exe on Linux?

To override this behavior, you can use --filter, which has a regular expression as its argument. To disable OS filtering, use --filter ., this will match everything.

You can naturally use --filter in place where you would use grep, e.g. lastversion --assets --filter win REPO

Use case: Work with a multi-project repository

Sometimes a single repository actually hosts many components, and creates releases that have separate version line for each component.

To help lastversion get a component's version for such repos, use --only and --exclude switches. They make lastversion look at only those releases which are tagged (or not) with specified strings.

Example:

lastversion --only chart https://github.com/lastversion-test-repos/autoscaler

The above will report 9.16.0.

lastversion --exclude chart https://github.com/lastversion-test-repos/autoscaler

The above will report a non-chart latest version, 1.23.0.

Useful for hard cases, you can pass in regular expressions for both arguments, by prepending them with tilde, like so:

lastversion --only '~-po.-' https://github.com/lastversion-test-repos/autoscaler

The above will consider only releases tagged with -pod-, or -pov-, etc.

Use case: How to download the latest version of something

You can also use lastversion to download assets/sources for the latest release.

Download the most recent Mautic source release:

lastversion download mautic/mautic 

Customize downloaded filename (works only for sources, which is the default):

lastversion download mautic/mautic -o mautic.tar.gz

You can also directly fetch and extract the latest release's file into the current working directory by using extract command:

lastversion extract wordpress

You can have lastversion output sources/assets URLs and have those downloaded by something else:

wget $(lastversion --assets mautic/mautic)

This will download all assets of the newest stable Mautic, which are two zip files.

How this works: lastversion outputs all asset URLs, each on a new line, and wget is smart enough to download each URL. Magic :)

For releases that have no assets added, it will download the source archive.

To always download the source, use --source instead:

wget $(lastversion --source mautic/mautic)  

Use case: Download specific asset under specified filename

If you want to download specific asset of the last version's release and save the downloaded file under a desired name, combine -d option (for download name) and --filter for specifying assets filter.

Example:

lastversion --pre Aircoookie/WLED --format assets --filter ESP32.bin -d ESP32.bin

Use case: Get the last version (betas are fine)

We consider the latest release is the one that is stable / not marked as beta. If you think otherwise, then pass --pre switch and if the latest version of repository is a pre-release, then you'll get its version instead:

lastversion --pre mautic/mautic 
#> 2.15.2b0

Use case: version of a specific branch

For some projects, there may be several stable releases available simultaneously, in different branches. An obvious example is PHP. You can use --major flag to specify the major release version to match with, to help you find the latest stable release of a branch, like so:

lastversion php/php-src --major 7.2

This will give you current stable version of PHP 7.2.x, e.g. 7.2.28.

Branch selector is easy to be specified after semicolon, and together with the search API, a clean invocation for the same would be:

lastversion php:7.2

The branch selector can also be used to get specific release details, e.g.:

lastversion php:7.2.33 --assets

Use case: releases with specific assets

Sometimes a project makes nice formal releases but delay in uploading assets for releases. And you might be interested in specific asset type always. Then you can make lastversion consider as latest only the last release with specific asset name. Easy with the --having-asset switch:

lastversion telegramdesktop/tdesktop --having-asset "Linux 64 bit: Binary"

The argument value to --having-asset can be made as regular expression. For this, prepend it with tilde sign. E.g. to get releases with macOS installers:

lastversion telegramdesktop/tdesktop --having-asset "~\.dmg$"

You can pass no value to --having-asset at all. Then lastversion will only return the latest release which has any assets added to it:

lastversion telegramdesktop/tdesktop --having-asset

Use case: version of an operating system

The operating systems are usually not versioned through GitHub releases or such. It is a challenge to get the last stable version of an OS other than from its website, or other announcement channels.

An easy compromise that lastversion does about this, is hard coding well-known OS names, and using Wikipedia behind the scenes:

lastversion rocky  #> 8.4 
lastversion windows  #> 10.0.19043.1081
lastversion ios  #> 14.6

You can supply a fully qualified URL to a Wikipedia page for an OS/software project to get version from there, e.g.:

lastversion https://en.wikipedia.org/wiki/Rocky_Linux  #> 8.4

Special use case: NGINX stable vs mainline branch version

lastversion https://nginx.org --major stable #> 1.16.1
lastversion https://nginx.org --major mainline #> 1.17.9

Behind the scenes, this checks with hg.nginx.org which is a Mercurial web repo. Those are supported as well, e.g.

lastversion https://hg.example.com/project/

Mercurial repositories are rather rare these days, but support has been added primarily for NGINX.

Special use case: find the release of a PyPI project

Most Python libraries/apps are hosted on PyPI. To check versions of a project on PyPI, you can use:

lastversion https://pypi.org/project/requests/

If you prefer using a shorter repo name, ensure --at pip switch, like so:

lastversion requests --at pip

Install an RPM asset

If a project provides .rpm assets and your system has yum or dnf, you can install the project's RPM directly, like so:

sudo lastversion install mailspring

This finds MailSpring, gets its latest release info, filters assets for .rpm and passes it to yum / dnf.

You can even set up an auto-updater cron job which will ensure you are on the latest version of a package, like so:

@daily /usr/bin/lastversion install mailspring -y 2>/dev/null

If the Mailspring GitHub repo posts a release with newer .rpm, then it will be automatically installed, making sure you are running the latest and greatest Mailspring version.

You'll even get an email alert after update (standard cron feature).

Needless to say, more often than not, such RPM packages have no idea about all potentially missing dependencies. Thus, only use lastversion install ... if the software is missing from the base yum repositories.

Install an AppImage

If a project provides .AppImage, you can install those directly using lastversion. The AppImage is self-contained Linux executable file. What lastversion does for you, is fetch the latest release's AppImage, installs it under ~/Applications/<app> and makes it executable. Just run:

lastversion install fluent-reader

Test version parser

The test command can be used for troubleshooting or simply well formatting a string with version:

lastversion test 'blah-1.2.3-devel' # > 1.2.3.dev0
lastversion test '1.2.x' # > False (no clear version)
lastversion test '1.2.3-rc1' # > 1.2.3rc1

Scripting with lastversion in bash

Semantic versioning support

Sometimes you only want to check updates for a specific semantic versioning level. Does a project have a new minor release? Does a project have a new major release? To print just the necessary semantic versioning base, use --sem option.

Acceptable values are major, minor, and patch.

lastversion wordpress --sem major
#> 5
lastversion wordpress --sem minor
#> 5.9
lastversion wordpress --sem patch
#> 5.9.3

The value --sem patch can be used to normalize a given result to semantic versioning, if a project doesn't follow the semantics strictly. E.g. sometimes WordPress would publish an x.y release while it's implicitly x.y.0. So let's say WordPress released "5.10":

lastversion wordpress --sem patch
#> 5.10.0

Format any version string

Say you ran mysqld --version and got this output:

mysqld Ver 5.6.51-91.0 for Linux on x86_64 (Percona Server (GPL), Release 91.0, Revision b59139e)

This is rather hard to parse in bash if you want to just extract the major MySQL server version.

lastversion can easily parse out and give the desired information based on desired semantic versioning level:

lastversion --sem major format "mysqld  Ver 5.6.51-91.0 for Linux on x86_64 (Percona Server (GPL) , Release 91.0, Revision b59139e)" 
#> 5

Compare arbitrary versions

Use lastversion for easy comparison of versions on the command line. Compare two versions, the command will output the highest version:

lastversion 1.2.3 -gt 1.2.4
#> 1.2.4

See the exit codes below, to find whether the first argument is a higher version, or the second.

The --sem option described earlier will affect both what's being printed and what semantic versioning base level is being compared, thus the result.

Check for NEW release

When you're building some upstream package, and you did this before, there is a known "last build" version. Automatic builds become easy with:

CURRENTLY_BUILT_VER=1.2.3 # stored somewhere, e.g. spec file in my case
LAST_VER=$(lastversion repo/owner -gt ${CURRENTLY_BUILT_VER})
if [[ $? -eq 0 ]]; then
  # LAST_VER is newer, update and trigger build
  # ....
fi

Here, the -gt is actually a switch passed to lastversion, which acts in a similar fashion to -gt comparison in bash.

There is more to it if you want to make this reliable. See my ranting on RPM auto-builds with lastversion

Check if there is a newer kernel for your Linux machine

LATEST_KERNEL=$(lastversion linux -gt $(uname -r | cut -d '-' -f 1))
if [[ $? -eq 0 ]]; then
  echo "I better update my kernel now, because ${LATEST_KERNEL} is there"
else 
  echo "My kernel is latest and greatest."
fi 

Exit Status codes

Exit status codes are the usual means of communicating a command's execution success or failure. So lastversion follows this: successful command returns 0 while anything else is an error of some kind. For example, when the latest stable release version if found, 0 is returned. 0 is also returned for -gt comparison when leftmost argument is newer than rightmost argument.

Exit status code 1 is returned for cases like no release tag existing for repository at all, or repository does not exist.

Exit status code 2 is returned for -gt version comparison negative lookup, that is when rightmost argument is newer than leftmost argument.

Exit status code 3 is returned when filtering assets of last release yields empty URL set (no match)

Tips

Getting the latest version is heavy on the API, because GitHub does not allow to fetch tags in chronological order, and some repositories switch from one version format to another, so we can't just consider the highest version to be latest. We have to fetch every tag's commit date, and see if it's actually more recent. Thus, it's slower with larger repositories, which have potentially a lot of tags.

Thus, lastversion makes use of caching API response to be fast and light on GitHub API, It does conditional ETag validation, which, as per GitHub API will not count towards rate limit. The cache is stored in ~/.cache/lastversion on Linux systems.

It is much recommended to set up your GitHub API token. Bare API token is enough, you may deselect all permissions. You can then increase your rate limit by adding the following ~/.bashrc file:

export GITHUB_API_TOKEN=xxxxxxxxxxxxxxx

You can use either GITHUB_API_TOKEN or GITHUB_TOKEN environment variable. The former has priority.

For GitLab, you can use a Personal Access Token:

export GITLAB_PA_TOKEN=xxxxxxxxxxxxxxx

Then run source ~/.bashrc. After this, lastversion will use it to get larger API calls allowance from GitHub.

Usage in a Python module

You can use lastversion.has_update(...) to find whether an update for existing version of something is available, simply:

from lastversion import has_update
latest_version = has_update(repo="mautic/mautic", current_version='1.2.3')
if latest_version:
    print(f'Newer Mautic version is available: {latest_version}')
else:
    print('No update is available')

The lastversion.has_update(...) function accepts any URL from a repository (or its short name , e.g. owner/name) and you should pass an existing/current version.

If you are checking version of a project on PyPi, supply an additional at='pip' argument, in order to avoid passing the full PyPI URI of a project, and remove ambiguity with GitHub hosted projects. For example, checking for newer Requests library:

from lastversion import has_update
latest_version = has_update(repo="requests", at='pip', current_version='1.2.3')
if latest_version:
    print('Newer Requests library is available: {latest_version}')
else:
    print('No update is available')

The has_update function returns either:

  • The Version object
  • False if there is no newer version than the one given

Alternatively, invoke lastversion.latest(...) function to get the latest version information for a repo.

from lastversion import latest
from packaging import version

latest_mautic_version = latest("mautic/mautic", output_format='version', pre_ok=True)

print(f'Latest Mautic version: {latest_mautic_version}')

if latest_mautic_version >= version.parse('1.8.1'):
    print('It is newer')

With output_format='version' (the default), the function returns a Version object, or None. So you can do things like above, namely version comparison, checking dev status, etc.

With output_format='dict', a dictionary returned with the latest release information, or False. The dictionary keys vary between different project locations (GitHub vs BitBucket, for example), but are guaranteed to always have these keys:

  • version: Version object, contains the found release version, e.g. 1.2.3
  • source: string, the identifier of the project source, e.g. github, or gitlab
  • tag_date: datetime object, the release date, e.g. 2020-12-15 14:41:39
  • from: string, contains fully qualified URL of the project
  • tag_name: string, version control tag name corresponding to the release

The lastversion.latest function accepts 3 arguments

  • repo, in format of <owner>/<name>, or any URL under this repository, e.g. https://github.com/dvershinin/lastversion/issues
  • format, which accepts the same values as when you run lastversion interactively, as well as dict to return a dictionary as described above
  • pre_ok, boolean for whether to include pre-releases as potential versions
  • at, specifies project location when using one-word repo names, one of github, gitlab, bitbucket, pip, hg, sf, website-feed, local

Using in Continuous Integration

You can also use lastversion directly in your GitHub action workflows, with lastversion-action.

Feature Requests and Enhancements

Only features that are essential to GitHub releases are prioritized. If your issue or suggested feature is outside the current focus, here's how you can help make it happen:

  • Contribute: We encourage you to submit a pull request with your proposed changes or enhancement.
  • Donate: If you'd like to see a feature developed but cannot contribute code, consider making a donation. Your donations help us allocate resources to work on additional features and improvements.

Sponsored Message

GetPageSpeed RPM Repository: Enhance your server performance with our NGINX modules and performance tools. Visit GetPageSpeed.com to learn more and subscribe for access.

DeepSource

lastversion's People

Contributors

add-sp avatar anotherfoxguy avatar deepsource-autofix[bot] avatar deepsourcebot avatar dvershinin avatar eumiro avatar henryiii avatar ilanbeloglovsky avatar kianmeng avatar lxl66566 avatar snyk-bot avatar stephrobert avatar tekktrik avatar trellixvulnteam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lastversion's Issues

lastversion foo.spec

  • Ability to pass a path to a .spec file instead of repo name/URL.

This will allow for easy updating of the Version: tag in spec files without adding extra tools (spectool2)...

lastversion foo.spec

RPM spec must be prepared.

lastversion does:

  • examines the spec file for a global upstream_github (used as repo instead of Source0:), uses Source0:? when not found...
  • examines the spec file for a global lastversion_major (used as --major), e.g. for building Varnish 6.0.x series only
  • if a newer version is found:
    • update/add %global lastversion_tag ... which is same as spec_tag field from JSON output
    • update/add %global lastversion_dir
    • reset Release: 1%{?dist}
    • update License: with rpmspec_license field from JSON output, if any

Needs the ability to specify semver constraint in the spec file, e.g. lastversion_semver patches should only update 1.2.x

Updating spec files for commit-based releases

When invoked against spec file, check existence of "commit" global. If such exists then fetch latest commit and update it in the spec file. Also update or add commit_date global. Update release field to:

  • if no release or tag exists at all, set release to 0.snapinfo
  • if there is any release, we are assuming that the latest commit represents a post-release, so 1.snapinfo
Snapinfo = git<commit date><short commit>

Example: https://github.com/gnachman/iTerm2-shell-integration

python3 version of lastversion for CentOS/RHEL 7, 8

Installing lastversion on rhel7 it seems like it's installed with python2. Can you make it so it's installed with python3?

Installed:
  lastversion.noarch 0:1.4.0-1.el7

Dependency Installed:
  python-feedparser.noarch 0:5.1.3-3.el7         python-requests.noarch 0:2.6.0-10.el7 python2-CacheControl.noarch 0:0.12.6-3.el7 python2-appdirs.noarch 0:1.4.4-1.el7
  python2-beautifulsoup4.noarch 0:4.6.3-2.el7sat python2-distro.noarch 0:1.2.0-3.el7   python2-lastversion.noarch 0:1.4.0-1.el7   python2-lockfile.noarch 1:0.11.0-17.el7
  python2-msgpack.x86_64 0:0.5.6-5.el7           python2-packaging.noarch 0:16.8-6.el7 python2-six.noarch 0:1.9.0-0.el7           python2-tqdm.noarch 0:4.50.2-1.el7

Failed:
  python-urllib3.noarch 0:1.10.2-7.el7

Then I get this error:

$ lastversion --version
Traceback (most recent call last):
  File "/usr/bin/lastversion", line 9, in <module>
    load_entry_point('lastversion==1.4.0', 'console_scripts', 'lastversion')()
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 378, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2566, in load_entry_point
    return ep.load()
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2260, in load
    entry = __import__(self.module_name, globals(),globals(), ['__name__'])
  File "/usr/lib/python2.7/site-packages/lastversion/__init__.py", line 14, in <module>
    from .lastversion import __self__
  File "/usr/lib/python2.7/site-packages/lastversion/lastversion.py", line 22, in <module>
    from cachecontrol import CacheControl
  File "/usr/lib/python2.7/site-packages/cachecontrol/__init__.py", line 9, in <module>
    from .wrapper import CacheControl
  File "/usr/lib/python2.7/site-packages/cachecontrol/wrapper.py", line 1, in <module>
    from .adapter import CacheControlAdapter
  File "/usr/lib/python2.7/site-packages/cachecontrol/adapter.py", line 5, in <module>
    from requests.adapters import HTTPAdapter
  File "/usr/lib/python2.7/site-packages/requests/__init__.py", line 58, in <module>
    from . import utils
  File "/usr/lib/python2.7/site-packages/requests/utils.py", line 32, in <module>
    from .exceptions import InvalidURL
  File "/usr/lib/python2.7/site-packages/requests/exceptions.py", line 10, in <module>
    from urllib3.exceptions import HTTPError as BaseHTTPError
  File "/usr/lib/python2.7/site-packages/urllib3/__init__.py", line 10, in <module>
    from .connectionpool import (
  File "/usr/lib/python2.7/site-packages/urllib3/connectionpool.py", line 31, in <module>
    from .connection import (
  File "/usr/lib/python2.7/site-packages/urllib3/connection.py", line 45, in <module>
    from .util.ssl_ import (
  File "/usr/lib/python2.7/site-packages/urllib3/util/__init__.py", line 4, in <module>
    from .request import make_headers
  File "/usr/lib/python2.7/site-packages/urllib3/util/request.py", line 5, in <module>
    from ..exceptions import UnrewindableBodyError
ImportError: cannot import name UnrewindableBodyError

Issue with NGINX assets

Hello, when trying to get the latest version of nginx, there is an issue with retrieving the assets:

lastversion --format assets nginx

Traceback (most recent call last):
  File "/usr/bin/lastversion", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.8/site-packages/lastversion/lastversion.py", line 246, in main
    res = latest(args.repo, args.format, args.pre, args.filter,
  File "/usr/lib/python3.8/site-packages/lastversion/lastversion.py", line 92, in latest
    return s.get_assets(release, short_urls, assets_filter)
AttributeError: 'MercurialRepoSession' object has no attribute 'get_assets'

Same issue when using --format json
Is this something that can be fixed?

Thanks

no assets found when ci/cd is working?

Hi,

I have discovered your amazing tool, and I have tested in a Fedora the install feature (it will be great to support apt too if deb is finded).

I have tested the Drawio desktop client who provides binaries and packages in the release https://github.com/jgraph/drawio-desktop/releases
But a new version was published 2 hours ago, the 15.3.7 but was not declared as "Latest release". I suppose that CI/CD is building binaries and the flag "Latest release" will move when all is done.

It's possible to point on "Latest release" and not only to the latest version?

The consequence is that I have : ERROR: No assets found to install
for lastversion install -y jgraph/drawio-desktop

There is a screenshot and the source code of the releases page :

Capture d’écran du 2021-09-28 17-51-10
https _github.com_jgraph_drawio-desktop_releases.txt

Implement quiet mode

Is it possible for you to implement a --quiet tag to prevent lastversion to produce a big output because when I need to log what all my scripts do, I see 100+ lines from lastversion indicating each download percentage unit.

Lastversion no longer works with some repo

Hello @dvershinin

Since a few days, lastversion is no longer working with some repositories.

For example :

[root@master ~]# lastversion php
No release was found
[root@master ~]# lastversion php/php-src --major 7.2
No release was found
[root@master ~]# lastversion openssl
No release was found

Is there any chance you can fix this?

Thank you in advance.
Regards,

atroubat

How to set name of downloaded file?

This command downloads a file called rain-v1.2.0_linux-amd64.zip:

lastversion \
--filter linux-amd64.zip \
--assets \
download https://github.com/aws-cloudformation/rain

I want to call the downloaded copy rain.zip (no version at the end) so that it's easier to process in a script.

The --download option is supported to download with a custom filename.

lastversion \
--filter linux-amd64.zip \
--assets \
--download rain.zip \
download https://github.com/aws-cloudformation/rain

But the name of the downloaded file is the same.

Am I missing something?

Mention GITHUB_API_TOKEN in `--help`

Hi Danila,

A couple of suggestions

  • include GITHUB_API_TOKEN in the usage help.
  • change Get the lastest => Find the latest

parser = argparse.ArgumentParser(description='Get the latest release from '
'GitHub/GitLab/BitBucket.',
prog='lastversion')

parser = argparse.ArgumentParser(description='Find the latest release from ' 
                                             'GitHub/GitLab/BitBucket.', 
                                 epilog='ProTip: set GITHUB_API_TOKEN env var '
									    'as per https://github.com/dvershinin/lastversion#tips',)
                                 prog='lastversion')

Should look something like this:

$ lastversion --help
usage: lastversion [-h] [--pre] [--verbose] [-d [FILENAME]] [--format {version,assets,source,json,tag}] [--assets] [--source] [-gt VER] [-b MAJOR]
                   [--filter REGEX] [-su] [-y] [--version]
                   [action] <repo or URL>

Find the latest release from GitHub/GitLab/BitBucket.

positional arguments:
...
  --version             show program's version number and exit

ProTip: set GITHUB_API_TOKEN env var as per https://github.com/dvershinin/lastversion#tips

Examine use of feeds

It's possible to use e.g. releases or tags feeds which would yield significant performance benefits if the desired information is contained there (because the recency information is readily available, which is not if used /tags API).

But this would bring extra dependencies (feedparser or...)?

Suggestion: Show the source from which fetched version

The package is capable of fetching version from multiple sources, but it wont show what was the version source when using
output_format='version' which is also the default.
I think it would be really good if the returned object also contained the source of the version

Ability to specify only desired semver level for -gt or has_update()

Most RPM-based auto-builds should only work with minor semantic version updates, because major updates bring API-incompatible changes, and as such aren't very suitable for distros aiming stability.

E.g.

# return success for any version newer than 1.2.3 (default)
lastversion repo --semver major -gt 1.2.3 

# return success for any version newer than 1.2.3 but below 2.0.0
lastversion repo --semver minor -gt 1.2.3

# return success only for version 1.2.4 to 1.2.9
lastversion repo --semver patch -gt 1.2.3 

Returned another exit status code 4 if -gt "failed" due to semver constraints. (so that it is possible to script things like sending an email if major release is out to review whether it should be re-incorporated to build)

Support many more software sites using feeds

For software that isn't stored in any of the supported providers (GitHub, BitBucket, etc.), the latest version can be obtained through website feeds discovery.

Example Filezilla client. There are no SVN tags even in viewvc.
However, the RSS feed can be discovered from the homepage:

<link rel="alternate" type="application/atom+xml" title="FileZilla News" href="newsfeed.php" />

... which contains releases info:

 <entry>
   <title>FileZilla Client 3.50.0 released</title>
   <link href="https://filezilla-project.org/"/>
   <id>filezilla-project.org:2020-08-27T17:55:00Z</id>
   <updated>2020-08-27T17:55:00Z</updated>
   <summary type="xhtml">
     <div xmlns="http://www.w3.org/1999/xhtml">
       <h4>Bugfixes and minor changes:</h4><ul><li>Minor fixes to Tardigrade integration</li>
</ul>
     </div>
  </summary>
 </entry>

A similar website, http://nginx.org/ (which already works in lastversion through Mercurial provider), can be supported likewise.

However, need to be able to specify keywords (filter) for title tags to consider extracting releases from (generic website feeds often have multiple projects's info).

lastversion https://filezilla-project.org/ --only "FileZilla Client"
#> 3.50.0

exception when trying to fetch version of mozilla/rhino

I try to fetch the version of mozilla/rhino.
Thats how i run the command"
lastversion mozilla/rhino
and i get the following error:

  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\Ilan Beloglovsky\AppData\Local\Programs\Python\Python37\Scripts\lastversion.exe\__main__.py", line 7, in <module>
  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\site-packages\lastversion\lastversion.py", line 253, in main
    args.shorter_urls, args.major, args.only)
  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\site-packages\lastversion\lastversion.py", line 53, in latest
    release = s.get_latest(pre_ok=pre_ok, major=major)
  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\site-packages\lastversion\GitHubRepoSession.py", line 464, in get_latest
    ret = self.find_in_tags_via_graphql(ret, pre_ok, major)
  File "c:\users\ilan beloglovsky\appdata\local\programs\python\python37\lib\site-packages\lastversion\GitHubRepoSession.py", line 255, in find_in_tags_via_graphql
    d = node['target']['tagger']['date']
KeyError: 'tagger'

I use
lastversion==1.3.1
windows 10 Pro==20H2

lastversion install REPO

Download distro-specific --assets to temp dir and invoke package manager, e.g. apt/yum depending on distro to directly install the latest version.

PyPI support

Hey dvershinin,

May I know for this lastversion module, does it only check those other modules available in GITHUB when doing lastversion.has_update function? There's this python module called lockfile, I've attached the homepage to this module down below.
I got this question because, in my venv, the lockfile module is already up to date at version 0.12.2, but when I do the has_update function, it shows that the latest version is 2.9.2 instead.

code:
import lastversion

latest_ver = lastversion.lastversion.has_update(repo="lockfile", current_version="0.12.2")
print(latest_ver)

2.9.2

link to lockfile module:
https://launchpad.net/pylockfile

screenshot

Last version isn't actually last verison. It's last published version

Hello

Few days ago I've seen Prometheus update where they published v2.19.1 and v2.20.0 on Github at same time, but v2.19.1 was shown by Lastversion as latest one. Is this bug or Lastversion doesn't take into consideration multiple releases to aggregate latest one according semver or other standard?

Error in docker build linux/arm/v7

This is an awesome tool. But I had a problem in my multi-arch docker build.
I cant replicate it outside of travis (cant get qemu to run locally).

the error is this:

#51 [linux/arm/v7 builder 4/7] RUN lastversion mutability/mlat-client --down...
1314#51 4.477 Traceback (most recent call last):
1315#51 4.477   File "/usr/local/bin/lastversion", line 8, in <module>
1316#51 4.477     sys.exit(main())
1317#51 4.477   File "/usr/local/lib/python3.8/site-packages/lastversion/lastversion.py", line 430, in main
1318#51 4.477     version = latest(args.repo, args.format, args.pre, args.newer_than, args.filter,
1319#51 4.477   File "/usr/local/lib/python3.8/site-packages/lastversion/lastversion.py", line 256, in latest
1320#51 4.477     the_date = r_commit.json()['committer']['date']
1321#51 4.477 KeyError: 'committer'

It works fine for v6 and all other...

Link to the travis fail:
https://travis-ci.com/github/ShoGinn/adsbexchange-mlat/builds/153330515

excerpt from the failed command

FROM --platform=$TARGETPLATFORM python as builder


WORKDIR /mlat-client


RUN pip3 install --upgrade shiv importlib-resources lastversion


RUN \
    lastversion mutability/mlat-client --download mlat-client.tar.gz && \

Support GITHUB_TOKEN env.

Many other tools, including the GitHub CLI and Hub, use GITHUB_TOKEN as the environment variable used to authenticate. In CI/CD environments, this would reduce boilerplate slightly when using your tool along with theirs.

I realize this ticket is not a huge blocker, so feel free to close. But I did want to register the request.

Thanks for a great project. It's very useful.

Handle full URL

Often a script has the full URL , and while it is easy enough to cut the string in half, it would be useful it let lastversion handle it.

> python3 -m lastversion --source http://github.com/Yelp/swagger_spec_validator
{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}No release was found

This might also be useful for supported enterprise GitHub which have their own domain.

Ability to parse/check Helm chart repository metadata

I've been trying to get version data for Helm charts where there is no apparent git tag or release, this is pretty common for repositories that contain multiple Helm charts.
Example: https://github.com/bitnami/charts/tree/master/bitnami

I see a couple various ways of doing this.

  1. All charts has a Chart.yaml that contains a version, example: https://github.com/bitnami/charts/blob/master/bitnami/apache/Chart.yaml

  2. Most repositories, but not all, produce a repository manifest. Example: https://charts.bitnami.com/bitnami/index.yaml

[Feature Request] --download should work with --filter and --assets

$ lastversion --assets --filter amd64.deb cli/cli gives me the url of the file I want, but adding --download doesn't work. I know that the README suggests wget $(lastversion --assets --filter amd64.deb cli/cli) but it would be nice to handle it without resorting to subshells or xargs.

Add __main__

It would be nice if it was able to be run as a module

> python3 -m lastversion --source SkiftCreative/python-change-case
/usr/bin/python3: No module named lastversion.__main__; 'lastversion' is a package and cannot be directly executed

Only download last version if you have not already

First... THANK YOU for LastVersion! It is amazing!!
Please close this ASAP as its more a feature request than an issue.
I am trying to keep software updated once per week, but i do not want to download a gigabyte every week to find out half of it is not updated from last week (same version still) is there OR could there be a way too download my list of releases only if it is a new version? (not just last version) Thank you for your work, its appreciated!

Feature Request: more options please

Feature Request

Can you add some more options?

potential usage output

usage: lastversion [-hvV] [--pre] [--api|--nosniff] [--novalidate] [--assets] REPO

Get latest release from GitHub.

positional arguments:
  REPO             	GitHub repository in format owner/name

optional arguments:
# -h, --help    	show this help message and exit
  -V, --version 	show version and exit
  -v, --verbose		Show URIs being tested	

  --pre		   		Include pre-releases in potential versions
  --assets			Show download URL of assets for last version
  --nosniff, --api	use api.github.com
# --novalidate

  --self        	show the latest version of 'lastversion'

command line options

verbose

Show the URIs being tested, especially in the for release in r.find_all loop.

Also useful info if --pre happens.

query this repo

Currently:

$ lastversion dvershinin/lastversion
0.0.5

$ lastversion --nosniff dvershinin/lastversion
0.0.8

$ hub api /repos/dvershinin/lastversion/releases/latest \
  | jq -r '.tag_name, .html_url, .tarball_url'
0.0.8
https://github.com/dvershinin/lastversion/releases/tag/0.0.8
https://api.github.com/repos/dvershinin/lastversion/tarball/0.0.8

New:

$ lastversion --self
0.0.8

internal version

Add an internal version number

$ lastversion --version
lastversion 0.0.8 (c) 2019 ...

Verbose mode shows binary version and repo?

$ lastversion --verbose --version
lastversion 0.0.8 (c) 2019 ...
github release: 0.0.9

pre-releases

I ended up here today, via one of the curl | jq gists because I was looking for a way to find pre-releases. In this case:

$ lastversion mautic/mautic
2.15.1

But I'm looking for a direct download link for 2.15.2-beta... which I worked out during this post.

$ tag=$( hub api /repos/mautic/mautic/tags | jq -r '.[0].name')
$ echo $tag
2.15.2-beta
$ hub api /repos/mautic/mautic/releases/tags/${tag} | jq -r '.tag_name, .assets[].browser_download_url'
2.15.2-beta
https://github.com/mautic/mautic/releases/download/2.15.2-beta/2.15.2-beta-update.zip
https://github.com/mautic/mautic/releases/download/2.15.2-beta/2.15.2-beta.zip
$ lastversion --pre mautic/mautic
2.15.2-beta

download urls

Show download URL of assets for last version found.
Be that: .assets[].browser_download_url for correctly formatted Releases, or
.tarball_url/.zipball_url when you have to use '/releases/:tag`

zipball vs tarball

platform check, win32 = zipball ?

--api

Because I don't under --nosniff at all 😁


Thanks in advance.

Virgil

lastversion returns None randomly

I'm using lastversion as python module in a code that being executed by celery
this is my code:

try:
                version = lastversion.latest(f'{org}/{lib}', output_format='dict', pre_ok=False)

                if version:
                    # Use the version
                else:
                    logger.error(f"Failed to fetch version for {org}/{lib}, got: {str(version)}")
            except Exception as e:
                logger.exception(f"An error occurred while trying to fetch version for {org}/{lib}", e)

I execute this code inside a loop that has around 45 iteration
For some reason beyond my understanding from time to time the function returns None but when i look at my logs i see that the module in fact DID managed to get the last version of that packages that he then returns None for them:
image

It happens with SiliconLabs/uC-OS2 (but not only)
When i run the same code in IDLE it works just fine

'HTTPResponse' object has no attribute 'chunked'

Installed using pip

lastversion https://github.com/php/php-src

Traceback (most recent call last):
File "/usr/bin/lastversion", line 9, in
load_entry_point('lastversion==1.1.1', 'console_scripts', 'lastversion')()
File "/usr/lib/python2.7/site-packages/lastversion/lastversion.py", line 195, in main
args.shorter_urls, args.major)
File "/usr/lib/python2.7/site-packages/lastversion/lastversion.py", line 53, in latest
release = s.get_latest(pre_ok=pre_ok, major=major)
File "/usr/lib/python2.7/site-packages/lastversion/GitHubRepoSession.py", line 137, in get_latest
r = self.get('https://{}/{}/releases.atom'.format(self.hostname, self.repo))
File "/usr/lib/python2.7/site-packages/lastversion/GitHubRepoSession.py", line 46, in get
r = super(GitHubRepoSession, self).get(url, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 498, in get
return self.request('GET', url, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 486, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 598, in send
r = adapter.send(request, **kwargs)
File "/usr/lib64/python2.7/site-packages/cachecontrol/adapter.py", line 53, in send
resp = super(CacheControlAdapter, self).send(request, **kw)
File "/usr/lib/python2.7/site-packages/requests/adapters.py", line 437, in send
return self.build_response(request, resp)
File "/usr/lib64/python2.7/site-packages/cachecontrol/adapter.py", line 107, in build_response
if response.chunked:
AttributeError: 'HTTPResponse' object has no attribute 'chunked'

Incorrect lastversion for a specific repo

Hello,
Thanks very much for you app! I'm using the lastest version and have an issue.

For portainer/portainer, it retrieves a lastversion of 2.6.2. However, even though this version is out, it is not the "latest" release which is 2.6.1 as shown here : https://github.com/portainer/portainer/releases/latest

Is this normal behavior? Can I avoid it?

Thanks!

Edit : I call the app with

lastversion "https://github.com/portainer/portainer"

Apt support

I'm interested in using this for apt repositories. Would you able to add that or accept a pull request if I implemented it?

There's a command line way to do this: apt-cache madison <pkg_name>, which helpfully prints out the versions available in the correct order from your distro's apt repos as well as any custom ones you've added. I'm not sure if Python's apt library implements this function or if there's another way to do it but calling that from a subprocess should work fine.

Another thing I was thinking that might be useful was a comparison feature. For example, the standard Ubuntu repos will have older versions of packages than those available through other sources e.g. Github. So maybe you'd be interested to see the latest version of some package from source X but also that there's a newer one available from this other source. One complication with this is that packages in Ubuntu repos will have different names and version formats than their Github counterparts. This is just a secondary idea though.

Using personal token with python code

Hi,

I see how you can use a personal token when you use the command line but is there a way to do the same when using lastversion in python code?

Thanks

Paginate /tags

Some repos like php-src have more than 100 tags and to get now ancient branch release like 7.0, need to paginate /tags requests.

Fetch assets

What about adding support for fetching the specified assets?

asset URL filter

# todo logic for filtering assets based on... ?

a --filter command-line option and let the user decide how to filter the asset URLs?

$ lastversion --assets stedolan/jq
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-1.6.tar.gz
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-1.6.zip
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux32
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-win32.exe
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-win64.exe

$ lastversion --assets stedolan/jq --filter linux64
https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64

$ lastversion --assets github/hub --filter windows-amd64
https://github.com/github/hub/releases/download/v2.12.3/hub-windows-amd64-2.12.3.zip

Now to get all the applications I use to publish usable Release assets when binaries are hosted outside Github.

I'm looking at you @koalaman, and hoping! 🤣

$ lastversion --assets koalaman/shellcheck
https://github.com/koalaman/shellcheck/archive/v0.7.0/shellcheck-v0.7.0.tar.gz

Argument -gt does not work

Hi,

I did my first steps with lastversion recently. I wrote some simple script to download DEB packages from Github repositories, if there's a new version availabe. So, nothing unknown for you.

But I could not get the argument -gt to work as expected. In fact, if the last version of the repository release is the same as the value to compare with (e.g. not "greater than"), lastversion seems to ignore the argument.

I tried a modification of the script which was described here, too, just to check if it works:

LASTVER=$(lastversion dvershinin/lastversion -gt 1.2.6)
echo $LASTVER
if [[ $? -eq 0 ]]; then
  # LASTVER is newer
  echo "Newer version available"
else
  echo "Nothing new"
fi

Output:

1.2.6
Newer version available

Tried several repositories which did not work. So seems like a bug of lastversion.

My environment:

uname -a
Linux vm 4.19.0-13-amd64 #1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux

cat /etc/debian_version
10.7

python3 --version
Python 3.7.3

lastversion --version
lastversion 1.2.6

Tried with repositories

dvershinin/lastversion
cdr/code-server
arendst/tasmota

Errors with some repositories (Datadog, Grafana)

Thank you for this useful project, it works very well !

Except for 2 repositories:

  • Grafana : the latest version is 6.2.2 and lastversion outputs 5.4.4
  • Datadog-agent : lastversion fails with an error:
Traceback (most recent call last):
  File "/usr/local/bin/lastversion", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/site-packages/lastversion/lastversion.py", line 95, in main
    version = latest(args.repo, args.sniff, args.validate)
  File "/usr/local/lib/python2.7/site-packages/lastversion/lastversion.py", line 41, in latest
    the_version = release.find("a").text
AttributeError: 'NoneType' object has no attribute 'text'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.