From c960e6cbc8ae677f97eb9f8c551d4431a030c568 Mon Sep 17 00:00:00 2001 From: Danila Vershinin Date: Sat, 7 Aug 2021 14:43:55 +0300 Subject: [PATCH] Consistency for --having-asset --- CHANGELOG.md | 5 +++ README.md | 15 +++++--- lastversion/GitHubRepoSession.py | 61 +++++++++++++++++++++++++++----- lastversion/__about__.py | 2 +- lastversion/lastversion.py | 3 +- tests/test_lastversion.py | 9 ++++- 6 files changed, 78 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb44ac50..b154356c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.5.1] - 2021-08-07 +### Added +* `--having-asset` accepts regular expression if tilde prepended +* For one-word repo argument, check word/word official GitHub repo first, then search + ## [1.5.0] - 2021-08-06 ### Added * New `--having-asset` switch to consider only formal releases with given asset name diff --git a/README.md b/README.md index 44531f15..c1718923 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ 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 or formal releases only +### 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. @@ -286,10 +286,15 @@ Easy with the `--having-asset` switch: lastversion telegramdesktop/tdesktop --having-asset "Linux 64 bit: Binary" ``` -In other situations, you want to consider only latest *formal* release in GitHub. Then you can use -`--having-asset` without a value. This is useful when you want to disregard any bare "tag" -releases from GitHub. Counter-intuitively, this may return a formal releases without any other -assets than source code alone. +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: + +```bash +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: ```bash lastversion telegramdesktop/tdesktop --having-asset diff --git a/lastversion/GitHubRepoSession.py b/lastversion/GitHubRepoSession.py index adec71dc..e0239ae5 100644 --- a/lastversion/GitHubRepoSession.py +++ b/lastversion/GitHubRepoSession.py @@ -2,6 +2,7 @@ import logging import math import os +import re import time from datetime import timedelta @@ -22,6 +23,25 @@ def set_matching_from_tag(ret, tag): ret = tag +def asset_matches(asset, search, regex_matching): + """Check if the asset equals to string or satisfies a regular expression + Args: + asset (dict): asset dict as returned by the API + search (str): string or regexp to match asset's name or label with + regex_matching (bool): whether search argument is a regexp + Returns: + bool: Whether match is satisfied + """ + if regex_matching: + if asset['label'] and re.search(search, asset['label']): + return True + if asset['name'] and re.search(search, asset['name']): + return True + elif search in (asset['label'], asset['name']): + return True + return False + + class GitHubRepoSession(ProjectHolder): """A class to represent a GitHub project holder.""" @@ -133,13 +153,17 @@ def __init__(self, repo, hostname): else: self.api_base = 'https://api.{}'.format(self.DEFAULT_HOSTNAME) if '/' not in repo: - repo = self.find_repo_by_name_only(repo) - if not repo: - return - self.set_repo(repo) - log.info('Using repo {} obtained from search API'.format(self.repo)) - else: - self.set_repo(repo) + official_repo = self.try_get_official(repo) + if official_repo: + repo = official_repo + log.info('Using official repo {}'.format(repo)) + else: + repo = self.find_repo_by_name_only(repo) + if repo: + log.info('Using repo {} obtained from search API'.format(self.repo)) + else: + return + self.set_repo(repo) def get_rate_limit_url(self): return '{}/rate_limit'.format(self.api_base) @@ -550,13 +574,18 @@ def set_matching_formal_release(self, ret, formal_release, version, pre_ok, "pre-release: {}.".format(version)) return ret if self.having_asset: - if 'assets' not in formal_release: + if 'assets' not in formal_release or not formal_release['assets']: log.info('Skipping this release due to no assets.') return ret if self.having_asset is not True: + regex_matching = False + search = self.having_asset + if search.startswith('~'): + search = r'{}'.format(search.lstrip('~')) + regex_matching = True found_asset = False for asset in formal_release['assets']: - if self.having_asset in (asset['label'], asset['name']): + if asset_matches(asset, search, regex_matching=regex_matching): found_asset = True break if not found_asset: @@ -569,3 +598,17 @@ def set_matching_formal_release(self, ret, formal_release, version, pre_ok, log.info("Selected version as current selection: {}.".format(formal_release['version'])) return formal_release + def try_get_official(self, repo): + """Check existence of repo/repo + + Returns: + str: updated repo + """ + official_repo = "{}/{}".format(repo, repo) + log.info('Checking existence of {}'.format(official_repo)) + url = '{}/repos/{}'.format(self.api_base, official_repo) + r = self.get(url) + if r.status_code == 200: + return official_repo + return None + diff --git a/lastversion/__about__.py b/lastversion/__about__.py index 77f1c8e6..51ed7c48 100644 --- a/lastversion/__about__.py +++ b/lastversion/__about__.py @@ -1 +1 @@ -__version__ = '1.5.0' +__version__ = '1.5.1' diff --git a/lastversion/lastversion.py b/lastversion/lastversion.py index 72200805..e8b0706c 100644 --- a/lastversion/lastversion.py +++ b/lastversion/lastversion.py @@ -52,7 +52,8 @@ def latest(repo, output_format='version', pre_ok=False, assets_filter=None, pre_ok (bool): Specifies whether pre-releases can be accepted as newer version. at (str): Specifies repo hosting more precisely, only useful if repo argument was specified as one word. - having_asset (str): Only consider releases with the given asset. + having_asset (Union[str, bool]): Only consider releases with the given asset. + Pass `True` for any asset Returns: Version: Newer version object, if found and `output_format` is `version`. diff --git a/tests/test_lastversion.py b/tests/test_lastversion.py index 1f881288..7d93996c 100644 --- a/tests/test_lastversion.py +++ b/tests/test_lastversion.py @@ -484,8 +484,15 @@ def test_wiki_direct_url_meego(): assert v == version.parse('1.2.0.10') -def test_having_asset(): +def test_having_specific_asset(): """Test locating release with a given asset name.""" repo = 'https://github.com/lastversion-test-repos/portainer' v = latest(repo, having_asset='portainer-2.6.1-linux-amd64.tar.gz') assert v == version.parse('2.6.1') + + +def test_having_any_asset(): + """Test locating release with a given asset name.""" + repo = 'https://github.com/lastversion-test-repos/portainer' + v = latest(repo, having_asset=True) + assert v == version.parse('2.6.3')