Skip to content

Commit be2d6b9

Browse files
opctimTim Nelles
andauthored
Merge commit from fork
Compute base-image fingerprint from bake metadata and store it under a vendor label. Add a local test script to reproduce the fingerprint and compare runs. Co-authored-by: Tim Nelles <tim.nelles@denkwerk.com>
1 parent ad7e4f1 commit be2d6b9

4 files changed

Lines changed: 181 additions & 42 deletions

File tree

.github/workflows/docker.yaml

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -50,54 +50,19 @@ jobs:
5050
php85_version: ${{ steps.check.outputs.php85_version }}
5151
skip: ${{ steps.check.outputs.skip }}
5252
ref: ${{ steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }}
53+
base_fingerprint: ${{ steps.check.outputs.base_fingerprint }}
5354
steps:
54-
- name: Check PHP versions
55-
id: check
56-
env:
57-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58-
run: |
59-
PHP_82_LATEST=$(skopeo inspect docker://docker.io/library/php:8.2 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
60-
PHP_83_LATEST=$(skopeo inspect docker://docker.io/library/php:8.3 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
61-
PHP_84_LATEST=$(skopeo inspect docker://docker.io/library/php:8.4 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
62-
PHP_85_LATEST=$(skopeo inspect docker://docker.io/library/php:8.5 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
63-
{
64-
echo php_version="${PHP_82_LATEST},${PHP_83_LATEST},${PHP_84_LATEST},${PHP_85_LATEST}"
65-
echo php82_version="${PHP_82_LATEST//./-}"
66-
echo php83_version="${PHP_83_LATEST//./-}"
67-
echo php84_version="${PHP_84_LATEST//./-}"
68-
echo php85_version="${PHP_85_LATEST//./-}"
69-
} >> "${GITHUB_OUTPUT}"
70-
71-
# Check if the Docker images must be rebuilt
72-
if [[ "${GITHUB_EVENT_NAME}" != "schedule" ]]; then
73-
echo skip=false >> "${GITHUB_OUTPUT}"
74-
exit 0
75-
fi
76-
77-
FRANKENPHP_LATEST_TAG=$(gh release view --repo php/frankenphp --json tagName --jq '.tagName')
78-
FRANKENPHP_LATEST_TAG_NO_PREFIX="${FRANKENPHP_LATEST_TAG#v}"
79-
FRANKENPHP_82_LATEST=$(skopeo inspect docker://docker.io/dunglas/frankenphp:"${FRANKENPHP_LATEST_TAG_NO_PREFIX}"-php8.2 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
80-
FRANKENPHP_83_LATEST=$(skopeo inspect docker://docker.io/dunglas/frankenphp:"${FRANKENPHP_LATEST_TAG_NO_PREFIX}"-php8.3 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
81-
FRANKENPHP_84_LATEST=$(skopeo inspect docker://docker.io/dunglas/frankenphp:"${FRANKENPHP_LATEST_TAG_NO_PREFIX}"-php8.4 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
82-
FRANKENPHP_85_LATEST=$(skopeo inspect docker://docker.io/dunglas/frankenphp:"${FRANKENPHP_LATEST_TAG_NO_PREFIX}"-php8.5 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
83-
84-
if [[ "${FRANKENPHP_82_LATEST}" == "${PHP_82_LATEST}" ]] && [[ "${FRANKENPHP_83_LATEST}" == "${PHP_83_LATEST}" ]] && [[ "${FRANKENPHP_84_LATEST}" == "${PHP_84_LATEST}" ]] && [[ "${FRANKENPHP_85_LATEST}" == "${PHP_85_LATEST}" ]]; then
85-
echo skip=true >> "${GITHUB_OUTPUT}"
86-
exit 0
87-
fi
88-
89-
{
90-
echo ref="${FRANKENPHP_LATEST_TAG}"
91-
echo skip=false
92-
} >> "${GITHUB_OUTPUT}"
9355
- uses: actions/checkout@v6
94-
if: ${{ !fromJson(steps.check.outputs.skip) }}
9556
with:
96-
ref: ${{ steps.check.outputs.ref }}
57+
fetch-depth: 0
9758
persist-credentials: false
9859
- name: Set up Docker Buildx
99-
if: ${{ !fromJson(steps.check.outputs.skip) }}
10060
uses: docker/setup-buildx-action@v3
61+
- name: Check PHP versions and base image fingerprint
62+
id: check
63+
env:
64+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65+
run: ./scripts/ci/compute-fingerprint.sh
10166
- name: Create variants matrix
10267
if: ${{ !fromJson(steps.check.outputs.skip) }}
10368
id: matrix
@@ -192,6 +157,7 @@ jobs:
192157
SHA: ${{ github.sha }}
193158
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
194159
PHP_VERSION: ${{ needs.prepare.outputs.php_version }}
160+
BASE_FINGERPRINT: ${{ needs.prepare.outputs.base_fingerprint }}
195161
- # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
196162
name: Export metadata
197163
if: fromJson(needs.prepare.outputs.push)

docker-bake.hcl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ variable "GO_VERSION" {
1414
default = "1.25"
1515
}
1616

17+
variable "BASE_FINGERPRINT" {
18+
default = ""
19+
}
20+
1721
variable "SPC_OPT_BUILD_ARGS" {
1822
default = ""
1923
}
@@ -120,6 +124,7 @@ target "default" {
120124
"org.opencontainers.image.created" = "${timestamp()}"
121125
"org.opencontainers.image.version" = VERSION
122126
"org.opencontainers.image.revision" = SHA
127+
"dev.frankenphp.base.fingerprint" = BASE_FINGERPRINT
123128
}
124129
args = {
125130
FRANKENPHP_VERSION = VERSION
@@ -146,6 +151,7 @@ target "static-builder-musl" {
146151
"org.opencontainers.image.created" = "${timestamp()}"
147152
"org.opencontainers.image.version" = VERSION
148153
"org.opencontainers.image.revision" = SHA
154+
"dev.frankenphp.base.fingerprint" = BASE_FINGERPRINT
149155
}
150156
args = {
151157
FRANKENPHP_VERSION = VERSION
@@ -171,6 +177,7 @@ target "static-builder-gnu" {
171177
"org.opencontainers.image.created" = "${timestamp()}"
172178
"org.opencontainers.image.version" = VERSION
173179
"org.opencontainers.image.revision" = SHA
180+
"dev.frankenphp.base.fingerprint" = BASE_FINGERPRINT
174181
}
175182
args = {
176183
FRANKENPHP_VERSION = VERSION

scripts/ci/compute-fingerprint.sh

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
write_output() {
5+
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
6+
echo "$1" >> "${GITHUB_OUTPUT}"
7+
else
8+
echo "$1"
9+
fi
10+
}
11+
12+
get_php_version() {
13+
local version="$1"
14+
skopeo inspect "docker://docker.io/library/php:${version}" \
15+
--override-os linux \
16+
--override-arch amd64 |
17+
jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")'
18+
}
19+
20+
PHP_82_LATEST="$(get_php_version 8.2)"
21+
PHP_83_LATEST="$(get_php_version 8.3)"
22+
PHP_84_LATEST="$(get_php_version 8.4)"
23+
PHP_85_LATEST="$(get_php_version 8.5)"
24+
25+
PHP_VERSION="${PHP_82_LATEST},${PHP_83_LATEST},${PHP_84_LATEST},${PHP_85_LATEST}"
26+
write_output "php_version=${PHP_VERSION}"
27+
write_output "php82_version=${PHP_82_LATEST//./-}"
28+
write_output "php83_version=${PHP_83_LATEST//./-}"
29+
write_output "php84_version=${PHP_84_LATEST//./-}"
30+
write_output "php85_version=${PHP_85_LATEST//./-}"
31+
32+
if [[ "${GITHUB_EVENT_NAME:-}" == "schedule" ]]; then
33+
FRANKENPHP_LATEST_TAG="$(gh release view --repo php/frankenphp --json tagName --jq '.tagName')"
34+
git checkout "${FRANKENPHP_LATEST_TAG}"
35+
fi
36+
37+
METADATA="$(PHP_VERSION="${PHP_VERSION}" docker buildx bake --print | jq -c)"
38+
39+
BASE_IMAGES=()
40+
while IFS= read -r image; do
41+
BASE_IMAGES+=("${image}")
42+
done < <(jq -r '
43+
.target[]?.contexts? | to_entries[]?
44+
| select(.value | startswith("docker-image://"))
45+
| .value
46+
| sub("^docker-image://"; "")
47+
' <<< "${METADATA}" | sort -u)
48+
49+
BASE_IMAGE_DIGESTS=()
50+
for image in "${BASE_IMAGES[@]}"; do
51+
if [[ "${image}" == */* ]]; then
52+
ref="docker://docker.io/${image}"
53+
else
54+
ref="docker://docker.io/library/${image}"
55+
fi
56+
digest="$(skopeo inspect "${ref}" \
57+
--override-os linux \
58+
--override-arch amd64 \
59+
--format '{{.Digest}}')"
60+
BASE_IMAGE_DIGESTS+=("${image}@${digest}")
61+
done
62+
63+
BASE_FINGERPRINT="$(printf '%s\n' "${BASE_IMAGE_DIGESTS[@]}" | sort | sha256sum | awk '{print $1}')"
64+
write_output "base_fingerprint=${BASE_FINGERPRINT}"
65+
66+
if [[ "${GITHUB_EVENT_NAME:-}" != "schedule" ]]; then
67+
write_output "skip=false"
68+
exit 0
69+
fi
70+
71+
FRANKENPHP_LATEST_TAG_NO_PREFIX="${FRANKENPHP_LATEST_TAG#v}"
72+
EXISTING_FINGERPRINT=$(
73+
skopeo inspect "docker://docker.io/dunglas/frankenphp:${FRANKENPHP_LATEST_TAG_NO_PREFIX}" \
74+
--override-os linux \
75+
--override-arch amd64 |
76+
jq -r '.Labels["dev.frankenphp.base.fingerprint"] // empty'
77+
)
78+
79+
if [[ -n "${EXISTING_FINGERPRINT}" ]] && [[ "${EXISTING_FINGERPRINT}" == "${BASE_FINGERPRINT}" ]]; then
80+
write_output "skip=true"
81+
exit 0
82+
fi
83+
84+
write_output "ref=${FRANKENPHP_LATEST_TAG}"
85+
write_output "skip=false"

scripts/ci/verify_image_tags.sh

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
PHP_VERSION="${PHP_VERSION:-}"
5+
GO_VERSION="${GO_VERSION:-}"
6+
USE_LATEST_PHP="${USE_LATEST_PHP:-0}"
7+
8+
if [[ -z "${GO_VERSION}" ]]; then
9+
GO_VERSION="$(awk -F'"' '/variable "GO_VERSION"/ {f=1} f && /default/ {print $2; exit}' docker-bake.hcl)"
10+
GO_VERSION="${GO_VERSION:-1.25}"
11+
fi
12+
13+
if [[ -z "${PHP_VERSION}" ]]; then
14+
PHP_VERSION="$(awk -F'"' '/variable "PHP_VERSION"/ {f=1} f && /default/ {print $2; exit}' docker-bake.hcl)"
15+
PHP_VERSION="${PHP_VERSION:-8.2,8.3,8.4,8.5}"
16+
fi
17+
18+
if [[ "${USE_LATEST_PHP}" == "1" ]]; then
19+
PHP_82_LATEST=$(skopeo inspect docker://docker.io/library/php:8.2 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
20+
PHP_83_LATEST=$(skopeo inspect docker://docker.io/library/php:8.3 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
21+
PHP_84_LATEST=$(skopeo inspect docker://docker.io/library/php:8.4 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
22+
PHP_85_LATEST=$(skopeo inspect docker://docker.io/library/php:8.5 --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")')
23+
PHP_VERSION="${PHP_82_LATEST},${PHP_83_LATEST},${PHP_84_LATEST},${PHP_85_LATEST}"
24+
fi
25+
26+
OS_LIST=()
27+
while IFS= read -r os; do
28+
OS_LIST+=("${os}")
29+
done < <(python3 - <<'PY'
30+
import re
31+
32+
with open("docker-bake.hcl", "r", encoding="utf-8") as f:
33+
data = f.read()
34+
35+
# Find the first "os = [ ... ]" block and extract quoted values
36+
m = re.search(r'os\s*=\s*\[(.*?)\]', data, re.S)
37+
if not m:
38+
raise SystemExit(1)
39+
40+
vals = re.findall(r'"([^"]+)"', m.group(1))
41+
for v in vals:
42+
print(v)
43+
PY
44+
)
45+
46+
IFS=',' read -r -a PHP_VERSIONS <<< "${PHP_VERSION}"
47+
48+
BASE_IMAGES=()
49+
for os in "${OS_LIST[@]}"; do
50+
BASE_IMAGES+=("golang:${GO_VERSION}-${os}")
51+
for pv in "${PHP_VERSIONS[@]}"; do
52+
BASE_IMAGES+=("php:${pv}-zts-${os}")
53+
done
54+
done
55+
56+
BASE_IMAGES=($(printf '%s\n' "${BASE_IMAGES[@]}" | sort -u))
57+
58+
BASE_IMAGE_DIGESTS=()
59+
for image in "${BASE_IMAGES[@]}"; do
60+
if [[ "${image}" == */* ]]; then
61+
ref="docker://docker.io/${image}"
62+
else
63+
ref="docker://docker.io/library/${image}"
64+
fi
65+
digest="$(skopeo inspect "${ref}" --override-os linux --override-arch amd64 --format '{{.Digest}}')"
66+
BASE_IMAGE_DIGESTS+=("${image}@${digest}")
67+
done
68+
69+
hash_cmd="sha256sum"
70+
if ! command -v "${hash_cmd}" >/dev/null 2>&1; then
71+
hash_cmd="shasum -a 256"
72+
fi
73+
74+
fingerprint="$(printf '%s\n' "${BASE_IMAGE_DIGESTS[@]}" | sort | ${hash_cmd} | awk '{print $1}')"
75+
76+
echo "PHP_VERSION=${PHP_VERSION}"
77+
echo "GO_VERSION=${GO_VERSION}"
78+
echo "OS_LIST=${OS_LIST[*]}"
79+
echo "Base images:"
80+
printf ' %s\n' "${BASE_IMAGES[@]}"
81+
echo "Fingerprint: ${fingerprint}"

0 commit comments

Comments
 (0)