Skip to content

Merge commit from fork #5865

Merge commit from fork

Merge commit from fork #5865

Workflow file for this run

---
name: Build Docker Images
concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
on:
pull_request:
types: [opened, synchronize, reopened, labeled]
branches:
- main
push:
branches:
- main
tags:
- v*.*.*
workflow_dispatch:
inputs:
#checkov:skip=CKV_GHA_7
version:
description: "FrankenPHP version"
required: false
type: string
schedule:
- cron: "0 4 * * *"
permissions:
contents: read
env:
IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
jobs:
prepare:
if: "github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'CI: All jobs')"
runs-on: ubuntu-24.04
outputs:
# Push if it's a scheduled job, a tag, or if we're committing to the main branch
push: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false }}
variants: ${{ steps.matrix.outputs.variants }}
matrix: ${{ steps.matrix.outputs.matrix }}
metadata: ${{ steps.matrix.outputs.metadata }}
php_version: ${{ steps.check.outputs.php_version }}
skip: ${{ steps.check.outputs.skip }}
ref: ${{ steps.check.outputs.ref || (github.ref_type == 'tag' && github.ref_name) || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }}
sha: ${{ steps.check.outputs.sha }}
source_date_epoch: ${{ steps.check.outputs.source_date_epoch }}
created: ${{ steps.check.outputs.created }}
base_fingerprint: ${{ steps.check.outputs.base_fingerprint }}
base_fingerprints: ${{ steps.check.outputs.base_fingerprints }}
rebuild_variants: ${{ steps.check.outputs.rebuild_variants }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Login to DockerHub
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} # zizmor: ignore[secrets-outside-env] TODO: drop once super-linter ships zizmor >=1.24.0, then the allowlist in zizmor.yaml takes over
- name: Check PHP versions and base image fingerprints
id: check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./.github/scripts/docker-compute-fingerprints.sh
- name: Create variants matrix
if: ${{ !fromJson(steps.check.outputs.skip) }}
id: matrix
shell: bash
run: |
set -e
METADATA="$(docker buildx bake --print | jq -c)"
variants="$(jq -c '.group.default.targets|map(sub("runner-|builder-"; ""))|unique' <<< "${METADATA}")"
# On scheduled rebuilds, only build the variants whose base images changed
if [[ -n "${REBUILD_VARIANTS}" && "${REBUILD_VARIANTS}" != "[]" ]]; then
variants="$(jq -c --argjson rebuild "${REBUILD_VARIANTS}" 'map(select(. as $v | $rebuild | index($v)))' <<< "${variants}")"
fi
{
echo metadata="${METADATA}"
echo variants="${variants}"
echo matrix="$(jq -cn --argjson variants "${variants}" --argjson platforms "${VARIANT_PLATFORMS}" \
'{include: [$variants[] as $v | $platforms[$v][] | {variant: $v, platform: .}]}')"
} >> "${GITHUB_OUTPUT}"
env:
SHA: ${{ github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || steps.check.outputs.ref || 'dev' }}
PHP_VERSION: ${{ steps.check.outputs.php_version }}
REBUILD_VARIANTS: ${{ steps.check.outputs.rebuild_variants }}
VARIANT_PLATFORMS: ${{ steps.check.outputs.variant_platforms }}
build:
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
needs:
- prepare
if: ${{ !fromJson(needs.prepare.outputs.skip) }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
- name: Prepare
id: prepare
run: echo "sanitized_platform=${PLATFORM//\//-}" >> "${GITHUB_OUTPUT}"
env:
PLATFORM: ${{ matrix.platform }}
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.ref }}
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
with:
platforms: ${{ matrix.platform }}
- name: Login to DockerHub
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} # zizmor: ignore[secrets-outside-env] TODO: drop once super-linter ships zizmor >=1.24.0, then the allowlist in zizmor.yaml takes over
- name: Build
id: build
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
with:
pull: true
load: ${{ !fromJson(needs.prepare.outputs.push) }}
source: .
targets: |
builder-${{ matrix.variant }}
runner-${{ matrix.variant }}
# Remove tags to prevent "can't push tagged ref [...] by digest" error
# Provenance attestations embed build timestamps, which would prevent reproducible images
set: |
*.tags=
*.platform=${{ matrix.platform }}
*.attest=type=provenance,disabled=true
${{ !fromJson(needs.prepare.outputs.push) && format('builder-{0}.cache-from=type=gha,scope=builder-{0}-{1}-{2}', matrix.variant, needs.prepare.outputs.ref || github.ref, matrix.platform) || '' }}
${{ !fromJson(needs.prepare.outputs.push) && format('builder-{0}.cache-from=type=gha,scope=refs/heads/main-builder-{0}-{1}', matrix.variant, matrix.platform) || '' }}
${{ format('builder-{0}.cache-to=type=gha,scope=builder-{0}-{1}-{2},ignore-error=true', matrix.variant, needs.prepare.outputs.ref || github.ref, matrix.platform) }}
${{ !fromJson(needs.prepare.outputs.push) && format('runner-{0}.cache-from=type=gha,scope=runner-{0}-{1}-{2}', matrix.variant, needs.prepare.outputs.ref || github.ref, matrix.platform) || '' }}
${{ !fromJson(needs.prepare.outputs.push) && format('runner-{0}.cache-from=type=gha,scope=refs/heads/main-runner-{0}-{1}', matrix.variant, matrix.platform) || '' }}
${{ format('runner-{0}.cache-to=type=gha,scope=runner-{0}-{1}-{2},ignore-error=true', matrix.variant, needs.prepare.outputs.ref || github.ref, matrix.platform) }}
${{ fromJson(needs.prepare.outputs.push) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true,rewrite-timestamp=true', env.IMAGE_NAME) || '' }}
env:
SHA: ${{ needs.prepare.outputs.sha || github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
PHP_VERSION: ${{ needs.prepare.outputs.php_version }}
BASE_FINGERPRINT: ${{ needs.prepare.outputs.base_fingerprint }}
BASE_FINGERPRINTS: ${{ needs.prepare.outputs.base_fingerprints }}
CREATED: ${{ needs.prepare.outputs.created }}
SOURCE_DATE_EPOCH: ${{ needs.prepare.outputs.source_date_epoch }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
name: Export metadata
if: fromJson(needs.prepare.outputs.push)
run: |
mkdir -p /tmp/metadata/builder /tmp/metadata/runner
builderDigest=$(jq -r ".\"builder-${VARIANT}\".\"containerimage.digest\"" <<< "${METADATA}")
touch "/tmp/metadata/builder/${builderDigest#sha256:}"
runnerDigest=$(jq -r ".\"runner-${VARIANT}\".\"containerimage.digest\"" <<< "${METADATA}")
touch "/tmp/metadata/runner/${runnerDigest#sha256:}"
env:
METADATA: ${{ steps.build.outputs.metadata }}
VARIANT: ${{ matrix.variant }}
- name: Upload builder metadata
if: fromJson(needs.prepare.outputs.push)
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: metadata-builder-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}
path: /tmp/metadata/builder/*
if-no-files-found: error
retention-days: 1
- name: Upload runner metadata
if: fromJson(needs.prepare.outputs.push)
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: metadata-runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}
path: /tmp/metadata/runner/*
if-no-files-found: error
retention-days: 1
- name: Run tests
if: ${{ !fromJson(needs.prepare.outputs.push) }}
run: |
# TODO: remove "containerimage.config.digest" fallback once all runners use buildx v0.18+
# which replaced it with "containerimage.digest" and "containerimage.descriptor"
docker run --platform="${PLATFORM}" --rm \
"$(jq -r ".\"builder-${VARIANT}\" | .\"containerimage.config.digest\" // .\"containerimage.digest\"" <<< "${METADATA}")" \
sh -c "./go.sh test ${RACE} -timeout 30m -v $(./go.sh list ./... | grep -v github.com/dunglas/frankenphp/internal/testext | grep -v github.com/dunglas/frankenphp/internal/extgen | tr '\n' ' ') && cd caddy && ../go.sh test ${RACE} -timeout 30m -v ./..."
env:
METADATA: ${{ steps.build.outputs.metadata }}
PLATFORM: ${{ matrix.platform }}
VARIANT: ${{ matrix.variant }}
# The Go race detector is only enabled on amd64. PHP's inherited PIE
# flags require external linking for runtime/cgo in pure-Go test packages.
RACE: ${{ matrix.platform == 'linux/amd64' && '-race -ldflags=-linkmode=external' || '' }}
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
push:
runs-on: ubuntu-24.04
needs:
- prepare
- build
if: fromJson(needs.prepare.outputs.push)
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
strategy:
fail-fast: false
matrix:
variant: ${{ fromJson(needs.prepare.outputs.variants) }}
target: ["builder", "runner"]
steps:
- name: Download metadata
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: metadata-${{ matrix.target }}-${{ matrix.variant }}-*
path: /tmp/metadata
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Login to DockerHub
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} # zizmor: ignore[secrets-outside-env] TODO: drop once super-linter ships zizmor >=1.24.0, then the allowlist in zizmor.yaml takes over
- name: Create manifest list and push
working-directory: /tmp/metadata
run: |
set -x
# shellcheck disable=SC2046,SC2086
docker buildx imagetools create $(jq -cr ".target.\"${TARGET}-${VARIANT}\".tags | map(\"-t \" + .) | join(\" \")" <<< ${METADATA}) \
$(printf "${IMAGE_NAME}@sha256:%s " *)
env:
METADATA: ${{ needs.prepare.outputs.metadata }}
TARGET: ${{ matrix.target }}
VARIANT: ${{ matrix.variant }}
- name: Inspect image
id: inspect
run: |
# shellcheck disable=SC2046,SC2086
tag=$(jq -cr ".target.\"${TARGET}-${VARIANT}\".tags | first" <<< ${METADATA})
docker buildx imagetools inspect "${tag}"
digest=$(docker buildx imagetools inspect --format '{{.Manifest.Digest}}' "${tag}")
echo "digest=${digest}" >> "${GITHUB_OUTPUT}"
env:
METADATA: ${{ needs.prepare.outputs.metadata }}
TARGET: ${{ matrix.target }}
VARIANT: ${{ matrix.variant }}
- uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
# docker.io/ prefix is required: actions/attest splits subject-name
# on the first '/' to find the registry. We only push to Docker Hub.
subject-name: docker.io/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.inspect.outputs.digest }}
push-to-registry: true