Readable job names, latest tracks main, and an AGENTS.md
Job names in the Gitea UI rendered as the raw matrix expression
("${{ fromJSON(needs.select.outputs.images) }}"). Gitea resolves a job's matrix
when it PARSES the workflow, before `needs` outputs exist, so matrix.image was
interpolated against an unresolved matrix. There is no way to win with a dynamic
matrix: jobparser.nameWithMatrix interpolates a name containing "${{ }}", and
appends "(<values>)" to one that doesn't — either way the raw expression shows.
See go-gitea/gitea#28207.
So drop the matrix. build.yaml now runs one job, "Build changed images", that
loops over the selected images and emits ::group:: markers, giving a collapsible
section per image. Also: every step has an explicit static name, because Gitea
does not interpolate expressions in names either ("Log in to ${{ env.REGISTRY }}"
rendered literally).
Tag scheme, per review: `latest` now tracks main rather than the newest release,
and `edge` is gone — it's an Alpine/Traefik convention, not a broad standard, and
`main-<sha>` already covers "a specific commit". `latest` has exactly one owner
so a release tag and a main build can't race to define it. Release tags remain
immutable `:vX.Y.Z`/`:vX.Y`/`:vX` for pinning. This also means the ToolHive
manifest's `:latest` resolves as soon as this lands on main, with no release tag
needed first.
hack/docker-tags.sh folded into hack/build-images.sh, which is now the whole
pipeline — tag, build, smoke-test, push — shared by `make build` and CI. It uses
plain `docker build` instead of buildx, dropping setup-buildx-action: it loads
into the local store so the test runs pre-publish, and emits a plain manifest
with no attestations for Gitea's registry.
Verified in a simulated runner (repo in a docker volume, socket mounted, real
runner image): select + build + group markers, all four tag modes, and the
multi-image loop with a scratch second image.
AGENTS.md records the conventions and, importantly, the three Gitea gotchas that
all look fine locally: no bind-mounting the workspace into a sibling container,
no dynamic matrix, no expressions in names.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
+18
-38
@@ -32,61 +32,41 @@ jobs:
|
||||
images: ${{ steps.select.outputs.images }}
|
||||
any: ${{ steps.select.outputs.any }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # need history to diff against the base commit
|
||||
|
||||
- id: select
|
||||
- name: Work out which images changed
|
||||
id: select
|
||||
run: ./hack/select-images.sh >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
DISPATCH_IMAGE: ${{ github.event.inputs.image }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
|
||||
|
||||
# One job that loops, rather than a matrix job per image: Gitea resolves a matrix
|
||||
# when it parses the workflow, before `needs` outputs exist, so a dynamic matrix
|
||||
# produces a single job named after the raw expression. Looping keeps the job name
|
||||
# readable and gives one collapsible log section per image.
|
||||
build:
|
||||
name: ${{ matrix.image }}
|
||||
name: Build changed images
|
||||
needs: select
|
||||
if: needs.select.outputs.any == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: ${{ fromJSON(needs.select.outputs.images) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- id: meta
|
||||
run: ./hack/docker-tags.sh '${{ matrix.image }}' >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
|
||||
# Loaded rather than pushed, so the smoke test runs before anything is
|
||||
# published. provenance is off because Gitea's registry rejects buildkit
|
||||
# attestation manifests.
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: images/${{ matrix.image }}
|
||||
load: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
provenance: false
|
||||
build-args: |
|
||||
VERSION=${{ steps.meta.outputs.version }}
|
||||
REVISION=${{ github.sha }}
|
||||
CREATED=${{ steps.meta.outputs.created }}
|
||||
|
||||
- name: Smoke test
|
||||
run: make test IMAGE='${{ matrix.image }}' REF='${{ steps.meta.outputs.primary }}'
|
||||
|
||||
- name: Log in to ${{ env.REGISTRY }}
|
||||
if: steps.meta.outputs.push == 'true'
|
||||
# Never on a pull request, which is exactly when nothing gets published.
|
||||
- name: Log in to the Gitea container registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.DOCKER_USER }}
|
||||
password: ${{ secrets.API_TOKEN }}
|
||||
|
||||
- name: Push
|
||||
if: steps.meta.outputs.push == 'true'
|
||||
run: printf '%s\n' '${{ steps.meta.outputs.tags }}' | xargs -r -n1 -t docker push
|
||||
- name: Build, smoke-test and publish
|
||||
run: ./hack/build-images.sh ${{ needs.select.outputs.images }}
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
|
||||
@@ -8,9 +8,11 @@ on:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
# Same targets you run locally with `make check lint`.
|
||||
- name: Repository layout
|
||||
|
||||
Reference in New Issue
Block a user