From 7a2d3d226b0d1a48df841c7f2693a151f059cbf4 Mon Sep 17 00:00:00 2001 From: lilydjwg Date: Sun, 14 Jun 2020 13:55:51 +0800 Subject: [PATCH] GitHub: add `use_latest_tag` --- README.rst | 9 ++++ nvchecker/source/github.py | 70 +++++++++++++++++++++++--- nvchecker/source/tornado_httpclient.py | 6 +++ tests/test_github.py | 6 ++- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index fb2ad8d..933b30a 100644 --- a/README.rst +++ b/README.rst @@ -298,6 +298,15 @@ use_latest_release Will return the release name instead of date. +use_latest_tag + Set this to ``true`` to check for the latest tag on GitHub. + + This requires a token because it's using the v4 GraphQL API. + +query + When ``use_latest_tag`` is ``true``, this sets a query for the tag. The exact + matching method is not documented by GitHub. + use_max_tag Set this to ``true`` to check for the max tag on GitHub. Unlike ``use_latest_release``, this option includes both annotated tags and diff --git a/nvchecker/source/github.py b/nvchecker/source/github.py index e19b804..eb53639 100644 --- a/nvchecker/source/github.py +++ b/nvchecker/source/github.py @@ -17,6 +17,7 @@ GITHUB_URL = 'https://api.github.com/repos/%s/commits' GITHUB_LATEST_RELEASE = 'https://api.github.com/repos/%s/releases/latest' # https://developer.github.com/v3/git/refs/#get-all-references GITHUB_MAX_TAG = 'https://api.github.com/repos/%s/git/refs/tags' +GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql' async def get_version(name, conf, **kwargs): try: @@ -24,7 +25,68 @@ async def get_version(name, conf, **kwargs): except HTTPError as e: check_ratelimit(e, name) +QUERY_LATEST_TAG = ''' +{{ + repository(name: "{name}", owner: "{owner}") {{ + refs(refPrefix: "refs/tags/", first: 1, + query: "{query}", + orderBy: {{field: TAG_COMMIT_DATE, direction: DESC}}) {{ + edges {{ + node {{ + name + }} + }} + }} + }} +}} +''' + +async def get_latest_tag(name, conf, token): + repo = conf.get('github') + query = conf.get('query', '') + owner, reponame = repo.split('/') + headers = { + 'Authorization': 'bearer %s' % token, + 'Content-Type': 'application/json', + } + q = QUERY_LATEST_TAG.format( + owner = owner, + name = reponame, + query = query, + ) + async with session.post( + GITHUB_GRAPHQL_URL, + headers = headers, + json = {'query': q}, + ) as res: + j = await res.json() + + refs = j['data']['repository']['refs']['edges'] + if not refs: + logger.error('no tag found', name=name) + return + + return refs[0]['node']['name'] + +def get_token(kwargs): + token = os.environ.get('NVCHECKER_GITHUB_TOKEN') + if token: + return token + + token = kwargs['keyman'].get_key('github') + return token + async def get_version_real(name, conf, **kwargs): + token = get_token(kwargs) + + use_latest_tag = conf.getboolean('use_latest_tag', False) + if use_latest_tag: + if not token: + logger.error('token not given but it is required', + name = name) + return + return await get_latest_tag(name, conf, token) + repo = conf.get('github') br = conf.get('branch') path = conf.get('path') @@ -47,12 +109,8 @@ async def get_version_real(name, conf, **kwargs): headers = { 'Accept': 'application/vnd.github.quicksilver-preview+json', } - if 'NVCHECKER_GITHUB_TOKEN' in os.environ: - headers['Authorization'] = 'token %s' % os.environ['NVCHECKER_GITHUB_TOKEN'] - else: - key = kwargs['keyman'].get_key('github') - if key: - headers['Authorization'] = 'token %s' % key + if token: + headers['Authorization'] = 'token %s' % token kwargs = {} if conf.get('proxy'): diff --git a/nvchecker/source/tornado_httpclient.py b/nvchecker/source/tornado_httpclient.py index 74ab246..36930b3 100644 --- a/nvchecker/source/tornado_httpclient.py +++ b/nvchecker/source/tornado_httpclient.py @@ -34,6 +34,12 @@ def try_use_http2(curl): curl.setopt(pycurl.HTTP_VERSION, 4) class Session: + def post(self, url, **kwargs): + j = kwargs.pop('json', None) + if j: + kwargs['body'] = json.dumps(j) + return self.get(url, method='POST', **kwargs) + def get(self, url, **kwargs): kwargs['prepare_curl_callback'] = try_use_http2 diff --git a/tests/test_github.py b/tests/test_github.py index 58226e0..3a59a4a 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -1,5 +1,5 @@ # MIT licensed -# Copyright (c) 2013-2018 lilydjwg , et al. +# Copyright (c) 2013-2020 lilydjwg , et al. import os import re @@ -48,3 +48,7 @@ async def test_github_max_tag_with_include(get_version): "include_regex": r"chrome-\d.*", }) assert re.match(r'chrome-[\d.]+', version) + +async def test_github_latest_tag(get_version): + assert await get_version("example", {"github": "harry-sanabria/ReleaseTestRepo", "use_latest_tag": 1}) == "release3" +