From 824267701681f20f9ba04ca3e7921c5d8429411d Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:27:05 +1000 Subject: [PATCH 1/6] correction to types, expose parsed docker images --- cpg_utils/cloud.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/cpg_utils/cloud.py b/cpg_utils/cloud.py index 894b297..257f10d 100644 --- a/cpg_utils/cloud.py +++ b/cpg_utils/cloud.py @@ -7,13 +7,16 @@ import traceback import urllib.parse from collections import defaultdict +from datetime import datetime from typing import Any, NamedTuple +from zoneinfo import ZoneInfo # pylint: disable=no-name-in-module import google.api_core.exceptions import google.auth.transport import google.oauth2 from deprecated import deprecated +from google.api_core.datetime_helpers import to_milliseconds from google.auth import ( credentials as google_auth_credentials, ) @@ -43,6 +46,8 @@ _EXTERNAL_ACCOUNT_TYPE, ) +TZ = ZoneInfo('Australia/Sydney') + def email_from_id_token(id_token_jwt: str) -> str: """Decodes the ID token (JWT) to get the email address of the caller. @@ -130,7 +135,7 @@ class DockerImage(NamedTuple): uri: str tag_uri: str size: str - build_time: str + build_time: datetime _repo_image_tags: dict[str, defaultdict[str, dict[str, DockerImage]]] = {} @@ -151,19 +156,43 @@ def _ensure_image_tags_loaded(project: str, location: str, repository: str) -> N name_and_checksum = image.name.rpartition('/dockerImages/')[2] name = urllib.parse.unquote(name_and_checksum).rpartition('@')[0] base_uri = image.uri.rpartition('@')[0] + + # digest the Google proto DatetimeWithNanoseconds object into a standard python datetime + images_build_time_ms = to_milliseconds(image.build_time) + build_datetime = datetime.fromtimestamp(images_build_time_ms // 1000, tz=TZ) + for tag in image.tags: image_tags[name][tag] = DockerImage( image.name, image.uri, f'{base_uri}:{tag}', image.image_size_bytes, - image.build_time, + build_datetime, ) image_tags.default_factory = None _repo_image_tags[repository] = image_tags +def get_tags_for_image( + project: str, + location: str, + repository: str, + image: str, +) -> dict[str, DockerImage]: + """ + Ensure available images are loaded, then request all available tags from a specific image + """ + _ensure_image_tags_loaded(project, location, repository) + if repository not in _repo_image_tags: + raise ValueError( + f'repository "{repository}" is not available in the collected tags.', + ) + if image not in _repo_image_tags[repository]: + raise ValueError(f'image "{image}" is not available in the collected tags.') + return _repo_image_tags[repository][image] + + def find_image(repository: str | None, name: str, version: str) -> DockerImage: """Returns image details or raises ValueError if the image or tag does not exist.""" repository = f'images-{repository}' if repository is not None else 'images' From 705a6baa2d2234903c79fb8fe137c09a42da78f7 Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:30:54 +1000 Subject: [PATCH 2/6] int type for size --- cpg_utils/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpg_utils/cloud.py b/cpg_utils/cloud.py index 257f10d..9b5db6f 100644 --- a/cpg_utils/cloud.py +++ b/cpg_utils/cloud.py @@ -134,7 +134,7 @@ class DockerImage(NamedTuple): name: str uri: str tag_uri: str - size: str + size: int build_time: datetime From 640f201ff796bdf4cd082db953ec207998465931 Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:39:56 +1000 Subject: [PATCH 3/6] corrected import location --- cpg_utils/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpg_utils/cloud.py b/cpg_utils/cloud.py index 9b5db6f..a629d9b 100644 --- a/cpg_utils/cloud.py +++ b/cpg_utils/cloud.py @@ -9,7 +9,6 @@ from collections import defaultdict from datetime import datetime from typing import Any, NamedTuple -from zoneinfo import ZoneInfo # pylint: disable=no-name-in-module import google.api_core.exceptions @@ -34,6 +33,7 @@ from google.cloud import artifactregistry, secretmanager from google.oauth2 import credentials as oauth2_credentials from google.oauth2 import service_account +from zoneinfo import ZoneInfo _CLOUD_SDK_MISSING_CREDENTIALS = """\ Your default credentials were not found. To set up Application Default Credentials, \ From 5b556ddbf97343febe0d7f428dc670f1ee6fac66 Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:40:08 +1000 Subject: [PATCH 4/6] run ruff before black --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c63791d..0cbf0fe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,17 +24,17 @@ repos: hooks: - id: cpg-id-checker - - repo: https://github.com/ambv/black - rev: 24.2.0 - hooks: - - id: black - - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.3.2 hooks: - id: ruff + - repo: https://github.com/ambv/black + rev: 24.2.0 + hooks: + - id: black + # Static type analysis (as much as it's possible in python using type hints) - repo: https://github.com/pre-commit/mirrors-mypy rev: "v1.8.0" From c0901ddeba92b32f144ec5d7d969c8007741952a Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:40:19 +1000 Subject: [PATCH 5/6] =?UTF-8?q?Bump=20version:=205.4.3=20=E2=86=92=205.4.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- .github/workflows/docker.yaml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 465d32c..aada647 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 5.4.3 +current_version = 5.4.4 commit = True tag = False diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index bf30241..6f11bb4 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -5,7 +5,7 @@ on: - main env: - VERSION: 5.4.3 + VERSION: 5.4.4 permissions: contents: read diff --git a/setup.py b/setup.py index 30c51a0..a3fb698 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name='cpg-utils', # This tag is automatically updated by bumpversion - version='5.4.3', + version='5.4.4', description='Library of convenience functions specific to the CPG', long_description=long_description, long_description_content_type='text/markdown', From b9907e1742bb94998ebc589c0427a523caeba416 Mon Sep 17 00:00:00 2001 From: MattWellie Date: Mon, 22 Dec 2025 10:40:59 +1000 Subject: [PATCH 6/6] put ruff back --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0cbf0fe..c63791d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,17 +24,17 @@ repos: hooks: - id: cpg-id-checker + - repo: https://github.com/ambv/black + rev: 24.2.0 + hooks: + - id: black + - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.3.2 hooks: - id: ruff - - repo: https://github.com/ambv/black - rev: 24.2.0 - hooks: - - id: black - # Static type analysis (as much as it's possible in python using type hints) - repo: https://github.com/pre-commit/mirrors-mypy rev: "v1.8.0"