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/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-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/.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 31d5b4f..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: @@ -35,17 +35,15 @@ jobs: platform: ${{ matrix.runner.platform }} image-name: ghcr.io/specsnl/specs-cli target: debian - version: ${{ github.ref_name }} version-build-arg: SPECS_VERSION 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 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): @@ -107,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: @@ -121,18 +132,16 @@ 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: 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 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 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