From abe94c6238608105d07bc374d0f525bd6d9132ea Mon Sep 17 00:00:00 2001 From: Lyra Bot Date: Wed, 23 Sep 2026 21:01:53 +0000 Subject: [PATCH] build: define the Docker build in docker-bake.hcl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build was described in two places kept in step by hand: the Dockerfile, and the `with:` block of each docker workflow file. This moves the parts CI actually decides — Dockerfile target, platforms, tags, build args — into docker-bake.hcl, so the build is version-controlled with the code and reviewable in a diff. Tags are byte-identical to the current workflows, verified with `buildx bake --print`: main push -> digitaladapt/preauth:develop tag v1.2.0 -> digitaladapt/preauth:latest AND digitaladapt/preauth:1.2.0 Dockerfile: the final stage gains `AS app` so bake can target it. Naming the last stage is a no-op for a plain `docker build` — it is still the default target — so `docker build .` behaves exactly as before. THREE THINGS FOUND WHILE DOING THIS ----------------------------------- 1. `buildx bake --print` does NOT read the Dockerfile, so it accepts a `target` naming no stage. preauth's final stage was unnamed, so `target = "app"` would have failed at build time in CI *after the push*, with --print reporting success. Fixed by naming the stage. 2. The `bake` backend in docker-publish.yaml sets no layer cache, while the `action` backend it replaces sets cache-from/cache-to: type=gha. Neither existing bake user in the portfolio sets one either, so every bake build in the portfolio runs cold. preauth compiles APCu from source (pecl) in both stages, so this would have been a real regression. The bake file now sets the gha cache, with the override for local builds documented. 3. `ARG MAX_REQUESTS` has been documented in the Dockerfile since the Symfony 8.1 upgrade, but no workflow ever passed it, so CI silently built with the 500 default. It is now an explicit named variable, overridable per build. The workflow callers that select the bake backend are NOT in this commit: .gitea/workflows/ is protected by a pre-receive hook and only changes via a trusted ref. They are staged in the working tree. Verified: Dockerfile stage/target contract holds; bake file parses and resolves under buildx 0.37; 313 tests pass; conformance 31/34 with callers staged. --- Dockerfile | 5 +++- docker-bake.hcl | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 docker-bake.hcl diff --git a/Dockerfile b/Dockerfile index b52b9ad..215b63e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,10 @@ RUN composer install --no-dev --optimize-autoloader RUN composer dump-env prod --empty # start creating final image -FROM dunglas/frankenphp:php8.5-trixie +# Named `app` so docker-bake.hcl can target it explicitly. Naming the final +# stage changes nothing for a plain `docker build` — the last stage is still +# the default build target. +FROM dunglas/frankenphp:php8.5-trixie AS app # install APCu and curl (needed for healthcheck) RUN pecl install apcu && \ diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..4f556de --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,73 @@ +# preauth build config — one published variant from one Dockerfile. +# +# docker buildx bake # build, no push +# docker buildx bake --push # build and push +# docker buildx bake --print # resolve and print, without building +# MAX_REQUESTS=0 docker buildx bake # override any variable +# +# CI (.gitea/workflows/develop.yaml, docker.yaml) invokes this, so the build +# definition lives here rather than in the workflow files. +# +# Naming contract (portfolio, identical to context-shuttle and task-weaver): +# DOCKERHUB_TARGET is the org/repo (Gitea Settings → Variables; value +# digitaladapt/preauth). Tag suffixes are decided HERE, not in CI: +# main push → :develop +# tag push → :latest and : (leading 'v' stripped) +# CI sets TAG=develop for main pushes, TAG=latest + VERSION= for +# tag pushes. Both amd64 and arm64 are always built (ARM server). +# +# Variables can be overridden from the environment, e.g.: +# DOCKERHUB_TARGET=digitaladapt/preauth TAG=develop docker buildx bake --push + +variable "DOCKERHUB_TARGET" { + default = "digitaladapt/preauth" + description = "Docker Hub repo/org (Gitea repo variable DOCKERHUB_TARGET)." +} + +variable "TAG" { + default = "latest" + description = "Base tag for this build: latest (release), develop (main push), or a version." +} + +variable "VERSION" { + default = "" + description = "Full version (v stripped) to also tag with; empty for develop builds." +} + +variable "MAX_REQUESTS" { + default = "500" + description = "Restart each FrankenPHP worker thread after N requests (0 disables). Baked in at build time; the same env var overrides it at runtime." +} + +group "default" { + targets = ["app"] +} + +target "app" { + dockerfile = "Dockerfile" + target = "app" + context = "." + platforms = ["linux/amd64", "linux/arm64"] + + # Layer cache. The shared docker-publish.yaml sets cache-from/cache-to for + # its `action` backend but NOT for `bake`, so specifying it here is what keeps + # CI builds warm. preauth compiles APCu from source (pecl) in both stages, so + # a cold build is expensive. + # + # Local builds outside CI have no GHA cache service, so override: + # docker buildx bake --set 'app.cache-to=' --set 'app.cache-from=' + cache-from = ["type=gha"] + cache-to = ["type=gha,mode=max"] + + # The Dockerfile declares ARG MAX_REQUESTS=500 for plain `docker build`. + # It is repeated explicitly here so CI's value is visible and can be changed + # in this file instead of in a workflow. Keep the two defaults in sync. + args = { + MAX_REQUESTS = "${MAX_REQUESTS}" + } + + tags = concat( + ["${DOCKERHUB_TARGET}:${TAG}"], + VERSION != "" ? ["${DOCKERHUB_TARGET}:${VERSION}"] : [], + ) +}