From a5db4b458f94dc507e24713f330e6a994818a517 Mon Sep 17 00:00:00 2001 From: Ilyes512 Date: Tue, 15 Sep 2026 00:48:59 +0200 Subject: [PATCH 1/2] fix(go-cli): default the version to the tag without its leading v MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build-go-cli.yml required a version, and the documented way to supply it was `${{ github.ref_name }}` — which is `v1.2.3`. Every Go repository in the org also releases through GoReleaser, which strips the `v` when it injects the same ldflag, so following the example publishes an image reporting `v1.2.3` while the binary cut from that very tag reports `1.2.3`. GitHub expressions have no way to strip a prefix, so every consumer had to add a job for it. specs-cli already has one. Better to resolve it once here: the input is now optional and defaults, on a tag push, to the tag with the `v` removed. Explicitly passing a version still overrides it. On any other trigger the default is empty and the build arg is omitted rather than passed empty, so the Dockerfile's fallback stands instead of the version being set to the empty string. merge-go-cli.yml needed nothing: metadata-action already labels the image org.opencontainers.image.version with the version it computed, so its `version` input was overriding a correct default. Documented as the override it is, and dropped from the examples. --- .github/workflows/build-go-cli.yml | 28 +++++++++++++++++++++++++--- .github/workflows/merge-go-cli.yml | 4 +++- docs/go-cli.md | 29 +++++++++++++++++++---------- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-go-cli.yml b/.github/workflows/build-go-cli.yml index 6c59c70..02aee86 100644 --- a/.github/workflows/build-go-cli.yml +++ b/.github/workflows/build-go-cli.yml @@ -16,9 +16,12 @@ on: type: string required: true version: - description: Version injected into the binary, i.e. the tag the release is cut from + description: >- + Version injected into the binary. Defaults, on a tag push, to the tag without its leading + "v" — the string GoReleaser injects, so an image never disagrees with the binary cut from + the same tag. Left empty on any other trigger, so the Dockerfile's own fallback stands. type: string - required: true + required: false version-build-arg: description: >- Name of the Dockerfile ARG the version is passed to, i.e. "SPECS_VERSION". The Dockerfile @@ -69,7 +72,24 @@ on: jobs: + version: + name: Version + runs-on: ${{ inputs.runs-on }} + outputs: + value: ${{ steps.resolve.outputs.value }} + steps: + - id: resolve + env: + GIVEN: ${{ inputs.version }} + run: | + value="$GIVEN" + if [ -z "$value" ] && [ "$GITHUB_REF_TYPE" = tag ]; then + value="${GITHUB_REF_NAME#v}" + fi + echo "value=$value" >> "$GITHUB_OUTPUT" + build: + needs: version uses: ./.github/workflows/build.yml with: runs-on: ${{ inputs.runs-on }} @@ -83,6 +103,8 @@ jobs: secrets: ${{ inputs.secrets }} push: ${{ inputs.push }} disable-apparmor: ${{ inputs.disable-apparmor }} + # Omitted entirely when there is no version, rather than passed empty: + # an empty ARG would override the Dockerfile's fallback with nothing. build-args: | - ${{ inputs.version-build-arg }}=${{ inputs.version }} + ${{ needs.version.outputs.value != '' && format('{0}={1}', inputs.version-build-arg, needs.version.outputs.value) || '' }} ${{ inputs.build-args }} diff --git a/.github/workflows/merge-go-cli.yml b/.github/workflows/merge-go-cli.yml index 9a11a0e..647be98 100644 --- a/.github/workflows/merge-go-cli.yml +++ b/.github/workflows/merge-go-cli.yml @@ -22,7 +22,9 @@ on: type: string required: false version: - description: Value for org.opencontainers.image.version + description: >- + Overrides org.opencontainers.image.version. Rarely needed — metadata-action already sets + that label to the version it computed, i.e. "1.2.3" for a "v1.2.3" tag. type: string required: false title: diff --git a/docs/go-cli.md b/docs/go-cli.md index 31d5b4f..e9e30af 100644 --- a/docs/go-cli.md +++ b/docs/go-cli.md @@ -35,7 +35,6 @@ jobs: platform: ${{ matrix.runner.platform }} image-name: ghcr.io/specsnl/specs-cli target: debian - version: ${{ github.ref_name }} version-build-arg: SPECS_VERSION merge: @@ -45,7 +44,6 @@ jobs: runs-on: ubuntu-24.04 image-name: ghcr.io/specsnl/specs-cli target: debian - version: ${{ github.ref_name }} ``` `target` is the Dockerfile stage to publish. The consuming repository owns its stages — see @@ -54,8 +52,8 @@ jobs: ## Version injection Go CLIs carry their version in an ldflag, so it has to be known at build time or the image reports its fallback -(`dev`). `build-go-cli.yml` passes `version` to the Dockerfile as the build arg named by `version-build-arg`; the -Dockerfile keeps ownership of the ldflag itself, which is how every Go repository in the org is already written: +(`dev`). `build-go-cli.yml` passes it to the Dockerfile as the build arg named by `version-build-arg`; the Dockerfile +keeps ownership of the ldflag itself, which is how every Go repository in the org is already written: ```dockerfile ARG GO_MODULE=github.com/specsnl/specs-cli @@ -65,13 +63,26 @@ RUN CGO_ENABLED=0 go build \ -ldflags "-s -w -X ${GO_MODULE}/internal/cmd.Version=${SPECS_VERSION}" -o ./specs ``` -`version-build-arg` has no default on purpose. The arg is named after the binary and differs per repository -(`SPECS_VERSION`, `LABELSYNC_VERSION`, …), and a wrong value fails silently: buildx warns about an unused build arg, -the build succeeds, and the image reports `dev`. Assert the version in a -[pull-request guard](testing-images.md) so that stays impossible to ship. +On a tag push the version defaults to **the tag without its leading `v`** — `v1.2.3` becomes `1.2.3` — so the +examples above pass no `version` at all. That default is not cosmetic. Every Go repository in the org also releases +through GoReleaser, which strips the `v` when it injects the same ldflag; passing `${{ github.ref_name }}` straight +through would publish an image reporting `v1.2.3` while the binary from that very tag reports `1.2.3`. + +Pass `version` explicitly to override it — to build a release from something other than its tag, or to stamp a version +on a branch build. On any trigger that is not a tag push the default is empty, and the build arg is then omitted +rather than passed empty, so the Dockerfile's own fallback stands. + +`version-build-arg` has no default on purpose, and is the one input here that genuinely cannot have one. The arg is +named after the binary and differs per repository (`SPECS_VERSION`, `LABELSYNC_VERSION`, …), and a wrong value fails +silently: buildx warns about an unused build arg, the build succeeds, and the image reports `dev`. Assert the version +in a [pull-request guard](testing-images.md) so that stays impossible to ship. Anything else the Dockerfile needs goes through `build-args`, which is appended to the version arg. +`merge-go-cli.yml` needs no `version` either: `metadata-action` already labels the image +`org.opencontainers.image.version` with the version it computed. The input is there to override that, which is rarely +what anyone wants. + ## Tags On top of what [`merge.yml` already emits](pipeline.md#tags): @@ -121,7 +132,6 @@ Run the build and merge jobs once per variant, each with its own `target`: platform: ${{ matrix.runner.platform }} image-name: ghcr.io/specsnl/specs-cli target: alpine - version: ${{ github.ref_name }} version-build-arg: SPECS_VERSION merge-alpine: @@ -132,7 +142,6 @@ Run the build and merge jobs once per variant, each with its own `target`: image-name: ghcr.io/specsnl/specs-cli target: alpine variant: alpine - version: ${{ github.ref_name }} ``` `variant: alpine` yields `specs-cli:1.2.3-alpine` and a bare `specs-cli:alpine`, alongside the unsuffixed primary From b8067b3adb59cc3ab110734b873c6c535a49de83 Mon Sep 17 00:00:00 2001 From: Ilyes512 Date: Tue, 15 Sep 2026 00:49:14 +0200 Subject: [PATCH 2/2] Bump internal version reference --- .github/workflows/build.yml | 2 +- .github/workflows/merge.yml | 2 +- README.md | 2 +- docs/actions.md | 4 ++-- docs/go-cli.md | 8 ++++---- docs/php.md | 4 ++-- docs/testing-images.md | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2bed33..83831e0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,7 +85,7 @@ jobs: uses: docker/setup-buildx-action@v4 - name: Build and Push by digest - uses: specsnl/github-actions/build-image@2.3.0 + uses: specsnl/github-actions/build-image@2.4.0 with: dockerfile: ${{ inputs.dockerfile }} context: ${{ inputs.context }} diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index e840806..d0865ce 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -67,7 +67,7 @@ jobs: uses: docker/setup-buildx-action@v4 - name: Create Manifest - uses: specsnl/github-actions/create-manifest@2.3.0 + uses: specsnl/github-actions/create-manifest@2.4.0 with: image-name: ${{ steps.image_name.outputs.lowercase }} target: ${{ inputs.target }} diff --git a/README.md b/README.md index aaa163f..2c677cb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This repository contains the Specsnl organisation collection of GitHub Actions workflows and composite actions that can be reused to automate various tasks in GitHub repositories. -Consumers pin by tag, i.e. `specsnl/github-actions/.github/workflows/build.yml@2.3.0`. +Consumers pin by tag, i.e. `specsnl/github-actions/.github/workflows/build.yml@2.4.0`. ## What is in here diff --git a/docs/actions.md b/docs/actions.md index 347e4ab..cbb12b3 100644 --- a/docs/actions.md +++ b/docs/actions.md @@ -9,7 +9,7 @@ Both assume the job has already checked out, logged in to the registry and set u ## `build-image` ```yaml -- uses: specsnl/github-actions/build-image@2.3.0 +- uses: specsnl/github-actions/build-image@2.4.0 ``` | Input | Default | Description | @@ -42,7 +42,7 @@ about conflicting outputs. With `load` on, the digest export and artifact upload ## `create-manifest` ```yaml -- uses: specsnl/github-actions/create-manifest@2.3.0 +- uses: specsnl/github-actions/create-manifest@2.4.0 ``` | Input | Default | Description | diff --git a/docs/go-cli.md b/docs/go-cli.md index e9e30af..e2ff796 100644 --- a/docs/go-cli.md +++ b/docs/go-cli.md @@ -21,7 +21,7 @@ permissions: jobs: build: - uses: specsnl/github-actions/.github/workflows/build-go-cli.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/build-go-cli.yml@2.4.0 strategy: fail-fast: false matrix: @@ -39,7 +39,7 @@ jobs: merge: needs: build - uses: specsnl/github-actions/.github/workflows/merge-go-cli.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/merge-go-cli.yml@2.4.0 with: runs-on: ubuntu-24.04 image-name: ghcr.io/specsnl/specs-cli @@ -118,7 +118,7 @@ Run the build and merge jobs once per variant, each with its own `target`: ```yaml build-alpine: - uses: specsnl/github-actions/.github/workflows/build-go-cli.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/build-go-cli.yml@2.4.0 strategy: fail-fast: false matrix: @@ -136,7 +136,7 @@ Run the build and merge jobs once per variant, each with its own `target`: merge-alpine: needs: build-alpine - uses: specsnl/github-actions/.github/workflows/merge-go-cli.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/merge-go-cli.yml@2.4.0 with: runs-on: ubuntu-24.04 image-name: ghcr.io/specsnl/specs-cli diff --git a/docs/php.md b/docs/php.md index f531a0f..9f1ef15 100644 --- a/docs/php.md +++ b/docs/php.md @@ -8,7 +8,7 @@ what name. jobs: build: - uses: specsnl/github-actions/.github/workflows/build-php.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/build-php.yml@2.4.0 strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: merge: needs: build - uses: specsnl/github-actions/.github/workflows/merge-php.yml@2.3.0 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@2.4.0 with: runs-on: ubuntu-24.04 image-name: ghcr.io/${{ github.repository }} diff --git a/docs/testing-images.md b/docs/testing-images.md index efa757e..43eb6b8 100644 --- a/docs/testing-images.md +++ b/docs/testing-images.md @@ -21,7 +21,7 @@ jobs: - uses: docker/setup-buildx-action@v4 - id: build - uses: specsnl/github-actions/build-image@2.3.0 + uses: specsnl/github-actions/build-image@2.4.0 with: platform: linux/amd64 image-name: ghcr.io/specsnl/specs-cli