{ "info": { "author": "Danila Vershinin", "author_email": "info@getpagespeed.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Operating System :: OS Independent", "Topic :: Software Development" ], "description": "# lastversion\n\n[![Build Status](https://travis-ci.org/dvershinin/lastversion.svg?branch=master)](https://travis-ci.org/dvershinin/lastversion)\n[![PyPI version](https://badge.fury.io/py/lastversion.svg)](https://badge.fury.io/py/lastversion)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/380e3a38dc524112b4dcfc0492d5b816)](https://www.codacy.com/manual/GetPageSpeed/lastversion?utm_source=github.com&utm_medium=referral&utm_content=dvershinin/lastversion&utm_campaign=Badge_Grade)\n\nA tiny command line utility that helps to answer one simple question:\n\n> What is the latest *stable* version for a GitHub project?\n\n... and, optionally, download it.\n\nGitHub has an API endpoint [here](https://developer.github.com/v3/repos/releases/#get-the-latest-release). But if you're here, then you know how it sucks:\n\nA release would show up in this API response *only* if it was filed formally using GitHub release interface.\nSometimes project authors use formal releases, and next thing you know, for next release they won't.\nThere is no consistency in human beings.\n\nOK, you think you could use another API endpoint to [list tags](https://developer.github.com/v3/repos/#list-tags).\nTags *usually* represent a release, however, the API does not sort them chronologically. \nMoreover, you might get something like \"latest-stable\" for a tag name's value.\n\nIn general, quite many project authors complicate things further by:\n\n* Creating a formal release that is clearly a Release Candidate (`rc` in tag), but forget to mark it as a pre-release\n* Putting extraneous text in release tag e.g. `release-1.2.3` or `name-1.2.3-2019` anything fancy like that\n* Putting or not put a 'v' prefix to release tags. Today yes, tomorrow not. I'm not consistent about it myself :)\n* Switching from one version format to another, e.g. `v20150121` to `v2.0.1`\n\nTo deal with all this mess and simply get well-formatted, last *stable* version (or download URL!) on the command line, you can use `lastversion`.\n\nIts primary use is for build systems - whenever you want to watch specific repositories for released versions in order to build packages automatically.\nOr otherwise require getting latest version in your automation scripts.\n\n[Like I do](https://www.getpagespeed.com/redhat)\n\n`lastversion` does a little bit of AI in order to detect if releasers mistakenly filed beta version as a stable release.\nIt uses both of the API endpoints and incorporates logic for cleaning up human inconsistency from version information.\n\n## Synopsis\n\n lastversion apache/incubator-pagespeed-ngx #> 1.13.35.2\n lastversion apache/incubator-pagespeed-ngx -d #> downloaded incubator-pagespeed-ngx-v1.13.35.2-stable.tar.gz\n lastversion apache/incubator-pagespeed-ngx -d pagespeed.tar.gz #> downloads with chosen filename\n\n### Download latest version of something \n\nYou can also use `lastversion` to download assets/sources for the latest release.\n\nDownload the most recent Mautic:\n\n lastversion mautic/mautic --download \n \nCustomize downloaded filename (works only for sources, which is the default):\n\n lastversion mautic/mautic --download mautic.tar.gz\n \nOr you can just have `lastversion` output sources/assets URLs and have those downloaded by something else: \n\n wget $(lastversion --assets mautic/mautic)\n\nThis will download all assets of the newest stable Mautic, which are 2 zip files.\n\nHow this works: `lastversion` outputs all asset URLs, each on new line, and `wget` is smart enough to download each URL. Magic :)\n\nFor releases which have no assets added, it will download source archive. \n\nTo always download source, use `--source` instead:\n\n wget $(lastversion --source mautic/mautic) \n\nAn 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 specific platform), program.\n\nSource files, are either tarballs or zipballs of sources for the source code of release. \n\n### Get last version (betas are fine)\n\nWe consider latest release is the one which is stable / not marked as beta.\nIf 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:\n\n lastversion --pre mautic/mautic #> 2.15.2b0\n\n## Usage\n\n Typically, you would just pass a repository URL (or repo owner/name to it) as the only argument, e.g.:\n\n lastversion https://github.com/gperftools/gperftools\n\nEquivalently accepted invocation with same output is:\n\n lastversion gperftools/gperftools \n\nIf 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).\nHelps to answer what is the latest Linux version:\n\n lastversion linux \n\nOr wondering what is the latest version of Wordpress? :\n\n lastversion wordpress\n \nA special value of `self` for the main argument, will lookup the last release of `lastversion` itself.\n\nFor more options to control output or behavior, see `--help` output: \n\n ```\nusage: lastversion [-h] [--pre] [--verbose]\n [--format {version,assets,source,json}] [--assets]\n [--source] [--version] [-gt VER] [--filter REGEX]\n REPO\n\nGet latest release from GitHub.\n\npositional arguments:\n REPO GitHub repository in format owner/name\n\noptional arguments:\n -h, --help show this help message and exit\n --pre Include pre-releases in potential versions\n --verbose\n --format {version,assets,source,json}\n Output format\n --assets Returns assets download URLs for last release\n --source Returns only source URL for last release\n --version show program's version number and exit\n -gt VER, --newer-than VER\n Output only if last version is newer than given\n version\n --filter REGEX Filters --assets result by a regular expression\n```\n\nThe `--format` will affect what kind of information from last release and in which format will be displayed, e.g.:\n\n* `version` is the default. Just outputs well format version number\n* `assets` will output newline separated list of assets URLs (if any), otherwise link to sources archive\n* `source` will output link to source archive, no matter if the release has some assets added\n* `json` can be used by external Python modules or for debugging, it is JSON output of an API call that satisfied last version checks\n\nYou can use shortcuts `--source` instead of `--format source`, and `--assets` instead of `--format assets`, as in the above examples.\n\n lastversion --source mautic/mautic #> https://github.com/mautic/mautic/archive/2.15.1/mautic-2.15.1.tar.gz\n\nBy default, `lastversion` filters output of `--assets` to be OS specific. Who needs `.exe` on Linux?\n\nTo override this behavior, you can use `--filter`, which has a regular expression as its argument.\nTo disable OS filtering, use `--filter .`, this will match everything.\n\nYou can naturally use `--filter` in place where you would use `grep`, e.g. `lastversion --assets --filter win REPO`\n\n### Scripting with lastversion\n\n#### Check for NEW release\n\nWhen you're building some upstream package, and you did this before, there is a known \"last build\" version.\nAutomatic builds become easy with:\n\n```bash\nCURRENTLY_BUILT_VER=1.2.3 # stored somewhere, e.g. spec file in my case\nLASTVER=$(lastversion repo/owner -gt $CURRENTLY_BUILT_VER)\nif [ $? -eq 0 ]; then\n # LASTVER is newer, update and trigger build\n ....\n```\n\nThere is more to it, if you want to make this reliable.\nSee my ranting on [RPM auto-builds with `lastversion`](https://github.com/dvershinin/lastversion/wiki/Use-in-RPM-building)\n\n#### Status codes\n\nExit status codes are the usual means of communicating a command's execution success or failure. \nSo `lastversion` follows this: successful command returns `0` while anything else is an error of some kind:\n \nExit status code `1` is returned for cases like no release tag existing for repository at all, or repository does not exist.\n\nExit status code `2` is returned for `-gt` version comparison negative lookup.\n\nExit status code `3` is returned when filtering assets of last release yields empty URL set (no match)\n\n### Installation for CentOS 7\n\n yum install https://extras.getpagespeed.com/release-el7-latest.rpm\n yum install lastversion\n\nPackaged install relies on some dependencies that were missing in EPEL or base repository.\nFollowing dependent packages are in our repository as well: \n\n* `python2-CacheControl`\n* newer `python2-msgpack`\n\n## Installation for other systems\n\nThe script is primarily developed for Python 2.7, but is known to work with recent versions like Python 3.7.\nInstalling with `pip` is easiest:\n\n pip install lastversion\n\n## Tips\n\nGetting latest version is heavy on the API, because GitHub does not allow to fetch tags in chronological order, \nand some repositories switch from one version format to another, so *we can't just consider highest version to be latest*.\nWe have to fetch every tag's commit date, and see if it's actually more recent. Thus it's slower with larger repositories, \nwhich have potentially a lot of tags.\n\nThus, `lastversion` makes use of caching API response to be fast and light on GitHub API,\nIt does conditional ETag validation, which, as per GitHub API will not count towards rate limit.\nThe cache is stored in `~/.cache/lastversion` on Linux systems.\n\nIt is *much recommended* to setup your [GitHub API token](https://github.com/settings/tokens) in `~/.bashrc` like this, to increase your rate limit:\n\n export GITHUB_API_TOKEN=xxxxxxxxxxxxxxx\n\nThen run `source ~/.bashrc`. After this, `lastversion` will use it to get larger API calls allowance from GitHub.\n\n## Usage in a Python module\n\n from lastversion import lastversion\n repo = \"mautic/mautic\"\n lastVersion = lastversion.latest(repo, 'version', True)\n print(lastVersion)\n\nWill yield: `2.15.2b0`.\n\nThe `lastversion.latest` function accepts 3 arguments\n\n* `repo`, in format of `/`, or any URL under this repository, e.g. `https://github.com/dvershinin/lastversion/issues` \n* `format`, which accepts same values as when you run `lastversion` interactively\n* `preOk`, boolean for whether to include pre-releases as potential versions\n\n### Check if there is a newer kernel for your Linux machine\n\n```bash\nNEWER_KERNEL=$(lastversion linux -gt $(uname -r | cut -d '-' -f 1))\nif [ $? -eq 0 ]; then\n echo \"I better update my kernel now, because ${KERNEL} is there\"\nelse \n echo \"My kernel is latest and greatest.\"\nfi \n```", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/dvershinin/lastversion", "keywords": "", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "lastversion", "package_url": "https://pypi.org/project/lastversion/", "platform": "", "project_url": "https://pypi.org/project/lastversion/", "project_urls": { "Homepage": "https://github.com/dvershinin/lastversion" }, "release_url": "https://pypi.org/project/lastversion/0.2.4/", "requires_dist": null, "requires_python": "", "summary": "A CLI tool to fetch last GitHub release version", "version": "0.2.4" }, "last_serial": 5964244, "releases": { "0.0.10": [ { "comment_text": "", "digests": { "md5": "2c9487ce70add260a7c9f87157d2c266", "sha256": "e0156e3225c0a479b84c718f03e7eb8d672592196f294ebba5a62b6e5f54f839" }, "downloads": -1, "filename": "lastversion-0.0.10.tar.gz", "has_sig": false, "md5_digest": "2c9487ce70add260a7c9f87157d2c266", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6442, "upload_time": "2019-06-12T19:46:40", "url": "https://files.pythonhosted.org/packages/0d/3a/f9eab0dca47510fcbf3e39c89faeee0dd4bc72cfc2bcb7a5c753110eb166/lastversion-0.0.10.tar.gz" } ], "0.0.11": [ { "comment_text": "", "digests": { "md5": "dd0ac5b1e53e71c5f241a536f3840032", "sha256": "408039d3459f9585d7a00d90cc0a52023ca4bd4ada8c60b1787ac9b7c42870ea" }, "downloads": -1, "filename": "lastversion-0.0.11.tar.gz", "has_sig": false, "md5_digest": "dd0ac5b1e53e71c5f241a536f3840032", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6446, "upload_time": "2019-06-13T06:16:10", "url": "https://files.pythonhosted.org/packages/f3/c5/2de0f579e720d22d4fd81b4c3784b22ada6a57e30e31627da09fdaf298a4/lastversion-0.0.11.tar.gz" } ], "0.0.12": [ { "comment_text": "", "digests": { "md5": "f7cd9d78fa79c50f1532291a48632c06", "sha256": "0704353f0a1805c9ce4cf99ecec89b8b105f8863f8b7e6865dce043d033bbff2" }, "downloads": -1, "filename": "lastversion-0.0.12.tar.gz", "has_sig": false, "md5_digest": "f7cd9d78fa79c50f1532291a48632c06", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6558, "upload_time": "2019-07-24T07:34:08", "url": "https://files.pythonhosted.org/packages/ad/50/f8a623156d438685e5e8bd9eef30c9d0ad2f89dec270951d6c405fdb8c25/lastversion-0.0.12.tar.gz" } ], "0.0.13": [ { "comment_text": "", "digests": { "md5": "c1c06ffe6998637dad3bd76f79d5a946", "sha256": "421d30b7ee1a9acc998d7c5e5b3d6e7921dd34bf47f53394b52503d37da59687" }, "downloads": -1, "filename": "lastversion-0.0.13.tar.gz", "has_sig": false, "md5_digest": "c1c06ffe6998637dad3bd76f79d5a946", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6609, "upload_time": "2019-07-25T06:04:20", "url": "https://files.pythonhosted.org/packages/f6/5a/ad20a7383e9a91b63ef41b2bebe990579fbfea126b14ce97ead9a32dd533/lastversion-0.0.13.tar.gz" } ], "0.0.14": [ { "comment_text": "", "digests": { "md5": "27ffc2459b40ea6fa99370ee9f483a54", "sha256": "135543e60f8206439e666077565eb4acf60c818c805d48372d1eb4b3c2f88993" }, "downloads": -1, "filename": "lastversion-0.0.14.tar.gz", "has_sig": false, "md5_digest": "27ffc2459b40ea6fa99370ee9f483a54", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6844, "upload_time": "2019-07-25T08:13:30", "url": "https://files.pythonhosted.org/packages/fd/b7/1af5e2300aecc3404edf1dac3954e64108008d436715afca3b1bd2464b1e/lastversion-0.0.14.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "c9bd40d7cdb36c3653c79bbc18e705e9", "sha256": "1c2d679403158a5ef061b23c338857e9ffa285b8d39a46db5244e5e1e9534e13" }, "downloads": -1, "filename": "lastversion-0.0.6.tar.gz", "has_sig": false, "md5_digest": "c9bd40d7cdb36c3653c79bbc18e705e9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4163, "upload_time": "2019-05-17T12:32:02", "url": "https://files.pythonhosted.org/packages/2e/40/f787169a916f6e3912f7275b771865e6b0b6a1f2116ca5b166dcda8c4c12/lastversion-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "3d361444c2c305575368218ae6457687", "sha256": "4073def3d93d8610c00a42ad89722a5af984e0e7936e38e336e405087c494104" }, "downloads": -1, "filename": "lastversion-0.0.7.tar.gz", "has_sig": false, "md5_digest": "3d361444c2c305575368218ae6457687", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4434, "upload_time": "2019-05-17T17:03:12", "url": "https://files.pythonhosted.org/packages/54/1c/ccd9083df41193e5fac7f45b6a5399c6c3caa1f44310f776b45e4f4de6fe/lastversion-0.0.7.tar.gz" } ], "0.0.8": [ { "comment_text": "", "digests": { "md5": "7db41b305e52a348c9faad2305872732", "sha256": "3105eb13866ad59423a0e27da8ade8d0da4828fdf101adf294c82134a734f719" }, "downloads": -1, "filename": "lastversion-0.0.8.tar.gz", "has_sig": false, "md5_digest": "7db41b305e52a348c9faad2305872732", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4684, "upload_time": "2019-05-17T17:28:54", "url": "https://files.pythonhosted.org/packages/ae/01/e57aa6536037f792be2a021e66003a409bdf3203e6cb65ff8b539c9c7bb4/lastversion-0.0.8.tar.gz" } ], "0.0.9": [ { "comment_text": "", "digests": { "md5": "69beef456060a9ed6450463ddfcae67f", "sha256": "4a795797479283a7811e82efe30eca87905107006e7a08e4209bbef86a67d0f3" }, "downloads": -1, "filename": "lastversion-0.0.9.tar.gz", "has_sig": false, "md5_digest": "69beef456060a9ed6450463ddfcae67f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5757, "upload_time": "2019-06-12T12:22:08", "url": "https://files.pythonhosted.org/packages/71/bd/7602b86d3d553d8c7709f03b4426bd88a9372205ef26e0cfa1d0c53c1d95/lastversion-0.0.9.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "f99e9497dd64d2be570ce5a1e1a094df", "sha256": "e9a71547a8feb9ab98a49162bc8354c559e8676c89867e18913a401c3c9ace61" }, "downloads": -1, "filename": "lastversion-0.1.0.tar.gz", "has_sig": false, "md5_digest": "f99e9497dd64d2be570ce5a1e1a094df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8760, "upload_time": "2019-07-29T20:20:42", "url": "https://files.pythonhosted.org/packages/3d/48/a91aa5f9d038f75a0ec425b1a73cde10c885767d480a27e6cbb561441b38/lastversion-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "d382e6c195567bdcebae804683543245", "sha256": "833ee473ba79c56d6992182c73e376a2a1970f0c88ffec16918eba3831d7fdcd" }, "downloads": -1, "filename": "lastversion-0.1.1.tar.gz", "has_sig": false, "md5_digest": "d382e6c195567bdcebae804683543245", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10961, "upload_time": "2019-07-30T21:45:40", "url": "https://files.pythonhosted.org/packages/3b/4f/3815110e2c10478843a99c44751b8dbef1b5fea0b4c2d01bb7d31be98edf/lastversion-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "6ed1bbe8feb0e92d70bb8af691e40782", "sha256": "584c36447a0d949093e0979c809e273265bb14787c258e205e39020b13b69fef" }, "downloads": -1, "filename": "lastversion-0.1.2.tar.gz", "has_sig": false, "md5_digest": "6ed1bbe8feb0e92d70bb8af691e40782", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11563, "upload_time": "2019-08-07T09:20:41", "url": "https://files.pythonhosted.org/packages/b8/64/23f6844203304101cea1bb04516810214204ad236f6a2f09d4dcaeeb2b87/lastversion-0.1.2.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "219cfc85c16c83ce2c578153c0b8bb76", "sha256": "d469075450220c6e9b4f93e8b86ddbbb6f87023021905f7376debda2a76e3901" }, "downloads": -1, "filename": "lastversion-0.2.0.tar.gz", "has_sig": false, "md5_digest": "219cfc85c16c83ce2c578153c0b8bb76", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12088, "upload_time": "2019-08-08T12:46:34", "url": "https://files.pythonhosted.org/packages/b2/14/53553a671ec60fa1763b2af6792874d9a9969bb1522535bbc8376bfc9d83/lastversion-0.2.0.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "e4952cd46d0e3bb1647b8d121ce6a22c", "sha256": "4130bcb2771414e566cf34e098c09ac924a2b31b18b985ed7db4e2d6f7a7d207" }, "downloads": -1, "filename": "lastversion-0.2.2.tar.gz", "has_sig": false, "md5_digest": "e4952cd46d0e3bb1647b8d121ce6a22c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12175, "upload_time": "2019-09-17T20:26:31", "url": "https://files.pythonhosted.org/packages/04/44/105bd3e5ea74ccb6c66cbc41da70125982a3e2e0b122073ce9b745b22d13/lastversion-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "95f73a03e6753924f9d7fc9fa4831934", "sha256": "9766be8d9bd40a819e3fb53c48334cfe06f7e5e522020e4fa8f9e5cb970fb3b5" }, "downloads": -1, "filename": "lastversion-0.2.3.tar.gz", "has_sig": false, "md5_digest": "95f73a03e6753924f9d7fc9fa4831934", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13081, "upload_time": "2019-09-24T11:47:33", "url": "https://files.pythonhosted.org/packages/5f/7d/e5bea1aa450ad1c0394c792e774a2bab8bc404cb08e4c152b10e2d3991da/lastversion-0.2.3.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "59351d9b876acd0b62e7a4c6d6300d5b", "sha256": "9aa742683c586c9d56ffd8870c467f806b8d706d9138b8ed24a9a3d5579ddf80" }, "downloads": -1, "filename": "lastversion-0.2.4.tar.gz", "has_sig": false, "md5_digest": "59351d9b876acd0b62e7a4c6d6300d5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13877, "upload_time": "2019-10-12T13:15:13", "url": "https://files.pythonhosted.org/packages/63/35/42c8d46c89461a8befa0f0e573ca7c60f964df8bf3d41237458473237da2/lastversion-0.2.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "59351d9b876acd0b62e7a4c6d6300d5b", "sha256": "9aa742683c586c9d56ffd8870c467f806b8d706d9138b8ed24a9a3d5579ddf80" }, "downloads": -1, "filename": "lastversion-0.2.4.tar.gz", "has_sig": false, "md5_digest": "59351d9b876acd0b62e7a4c6d6300d5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13877, "upload_time": "2019-10-12T13:15:13", "url": "https://files.pythonhosted.org/packages/63/35/42c8d46c89461a8befa0f0e573ca7c60f964df8bf3d41237458473237da2/lastversion-0.2.4.tar.gz" } ] }