diff --git a/README.md b/README.md index 5f1a17b..79dc423 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,12 @@ the SHA. This makes branch tags **sortable** so newest build — the Git SHA alone is not orderable. The short SHA is kept for traceability and Flux sorts on the timestamp only. +> **Note:** with `docker-tag-timestamp: 'true'` the build also pushes the plain +> `-` tag alongside the timestamped one. That stable per-commit +> tag is what the release step retags into the version tag, so it must continue +> to exist. It does not match the `^-[0-9]+-[0-9a-f]+$` filter below, so +> Flux ignores it. + With the timestamp enabled, use one `ImagePolicy` per environment, filtering by prefix: ```yaml diff --git a/scripts/generate-tags.sh b/scripts/generate-tags.sh index 8f5b26d..036154a 100755 --- a/scripts/generate-tags.sh +++ b/scripts/generate-tags.sh @@ -16,24 +16,34 @@ require_env INPUT_DOCKER_REGISTRY require_env INPUT_DOCKER_IMAGE BUILD="true" +# ALIAS_TAG is an additional immutable tag pushed alongside TAG (see set_branch_tags). +ALIAS_TAG="" -# branch_tag builds the immutable tag for an environment branch. +# set_branch_tags computes the immutable tag(s) for an environment branch and +# assigns them to the globals TAG and ALIAS_TAG. # -# When INPUT_DOCKER_TAG_TIMESTAMP is "true" the tag gets a UTC timestamp inserted -# before the short SHA (e.g. dev-20260602143055-abcdef12). This makes branch tags -# sortable by Flux image automation (numerical policy) — the git SHA alone is not -# orderable, so Flux cannot otherwise tell which build is newest. The SHA is kept -# for traceability. When the flag is unset/false the legacy - shape -# is produced, so existing consumers are unaffected. +# When INPUT_DOCKER_TAG_TIMESTAMP is "true" the canonical TAG gets a UTC timestamp +# inserted before the short SHA (e.g. dev-20260602143055-abcdef12). This makes +# branch tags sortable by Flux image automation (numerical policy) — the Git SHA +# alone is not orderable, so Flux cannot otherwise tell which build is newest. +# In that case ALIAS_TAG holds the legacy - tag, which is also +# pushed: it is the stable per-commit handle that retag-image.sh looks up to find +# the source image for a release, so dropping it would break the release retag. +# The alias does not match Flux's "--" pattern, so Flux +# ignores it. When the flag is unset/false only the legacy - +# tag is produced, so existing consumers are unaffected. # # The timestamp is overridable via BUILD_TIMESTAMP for deterministic tests. -branch_tag() { +set_branch_tags() { local prefix="$1" + local sha="${GITHUB_SHA::8}" if [[ "${INPUT_DOCKER_TAG_TIMESTAMP:-false}" == "true" ]]; then local ts="${BUILD_TIMESTAMP:-$(date -u +%Y%m%d%H%M%S)}" - echo "${prefix}-${ts}-${GITHUB_SHA::8}" + TAG="${prefix}-${ts}-${sha}" + ALIAS_TAG="${prefix}-${sha}" else - echo "${prefix}-${GITHUB_SHA::8}" + TAG="${prefix}-${sha}" + ALIAS_TAG="" fi } @@ -43,15 +53,15 @@ if [[ -n "${INPUT_DOCKER_CUSTOM_TAG:-}" ]]; then PUSH="true" BUILD="${INPUT_DOCKER_DISABLE_RETAGGING:-false}" elif [[ $GITHUB_REF == refs/heads/master ]]; then - TAG="$(branch_tag master)" + set_branch_tags master LATEST="master" PUSH="true" elif [[ $GITHUB_REF == refs/heads/main ]]; then - TAG="$(branch_tag main)" + set_branch_tags main LATEST="main" PUSH="true" elif [[ $GITHUB_REF == refs/heads/dev ]]; then - TAG="$(branch_tag dev)" + set_branch_tags dev LATEST="dev" PUSH="true" elif [[ $GITHUB_REF == refs/tags/v* ]]; then @@ -71,6 +81,9 @@ else fi TAG_LIST="${INPUT_DOCKER_REGISTRY}/${INPUT_DOCKER_IMAGE}:${TAG}" +if [[ -n "${ALIAS_TAG:-}" ]]; then + TAG_LIST+=",${INPUT_DOCKER_REGISTRY}/${INPUT_DOCKER_IMAGE}:${ALIAS_TAG}" +fi if [[ -n "${LATEST:-}" ]]; then TAG_LIST+=",${INPUT_DOCKER_REGISTRY}/${INPUT_DOCKER_IMAGE}:${LATEST}" fi diff --git a/tests/generate-tags.bats b/tests/generate-tags.bats index 2fdfc92..387a9aa 100644 --- a/tests/generate-tags.bats +++ b/tests/generate-tags.bats @@ -69,6 +69,27 @@ teardown() { assert_output_value "latest" "dev" } +@test "timestamp flag pushes a stable - alias in tag_list" { + export INPUT_DOCKER_TAG_TIMESTAMP="true" + export GITHUB_REF="refs/heads/main" + run "$SCRIPT" + assert_success + # canonical timestamped tag + stable sha alias (for release retag) + floating tag + local tag_list + tag_list=$(get_output_value "tag_list") + [[ "$tag_list" == "registry.staffbase.com/my-service:main-20260602143055-abcdef12,registry.staffbase.com/my-service:main-abcdef12,registry.staffbase.com/my-service:main" ]] +} + +@test "no - alias is added when timestamp flag is off" { + export GITHUB_REF="refs/heads/main" + run "$SCRIPT" + assert_success + local tag_list + tag_list=$(get_output_value "tag_list") + [[ "$tag_list" != *"my-service:main-abcdef12,"*"my-service:main-abcdef12"* ]] + [[ "$tag_list" == "registry.staffbase.com/my-service:main-abcdef12,registry.staffbase.com/my-service:main" ]] +} + @test "main branch with timestamp flag inserts timestamp before sha" { export INPUT_DOCKER_TAG_TIMESTAMP="true" export GITHUB_REF="refs/heads/main"