Derive OCI publish mode from trigger to end twin-publish race #48

Merged
David merged 2 commits from fix/GOV-15-twin-trigger-publish-mode into main 2026-06-26 18:21:28 +02:00
Owner

What

Ports the GOV-13 twin-trigger publish-mode fix into the vervain-apps OCI build workflow as part of the GOV-15 per-repo rollout.

Why

A release commit is simultaneously a push to main and the v* tag push, so build-oci-image.yml fired on both events. The old ci-build/get-tags.nu resolved its tag set from git describe, returning the identical [vX.Y.Z, latest] pair on both runs, so the two builds raced to write the same destinations: a 409 on immutable generic-package files and an overwrite race on the mutable OCI latest tag.

How

The publish mode is now derived from the workflow trigger, never from git describe. A v* tag push resolves to the release train and publishes only the immutable vX.Y.Z tag; a main push resolves to the latest train and publishes only the rolling latest tag; a workflow_dispatch resolves to dry-run, building locally and mutating nothing. The two real runs now write disjoint tag sets and never collide.

ci-build/get-tags.nu is replaced with the canonical --mode version returning a { mode, train, tag, describe } record. The workflow gains a workflow_dispatch trigger with dry_run and simulate_tag inputs, a resolve step that maps the trigger to a mode, a single-tag dry-run-aware build-and-push step, and a dry-run-aware print step. Image name (vervain-web), registry wiring, gha cache strategy, build-args, and Dockerfile path are unchanged. The companion build-desktop-linux.yml is not touched.

Verification

YAML parses, nu-check returns true on the helper, all four functional modes resolve the expected tag (release -> v9.9.9, latest -> latest, dry-run+simulate -> v9.9.9, dry-run default -> latest), and both error paths (bogus mode, release with no version) exit non-zero.

## What Ports the GOV-13 twin-trigger publish-mode fix into the `vervain-apps` OCI build workflow as part of the GOV-15 per-repo rollout. ## Why A release commit is simultaneously a push to `main` and the `v*` tag push, so `build-oci-image.yml` fired on both events. The old `ci-build/get-tags.nu` resolved its tag set from `git describe`, returning the identical `[vX.Y.Z, latest]` pair on both runs, so the two builds raced to write the same destinations: a 409 on immutable generic-package files and an overwrite race on the mutable OCI `latest` tag. ## How The publish mode is now derived from the workflow trigger, never from `git describe`. A `v*` tag push resolves to the `release` train and publishes only the immutable `vX.Y.Z` tag; a `main` push resolves to the `latest` train and publishes only the rolling `latest` tag; a `workflow_dispatch` resolves to `dry-run`, building locally and mutating nothing. The two real runs now write disjoint tag sets and never collide. `ci-build/get-tags.nu` is replaced with the canonical `--mode` version returning a `{ mode, train, tag, describe }` record. The workflow gains a `workflow_dispatch` trigger with `dry_run` and `simulate_tag` inputs, a resolve step that maps the trigger to a mode, a single-tag dry-run-aware build-and-push step, and a dry-run-aware print step. Image name (`vervain-web`), registry wiring, gha cache strategy, build-args, and Dockerfile path are unchanged. The companion `build-desktop-linux.yml` is not touched. ## Verification YAML parses, `nu-check` returns true on the helper, all four functional modes resolve the expected tag (release -> `v9.9.9`, latest -> `latest`, dry-run+simulate -> `v9.9.9`, dry-run default -> `latest`), and both error paths (bogus mode, release with no version) exit non-zero.
fix(ci): derive OCI publish mode from trigger to end twin-publish race
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 12m5s
6576e15b3b
A release commit is simultaneously a push to main and the v* tag push, so
the build-oci-image workflow fired on both events. The old get-tags.nu
resolved its tag set from git describe, returning the identical [vX.Y.Z,
latest] pair on both runs, so the two builds raced to write the same
destinations: a 409 on immutable generic-package files and an overwrite race
on the mutable OCI latest tag.

Derive the publish mode from the trigger instead. A v* tag push resolves to
the release train and publishes only the immutable vX.Y.Z tag; a main push
resolves to the latest train and publishes only the rolling latest tag; a
workflow_dispatch resolves to dry-run, building locally and mutating nothing.
The two real runs now write disjoint tag sets and never collide.

get-tags.nu is replaced with the canonical --mode version returning a
{ mode, train, tag, describe } record. The workflow gains a workflow_dispatch
trigger with dry_run and simulate_tag inputs, a resolve step that maps the
trigger to a mode, a single-tag dry-run-aware build-and-push step, and a
dry-run-aware print step. Image name, registry wiring, gha cache strategy,
build-args, and Dockerfile path are unchanged.

#GOV-15
#GOV-13
Merge branch 'main' into fix/GOV-15-twin-trigger-publish-mode
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 28s
Create release / Create release from merged PR (pull_request) Has been skipped
6c5b32d2f3
David merged commit 9b8c4ddc15 into main 2026-06-26 18:21:28 +02:00
David deleted branch fix/GOV-15-twin-trigger-publish-mode 2026-06-26 18:21:28 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-apps!48
No description provided.