From 5a3a6f0cf699f9b7abd8516b928a10c1718cc046 Mon Sep 17 00:00:00 2001 From: xhon-pelushi Date: Sat, 15 Aug 2026 18:05:39 -0400 Subject: [PATCH] fix(promote-charms): verify all revision tags on target commit are provided Only checking that at least one tag per charm was passed let a partial promotion slip through: if a commit produced more than one revision tag for the same charm (e.g. separate amd64/arm64 revisions), promoting a subset would leave the missed revision behind on the lower channel. Diff revision tags found on the resolved commit against the `revisions` input and fail before promoting if any are missing. Closes #369 Signed-off-by: xhon-pelushi --- .../craft_tools/promote.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/_cli/data_platform_workflows_cli/craft_tools/promote.py b/_cli/data_platform_workflows_cli/craft_tools/promote.py index d15212e9..0daf013c 100644 --- a/_cli/data_platform_workflows_cli/craft_tools/promote.py +++ b/_cli/data_platform_workflows_cli/craft_tools/promote.py @@ -539,6 +539,28 @@ def charms(): commit_sha = commit_shas.pop() logging.info(f"All provided revisions were built from git commit {repr(commit_sha)}") + # Verify that no revision tags pointing at this commit were left out of the `revisions` input + # (e.g. an amd64 revision tag provided but the arm64 revision tag for the same commit is not), + # so that a partial promotion cannot be triggered by mistake + logging.info("Checking that all revision tags on the target commit were provided") + missing_tags: list[str] = [] + for charm, revisions in charm_revisions_map.items(): + tags_on_commit = subprocess.run( + ["git", "tag", "--list", f"{charm.tag_prefix}*", "--points-at", commit_sha], + capture_output=True, + check=True, + text=True, + ).stdout.splitlines() + provided_tags = {f"{charm.tag_prefix}{revision}" for revision in revisions} + missing_tags.extend(sorted(set(tags_on_commit) - provided_tags)) + if missing_tags: + raise ValueError( + f"Revision tag(s) {repr(sorted(missing_tags))} point to the same git commit " + f"({repr(commit_sha)}) as the provided `revisions` input but were not included in it. " + "Include all revision tags for this commit so that no revision is left behind when " + "promoting." + ) + subprocess.run(["git", "checkout", commit_sha], check=True) for charm in charms_: