docs(changelog): add the 0.0.3 release section #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: release | |
| # Tag-driven release: build + smoke-test the PHP matrix, push the images to | |
| # GHCR, then cut a GitHub Release with notes lifted from CHANGELOG.md. | |
| # Trigger: git tag -a vX.Y.Z && git push --follow-tags | |
| on: | |
| push: | |
| tags: ["v*"] | |
| # Least privilege at the top; the jobs that need more opt in explicitly. | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| REGISTRY: ghcr.io | |
| jobs: | |
| images: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read # checkout | |
| packages: write # push to GHCR via the built-in GITHUB_TOKEN | |
| id-token: write # keyless (OIDC) signing for the attestations below | |
| attestations: write # record the provenance + SBOM attestations | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| php: ["8.3", "8.4", "8.5"] | |
| env: | |
| PHP: ${{ matrix.php }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| persist-credentials: false | |
| # Single-source the release coordinates from the Dockerfile ARGs (same as | |
| # the Makefile) so this workflow needs no edit on a version bump. GHCR | |
| # requires a lowercase image path, hence the owner is downcased. | |
| - name: derive image coordinates | |
| run: | | |
| owner=${GITHUB_REPOSITORY_OWNER,,} | |
| { | |
| echo "IMAGE=${REGISTRY}/${owner}/freeunit-php" | |
| echo "VERSION=${GITHUB_REF_NAME#v}" | |
| echo "SUITE=$(sed -n 's/^ARG SUITE=//p' Dockerfile)" | |
| echo "DEFAULT_PHP=$(sed -n 's/^ARG PHP_VER=//p' Dockerfile)" | |
| echo "FREEUNIT_RELEASE=$(sed -n 's/^ARG FREEUNIT_RELEASE=//p' Dockerfile)" | |
| } >> "$GITHUB_ENV" | |
| # Reuses the Makefile target: builds php$PHP with the immutable and | |
| # floating tags, then runs the end-to-end smoke test against it. | |
| - name: build + smoke test | |
| run: make test DEFAULT_PHP="$PHP" IMAGE="$IMAGE" | |
| - name: log in to GHCR | |
| env: | |
| GHCR_USER: ${{ github.actor }} | |
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: echo "$GHCR_TOKEN" | docker login "$REGISTRY" -u "$GHCR_USER" --password-stdin | |
| # Push the two tags make produced (floating + immutable), add a | |
| # release-version tag, and on the default PHP line also publish :latest and | |
| # the bare :$VERSION so `docker pull $IMAGE` and `:$VERSION` resolve. | |
| - name: tag + push | |
| run: | | |
| floating="$IMAGE:${SUITE}-php${PHP}" | |
| immutable="$IMAGE:${SUITE}-${FREEUNIT_RELEASE}-php${PHP}" | |
| versioned="$IMAGE:${VERSION}-php${PHP}" | |
| docker tag "$floating" "$versioned" | |
| docker push "$floating" | |
| docker push "$immutable" | |
| docker push "$versioned" | |
| if [ "$PHP" = "$DEFAULT_PHP" ]; then | |
| docker tag "$floating" "$IMAGE:latest" | |
| docker tag "$floating" "$IMAGE:${VERSION}" | |
| docker push "$IMAGE:latest" | |
| docker push "$IMAGE:${VERSION}" | |
| fi | |
| # All tags for this PHP leg point at one image; resolve its registry | |
| # digest once so the attestations below bind to the manifest, not a | |
| # mutable tag. Export the local ref too for the SBOM scan. | |
| digest=$(docker buildx imagetools inspect "$immutable" --format '{{ .Manifest.Digest }}') | |
| { | |
| echo "IMAGE_DIGEST=$digest" | |
| echo "IMAGE_REF=$immutable" | |
| } >> "$GITHUB_ENV" | |
| # Scan the just-built image into an SPDX SBOM (from the local daemon, so no | |
| # re-pull). Artifact upload is off: the SBOM is published as an attestation | |
| # below, and parallel matrix legs would collide on a shared artifact name. | |
| - name: generate SBOM | |
| uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 | |
| with: | |
| image: ${{ env.IMAGE_REF }} | |
| format: spdx-json | |
| output-file: sbom.spdx.json | |
| upload-artifact: false | |
| # Keyless (OIDC) provenance + SBOM attestations, pushed to GHCR as OCI | |
| # referrers of the image manifest. Verify with: | |
| # gh attestation verify oci://$IMAGE@$DIGEST --owner <owner> | |
| - name: attest build provenance | |
| uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 | |
| with: | |
| subject-name: ${{ env.IMAGE }} | |
| subject-digest: ${{ env.IMAGE_DIGEST }} | |
| push-to-registry: true | |
| - name: attest SBOM | |
| uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0 | |
| with: | |
| subject-name: ${{ env.IMAGE }} | |
| subject-digest: ${{ env.IMAGE_DIGEST }} | |
| sbom-path: sbom.spdx.json | |
| push-to-registry: true | |
| - name: log out of GHCR | |
| if: always() | |
| run: docker logout "$REGISTRY" | |
| release: | |
| needs: images | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # create the GitHub Release | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| persist-credentials: false | |
| # Pull just this version's section out of CHANGELOG.md for the release body | |
| # (everything between this `## [x.y.z]` heading and the next `## [`). | |
| - name: extract changelog section | |
| run: | | |
| version=${GITHUB_REF_NAME#v} | |
| awk -v v="$version" ' | |
| $0 ~ "^## \\[" v "\\]" { grab = 1; next } | |
| grab && /^## \[/ { exit } | |
| grab { print } | |
| ' CHANGELOG.md > release-notes.md | |
| if [ ! -s release-notes.md ]; then | |
| echo "ERROR: no CHANGELOG.md section for $version" >&2 | |
| exit 1 | |
| fi | |
| - name: create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file release-notes.md |