feat(ci): add --container-tag to decouple image tag from release version
CI / validate (pull_request) Failing after 47s
CI / auto-merge (pull_request) Skipped

This commit is contained in:
Emil Simeonov
2026-09-19 04:18:36 +02:00
parent 8cbf148745
commit 0fc1d82365
3 changed files with 54 additions and 3 deletions
+14 -3
View File
@@ -233,6 +233,15 @@ def create_vikunja_task(title: str, description: str) -> str | None:
default="", default="",
help=_("Git ref of the producer release (default: v<new-version>), recorded in the manifest."), help=_("Git ref of the producer release (default: v<new-version>), recorded in the manifest."),
) )
@click.option(
"--container-tag",
default="",
help=_(
"Container tag to verify with --verify-container (default: --new-version). "
"Use when the image tag differs from the release version, e.g. a package "
"__version__ tag vs a release git tag."
),
)
@click.option("--dry-run", is_flag=True, default=False, help=_("Show what would be done without creating PR")) @click.option("--dry-run", is_flag=True, default=False, help=_("Show what would be done without creating PR"))
def cli( def cli(
repo: str, repo: str,
@@ -243,6 +252,7 @@ def cli(
manifest_path: str, manifest_path: str,
verify_container: str, verify_container: str,
source_ref: str, source_ref: str,
container_tag: str,
dry_run: bool, dry_run: bool,
) -> None: ) -> None:
"""Create an infra PR to bump a pinned dependency version.""" """Create an infra PR to bump a pinned dependency version."""
@@ -261,12 +271,13 @@ def cli(
_("Invalid container format: {container} (expected owner/name)", container=verify_container) _("Invalid container format: {container} (expected owner/name)", container=verify_container)
) )
c_owner, c_name = verify_container.split("/", 1) c_owner, c_name = verify_container.split("/", 1)
image_digest = resolve_container_digest(GITEA_API_URL, c_owner, c_name, new_version, token) image_tag = container_tag or new_version
image_digest = resolve_container_digest(GITEA_API_URL, c_owner, c_name, image_tag, token)
click.echo( click.echo(
_( _(
"[dep-pr] Verified {container}:{version} -> {digest}", "[dep-pr] Verified {container}:{version} -> {digest}",
container=verify_container, container=verify_container,
version=new_version, version=image_tag,
digest=image_digest, digest=image_digest,
) )
) )
@@ -341,7 +352,7 @@ def cli(
fields = { fields = {
"version": new_version, "version": new_version,
"git_ref": source_ref or f"v{new_version}", "git_ref": source_ref or f"v{new_version}",
"image_tag": new_version, "image_tag": container_tag or new_version,
"updated_at": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"), "updated_at": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
} }
if image_digest: if image_digest:
+8
View File
@@ -1351,6 +1351,14 @@
"ru": "Артефакт контейнера {owner}/{name}:{tag} не найден или недоступен для чтения (HTTP {status}). Отказ открывать PR зависимости для неопубликованного артефакта.", "ru": "Артефакт контейнера {owner}/{name}:{tag} не найден или недоступен для чтения (HTTP {status}). Отказ открывать PR зависимости для неопубликованного артефакта.",
"zh": "容器构件 {owner}/{name}:{tag} 未找到或不可读 (HTTP {status})。拒绝为未发布的构件创建依赖 PR。" "zh": "容器构件 {owner}/{name}:{tag} 未找到或不可读 (HTTP {status})。拒绝为未发布的构件创建依赖 PR。"
}, },
"Container tag to verify with --verify-container (default: --new-version). Use when the image tag differs from the release version, e.g. a package __version__ tag vs a release git tag.": {
"bg": "Таг на контейнер за проверка с --verify-container (по подразбиране: --new-version). Използвайте, когато тагът на изображението се различава от версията на изданието, напр. таг на __version__ на пакет срещу git таг на издание.",
"de": "Container-Tag, der mit --verify-container geprüft wird (Standard: --new-version). Zu verwenden, wenn sich das Image-Tag von der Release-Version unterscheidet, z. B. ein __version__-Tag eines Pakets vs. ein Release-Git-Tag.",
"en": "Container tag to verify with --verify-container (default: --new-version). Use when the image tag differs from the release version, e.g. a package __version__ tag vs a release git tag.",
"pl": "Tag kontenera do weryfikacji z --verify-container (domyślnie: --new-version). Użyj, gdy tag obrazu różni się od wersji wydania, np. tag __version__ pakietu a tag git wydania.",
"ru": "Тег контейнера для проверки с --verify-container (по умолчанию: --new-version). Используйте, когда тег образа отличается от версии релиза, например тег __version__ пакета против git-тега релиза.",
"zh": "用 --verify-container 验证的容器标签(默认:--new-version)。当镜像标签与发布版本不同时使用,例如包的 __version__ 标签与发布 git 标签。"
},
"Container to verify before opening the PR (owner/name). Resolves the OCI digest of the tag matching --new-version and records it in the manifest.": { "Container to verify before opening the PR (owner/name). Resolves the OCI digest of the tag matching --new-version and records it in the manifest.": {
"bg": "Контейнер за проверка преди отваряне на PR (owner/name). Разрешава OCI дайджеста на тага, съвпадащ с --new-version, и го записва в манифеста.", "bg": "Контейнер за проверка преди отваряне на PR (owner/name). Разрешава OCI дайджеста на тага, съвпадащ с --new-version, и го записва в манифеста.",
"de": "Container, der vor dem Öffnen des PR verifiziert wird (owner/name). Ermittelt den OCI-Digest des zu --new-version passenden Tags und trägt ihn ins Manifest ein.", "de": "Container, der vor dem Öffnen des PR verifiziert wird (owner/name). Ermittelt den OCI-Digest des zu --new-version passenden Tags und trägt ihn ins Manifest ein.",
+32
View File
@@ -421,3 +421,35 @@ class TestCliManifestMode:
], ],
) )
assert result.exit_code != 0 assert result.exit_code != 0
@patch("devx.ci.create_dependency_pr.resolve_container_digest")
@patch("devx.ci.create_dependency_pr.read_manifest_version")
@patch("devx.ci.create_dependency_pr.get_ci_token")
def test_container_tag_overrides_new_version(
self, mock_token: MagicMock, mock_read: MagicMock, mock_digest: MagicMock
) -> None:
"""--container-tag selects the image tag when it differs from version."""
mock_token.return_value = "fake-token"
mock_read.return_value = "0.9.1"
mock_digest.return_value = "sha256:abc"
runner = CliRunner()
result = runner.invoke(
cli,
[
"--package",
"sso_bridge",
"--new-version",
"0.9.1",
"--source-repo",
"oblachno/sso-bridge",
"--manifest",
"deploy/m.json",
"--verify-container",
"oblachno/sso-bridge",
"--container-tag",
"0.2.4",
],
)
assert result.exit_code == 0
args = mock_digest.call_args[0]
assert args[1:4] == ("oblachno", "sso-bridge", "0.2.4")