fix(ci-images): static build matrix for Gitea
Gitea expands a job's matrix when the run is created, before plan has any
outputs, so fromJSON(needs.plan.outputs.matrix) collapsed to a single empty
"Build ${{ matrix.key }}" job and nothing was ever built. The matrix is now
the fixed list of image keys; plan emits every image's spec with a build flag
and each matrix job looks its own entry up, no-opping when it wasn't picked.
Also document that both registry tokens need write:package -- the vault token
was read-only, so the gitea_ci_build_local bootstrap failed its push.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8701ada7e2
commit
be50798096
@@ -63,7 +63,7 @@ jobs:
|
||||
name: Plan
|
||||
runs-on: fedora
|
||||
outputs:
|
||||
matrix: ${{ steps.plan.outputs.matrix }}
|
||||
images: ${{ steps.plan.outputs.images }}
|
||||
any: ${{ steps.plan.outputs.any }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -153,7 +153,12 @@ jobs:
|
||||
else:
|
||||
picked = [i for i in images if f"{ctx}/{i['containerfile']}" in touched]
|
||||
|
||||
print(f"matrix={json.dumps({'include': picked})}")
|
||||
# Every image, keyed by matrix.key, each flagged build or skip. The
|
||||
# build job's matrix is static (see there), so it needs the full set
|
||||
# to look its own entry up in, not just the picked ones.
|
||||
picked_keys = {i["key"] for i in picked}
|
||||
specs = {i["key"]: {**i, "build": i["key"] in picked_keys} for i in images}
|
||||
print(f"images={json.dumps(specs)}")
|
||||
print(f"any={'true' if picked else 'false'}")
|
||||
print("building: " + (", ".join(i["tag"] for i in picked) or "nothing"), file=sys.stderr)
|
||||
PY
|
||||
@@ -167,11 +172,34 @@ jobs:
|
||||
# One image failing must not cancel the others: they are independent, and
|
||||
# a half-published set is what this whole workflow exists to avoid.
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
|
||||
# Static on purpose. Gitea expands the matrix when the run is created,
|
||||
# before plan has produced any outputs, so a
|
||||
# fromJSON(needs.plan.outputs.*) matrix collapses to one empty job. Each
|
||||
# entry instead looks its spec up in plan's output and no-ops its steps
|
||||
# when plan did not pick it. Keys must match `images` in plan.
|
||||
matrix:
|
||||
key: [ci, espidf, platformio]
|
||||
steps:
|
||||
- name: Look up the ${{ matrix.key }} image spec
|
||||
id: spec
|
||||
env:
|
||||
IMAGES: ${{ needs.plan.outputs.images }}
|
||||
KEY: ${{ matrix.key }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 - <<'PY' >> "$GITHUB_OUTPUT"
|
||||
import json, os
|
||||
spec = json.loads(os.environ["IMAGES"])[os.environ["KEY"]]
|
||||
for k in ("containerfile", "tag", "build_args"):
|
||||
print(f"{k}={spec[k]}")
|
||||
print(f"build={'true' if spec['build'] else 'false'}")
|
||||
PY
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: steps.spec.outputs.build == 'true'
|
||||
|
||||
- name: Log in to the Gitea Container Registry
|
||||
if: steps.spec.outputs.build == 'true'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
@@ -184,18 +212,20 @@ jobs:
|
||||
# image, so PRs get a throwaway tag that the cleanup step removes.
|
||||
- name: Resolve build tag
|
||||
id: tag
|
||||
if: steps.spec.outputs.build == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
echo "image=${{ matrix.tag }}-pr${{ github.event.number }}" >> "$GITHUB_OUTPUT"
|
||||
echo "image=${{ steps.spec.outputs.tag }}-pr${{ github.event.number }}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "image=${{ matrix.tag }}" >> "$GITHUB_OUTPUT"
|
||||
echo "image=${{ steps.spec.outputs.tag }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Build ${{ matrix.key }}
|
||||
if: steps.spec.outputs.build == 'true'
|
||||
env:
|
||||
IMAGE: ${{ steps.tag.outputs.image }}
|
||||
BUILD_ARGS: ${{ matrix.build_args }}
|
||||
BUILD_ARGS: ${{ steps.spec.outputs.build_args }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
args=()
|
||||
@@ -205,10 +235,11 @@ jobs:
|
||||
docker build --pull \
|
||||
"${args[@]}" \
|
||||
-t "$IMAGE" \
|
||||
-f "$CONTEXT/${{ matrix.containerfile }}" \
|
||||
-f "$CONTEXT/${{ steps.spec.outputs.containerfile }}" \
|
||||
"$CONTEXT"
|
||||
|
||||
- name: Verify the prune-exemption label survived the build
|
||||
if: steps.spec.outputs.build == 'true'
|
||||
env:
|
||||
IMAGE: ${{ steps.tag.outputs.image }}
|
||||
run: |
|
||||
@@ -224,7 +255,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Push ${{ matrix.key }}
|
||||
if: github.event_name != 'pull_request'
|
||||
if: github.event_name != 'pull_request' && steps.spec.outputs.build == 'true'
|
||||
env:
|
||||
IMAGE: ${{ steps.tag.outputs.image }}
|
||||
run: |
|
||||
@@ -236,7 +267,7 @@ jobs:
|
||||
# so the nightly prune will not reclaim it and a few skipped cleanups add
|
||||
# up to gigabytes in the runner's store.
|
||||
- name: Drop the pull-request image
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
if: always() && github.event_name == 'pull_request' && steps.spec.outputs.build == 'true'
|
||||
env:
|
||||
IMAGE: ${{ steps.tag.outputs.image }}
|
||||
run: docker rmi -f "$IMAGE" || true
|
||||
|
||||
Reference in New Issue
Block a user