From c3cf4d20227e0ee5bda21f42577ee01e0f3a0ffc Mon Sep 17 00:00:00 2001 From: Michal Nasiadka Date: Mon, 8 Jun 2026 07:11:30 +0100 Subject: [PATCH] Add pagination for list repositories and tags --- quaytool/quaytool.py | 49 +++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/quaytool/quaytool.py b/quaytool/quaytool.py index e9d90d4..d3a3f84 100755 --- a/quaytool/quaytool.py +++ b/quaytool/quaytool.py @@ -272,9 +272,23 @@ def list_repositories(api_url, headers, insecure, organization, visibility): if organization: url += "&namespace=%s" % organization - r = requests.get(url, headers=headers, verify=insecure) - r.raise_for_status() - return r.json() + repositories = [] + next_page = None + while True: + page_url = "%s&next_page=%s" % (url, next_page) if next_page else url + r = requests.get(page_url, headers=headers, verify=insecure) + r.raise_for_status() + data = r.json() + new_repos = data.get('repositories', []) + # Workaround for Quay API bug: next_page token returning same repos + if all(repo in repositories for repo in new_repos): + break + repositories.extend(new_repos) + next_page = data.get('next_page') + if not next_page: + break + + return {'repositories': repositories} def expire_tag(api_url, headers, insecure, organization, tag, repositories, @@ -324,6 +338,22 @@ def _make_restore(api_url, headers, insecure, organization, tag, repository, r.raise_for_status() +def _get_all_tags(api_url, headers, insecure, organization, repo_name): + tags = [] + page = 1 + while True: + url = "%s/repository/%s/%s/tag?page=%d" % ( + api_url, organization, repo_name, page) + r = requests.get(url, headers=headers, verify=insecure) + r.raise_for_status() + data = r.json() + tags.extend(data.get('tags', [])) + if not data.get('has_additional'): + break + page += 1 + return tags + + def _tag_helper(api_url, headers, insecure, organization, tag, repositories, days=None, expire_tag=False, restore_tag=False): @@ -334,19 +364,14 @@ def _tag_helper(api_url, headers, insecure, organization, tag, repositories, missing_tags = [] for repository in repositories: - # get all available tags for that repository - url = "%s/repository/%s/%s/tag" % (api_url, organization, - repository['name']) - r = requests.get(url, headers=headers, verify=insecure) - r.raise_for_status() - - available_tags = r.json() + available_tags = _get_all_tags(api_url, headers, insecure, organization, + repository['name']) - if 'tags' not in available_tags: + if not available_tags: print("Can't find any tag for repository %s" % repository['name']) continue - for available_tag in available_tags['tags']: + for available_tag in available_tags: if available_tag['name'] == tag: print("Found a tag %s in repository %s" % ( tag, repository['name']))