From d0f95dfe4755a9d956461b595659e7eb31a359cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Raes?= Date: Tue, 30 Jan 2024 15:46:02 +0100 Subject: [PATCH] fix: Tag fetching (#27) While checking tags, if current tag isn't found in first page, script will now browse all API pages until either tag is found or there are no more pages. --- tools/verify_versions.py | 50 ++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/tools/verify_versions.py b/tools/verify_versions.py index ff8a52f..b905e8c 100644 --- a/tools/verify_versions.py +++ b/tools/verify_versions.py @@ -3,6 +3,14 @@ import json def verify_all_mod_versions(): + """ + Ensure all mod versions are properly declared to GitHub. + + For each mod entry of this repository's manifesto, this method will fetch information + from GitHub API and compare declared SHA ("CommitHash" member) to GitHub information, + to ensure tracability of verified mods. + """ + # Load local manifesto file f = open('verified-mods.json') manifesto = json.load(f) @@ -10,27 +18,51 @@ def verify_all_mod_versions(): for mod in manifesto: print('Verifying "{}":'.format(mod)) - # Build GitHub API link and fetch distant tags list + # Build GitHub API link words = manifesto[mod]['Repository'].split('/') tags_url = "https://api.github.com/repos/{}/{}/tags".format(words[-2], words[-1]) - response = urlopen(tags_url) - tags_data = json.loads(response.read()) # Check all mod versions one-by-one for version in manifesto[mod]['Versions']: + distant_version = retrieve_tag_info(version['Version'], tags_url) local_hash = version['CommitHash'] - matching_distant_versions = list(filter(lambda v: v['name'] == version['Version'], tags_data)) - - # There should be only one matching version - if len(matching_distant_versions) != 1: - sys.exit('\t❌ v{} (unknown distant version)'.format(version['Version'])) # Compare manifesto commit hash with repository hash - distant_version = matching_distant_versions[0] if local_hash == distant_version['commit']['sha']: print('\t✔️ v{}'.format(version['Version'])) else: sys.exit('\t❌ v{} (hash comparison failed)'.format(version['Version'])) + +def retrieve_tag_info(tag_name, repository_url): + """ + Retrieves tag information from distant API. + + Since the GitHub API is paginated, (*i.e.* it does not list all data in a single page, + but rather serves pages holding 30 elements maximum), we need to browse all pages + until either the tag is found or the page is empty, meaning we didn't find the tag. + Page browsing is done by updating the `page` URL argument (`?page=1`, `?page=2` etc). + + @param tag_name: the name of the mod release + @param repository_url: API URL used to access mod's tags data + @return: tag data, including commit SHA signature + """ + + i = 1 + while True: + url = '{}?page={}'.format(repository_url, i) + response = urlopen(url) + tags_data = json.loads(response.read()) + + # If page is empty, it means the tag couldn't be found + if len(tags_data) == 0: + raise LookupError('Tag not found.') + + # If there's one matching result, we found the tag! + matching_distant_versions = list(filter(lambda v: v['name'] == tag_name, tags_data)) + if len(matching_distant_versions) == 1: + return matching_distant_versions[0] + i += 1 + if __name__ == "__main__": verify_all_mod_versions()