diff --git a/get_all_container_registry_image_tags.py b/get_all_container_registry_image_tags.py new file mode 100644 index 0000000000000000000000000000000000000000..3c7cdba7ce2ca5cfad6e7c99ac7e0ab1ae019d32 --- /dev/null +++ b/get_all_container_registry_image_tags.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Description: Fetch projects (all, group, project), get the container registry images and list all tags +# Requirements: python-gitlab Python libraries. GitLab API read access, and developer access to all configured groups/projects. +# Author: Michael Friedrich +# License: MIT, (c) 2024-present GitLab B.V. + +import gitlab +import os +import sys +import datetime + +GITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com') +GITLAB_TOKEN = os.environ.get('GL_TOKEN') # token requires developer permissions +PROJECT_ID = os.environ.get('GL_PROJECT_ID') #optional +# https://gitlab.com/gitlab-de/use-cases/docker +GROUP_ID = os.environ.get('GL_GROUP_ID') #optional, use 10087220 for gitlab.com/gitlab-da + +################# +# Main + +if __name__ == "__main__": + if not GITLAB_TOKEN: + print("🤔 Please set the GL_TOKEN env variable.") + sys.exit(1) + + gl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN) + + print("# Starting...", end="", flush=True) + + # Collect all projects, or prefer projects from a group id, or a project id + projects = [] + + # Direct project ID + if PROJECT_ID: + projects.append(gl.projects.get(PROJECT_ID)) + + # Groups and projects inside + elif GROUP_ID: + group = gl.groups.get(GROUP_ID) + + for project in group.projects.list(include_subgroups=True, all=True): + print(".", end="", flush=True) # Get some feedback that it is still looping + # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples + manageable_project = gl.projects.get(project.id , lazy=True) + projects.append(manageable_project) + + # All projects on the instance (may take a while to process) + else: + projects = gl.projects.list(get_all=True) + + print(f"\n# Found {len(projects)} projects. Analysing...", end="", flush=True) # new line + + container_registry_images_tags = {} + + # Loop over projects, fetch container repositories and their tags. + for project in projects: + # Projects are not created yet, lazy+true. Instantiate an object. + project_obj = gl.projects.get(project.id) + + try: + repositories = project_obj.repositories.list() + except gitlab.exceptions.GitlabGetError as e: + # Ignore 403 errors + print("Ignoring project repositories {p}: {e}".format(p=project_obj.name_with_namespace, e=e)) + print(".", end="", flush=True) # Get some feedback that it is still looping + continue + + if len(repositories) > 0: + print("# {p}".format(p=project_obj.name_with_namespace)) + + for repository in repositories: + print("## {r}".format(r=repository.name)) + + tags = repository.tags.list() + + for tag in tags: + tag_detail = repository.tags.get(tag.name) + dt = datetime.datetime.strptime(tag_detail.created_at, '%Y-%m-%dT%H:%M:%S.%f%z').replace(tzinfo=None) + + print("### {t}".format(t=tag.name)) + + # https://docs.gitlab.com/ee/api/container_registry.html#get-details-of-a-registry-repository-tag + container_registry_images_tags[project_obj.web_url] = { + "project_name": project_obj.name, + "project_web_url": project_obj.web_url, + "tag_name": tag_detail.name, + "location": tag_detail.location, + "revision": tag_detail.revision, + "created_at": tag_detail.created_at, + "total_size": tag_detail.total_size + } + + + + print("\nDone") + + if len(container_registry_images_tags) > 0: + print("|Project|URL|Image Tag|Location|Revision|Created at|Total size|\n|-|-|-|-|-|-|-|") # Start markdown friendly table + for project_web_url, details in container_registry_images_tags.items(): + print(f'| [{ details["project_name"] }]({project_web_url}) | { details["tag_name"] } | { details["location"] } | { details["revision"] } | { details["created_at"] } | { details["total_size"] } |')