Skip to content

docs(changelog): add the 0.0.3 release section #2

docs(changelog): add the 0.0.3 release section

docs(changelog): add the 0.0.3 release section #2

Workflow file for this run

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