Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 49 additions & 14 deletions .github/scripts/docker-compute-fingerprints.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,37 @@ get_php_version() {
jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")'
}

get_image_digest() {
local image="$1" ref
if [[ "${image}" == */* ]]; then
ref="docker://docker.io/${image}"
image_ref() {
if [[ "$1" == */* ]]; then
echo "docker://docker.io/$1"
else
ref="docker://docker.io/library/${image}"
echo "docker://docker.io/library/$1"
fi
skopeo inspect "${ref}" \
}

get_image_digest() {
skopeo inspect "$(image_ref "$1")" \
--override-os linux \
--override-arch amd64 \
--format '{{.Digest}}'
}

get_image_platforms() {
local platforms
platforms="$(skopeo inspect --raw "$(image_ref "$1")" | jq -c '
[.manifests // [] | .[] | .platform | select(.os == "linux")
| "linux/\(.architecture)" + (if .architecture == "arm" and (.variant // "") != "" then "/\(.variant)" else "" end)]
| unique
')"

if [[ "${platforms}" == "[]" ]]; then
echo "No linux platform in the manifest of $1" >&2
return 1
fi

echo "${platforms}"
}

get_existing_fingerprint() {
local tag="$1"
skopeo inspect "docker://docker.io/dunglas/frankenphp:${tag}" \
Expand All @@ -50,10 +68,6 @@ main() {

PHP_VERSION="${PHP_82_LATEST},${PHP_83_LATEST},${PHP_84_LATEST},${PHP_85_LATEST}"
write_output "php_version=${PHP_VERSION}"
write_output "php82_version=${PHP_82_LATEST//./-}"
write_output "php83_version=${PHP_83_LATEST//./-}"
write_output "php84_version=${PHP_84_LATEST//./-}"
write_output "php85_version=${PHP_85_LATEST//./-}"

local FRANKENPHP_LATEST_TAG=""
if [[ "${GITHUB_EVENT_NAME:-}" == "schedule" ]]; then
Expand All @@ -74,21 +88,22 @@ main() {
# Collect the base images (docker-image:// contexts) of each variant. The variant key
# is derived from the php-base ref (e.g. "php:8.4.23-zts-trixie" -> "8.4.23-trixie") and
# matches the "${php-version}-${os}" keys expected by docker-bake.hcl for BASE_FINGERPRINTS.
declare -A VARIANT_IMAGES=() VARIANT_NAMES=() DIGEST_CACHE=() VARIANT_FINGERPRINTS=()
local target php_base images image variant_key variant_name
while IFS=$'\t' read -r target php_base images; do
declare -A VARIANT_IMAGES=() VARIANT_NAMES=() VARIANT_PLATFORMS=() DIGEST_CACHE=() VARIANT_FINGERPRINTS=()
local target php_base images platforms image variant_key variant_name
while IFS=$'\t' read -r target php_base images platforms; do
[[ -z "${php_base}" ]] && continue
variant_key="${php_base#php:}"
variant_key="${variant_key/-zts/}"
variant_name="${target#builder-}"
variant_name="${variant_name#runner-}"
VARIANT_IMAGES["${variant_key}"]="${images}"
VARIANT_NAMES["${variant_key}"]="${variant_name}"
VARIANT_PLATFORMS["${variant_key}"]="${platforms}"
done < <(jq -r '
.target | to_entries[]
| (.value.contexts // {} | [to_entries[].value | select(startswith("docker-image://")) | sub("^docker-image://"; "")]) as $images
| select(($images | length) > 0)
| [.key, ($images | map(select(startswith("php:"))) | first // ""), ($images | sort | join(" "))]
| [.key, ($images | map(select(startswith("php:"))) | first // ""), ($images | sort | join(" ")), (.value.platforms // [] | tojson)]
| @tsv
' <<<"${METADATA}")

Expand All @@ -114,6 +129,26 @@ main() {
write_output "base_fingerprint=${BASE_FINGERPRINT}"
write_output "base_fingerprints=${fingerprints_json}"

declare -A PLATFORM_CACHE=()
local variant_platforms="{}" buildable
for variant_key in "${!VARIANT_IMAGES[@]}"; do
buildable="${VARIANT_PLATFORMS["${variant_key}"]}"
for image in ${VARIANT_IMAGES["${variant_key}"]}; do
if [[ -z "${PLATFORM_CACHE["${image}"]:-}" ]]; then
PLATFORM_CACHE["${image}"]="$(get_image_platforms "${image}")"
fi
buildable="$(jq -c --argjson carried "${PLATFORM_CACHE["${image}"]}" 'map(select(IN($carried[])))' <<<"${buildable}")"
done

if [[ "${buildable}" == "[]" ]]; then
echo "None of ${VARIANT_PLATFORMS["${variant_key}"]} is carried by every base image of ${VARIANT_NAMES["${variant_key}"]}" >&2
return 1
fi

variant_platforms="$(jq -c --arg k "${VARIANT_NAMES["${variant_key}"]}" --argjson v "${buildable}" '. + {($k): $v}' <<<"${variant_platforms}")"
done
write_output "variant_platforms=${variant_platforms}"

if [[ "${GITHUB_EVENT_NAME:-}" != "schedule" ]]; then
write_output "skip=false"
return 0
Expand Down
38 changes: 6 additions & 32 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,9 @@ jobs:
# 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 }}
platforms: ${{ steps.matrix.outputs.platforms }}
matrix: ${{ steps.matrix.outputs.matrix }}
metadata: ${{ steps.matrix.outputs.metadata }}
php_version: ${{ steps.check.outputs.php_version }}
php82_version: ${{ steps.check.outputs.php82_version }}
php83_version: ${{ steps.check.outputs.php83_version }}
php84_version: ${{ steps.check.outputs.php84_version }}
php85_version: ${{ steps.check.outputs.php85_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 }}
Expand Down Expand Up @@ -89,45 +85,23 @@ jobs:
{
echo metadata="${METADATA}"
echo variants="${variants}"
echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "${METADATA}")"
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:
variant: ${{ fromJson(needs.prepare.outputs.variants) }}
platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
include:
- race: ""
- platform: linux/amd64
race: "-race" # The Go race detector is only supported on amd64
exclude:
# arm/v6 is only available for Alpine: https://github.com/docker-library/golang/issues/502
- variant: php-${{ needs.prepare.outputs.php82_version }}-trixie
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php83_version }}-trixie
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php84_version }}-trixie
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php85_version }}-trixie
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php82_version }}-bookworm
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php83_version }}-bookworm
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php84_version }}-bookworm
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php85_version }}-bookworm
platform: linux/arm/v6
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
- name: Prepare
id: prepare
Expand Down Expand Up @@ -222,7 +196,7 @@ jobs:
METADATA: ${{ steps.build.outputs.metadata }}
PLATFORM: ${{ matrix.platform }}
VARIANT: ${{ matrix.variant }}
RACE: ${{ matrix.race }}
RACE: ${{ matrix.platform == 'linux/amd64' && '-race' || '' }}

# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
push:
Expand Down
Loading