Skip to content

[TASK] Add a generated tag anatomy banner to the README - #601

Merged
Kanti merged 9 commits into
webdevops:masterfrom
andersundsehr:ccr-be775e89-f8phpz
Nov 9, 2026
Merged

Kanti merged 9 commits into
webdevops:masterfrom
andersundsehr:ccr-be775e89-f8phpz

Conversation

@Kanti

@Kanti Kanti commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator
How an image tag is built: web server, variant, PHP version and base OS, with all options of each part

The README lists 48 tags in two long lists. This adds a banner at the top that explains how a tag is built instead: it takes webdevops/php-nginx-dev:8.5-alpine apart into web server, variant, PHP version and base OS and shows every option of each part. GitHub shows the light or the dark version depending on the reader's theme.

The banner is generated, so it stays current without manual work:

  • ci/console readme-banner:generate renders docs/assets/readme-banner-light.svg and -dark.svg from the Dockerfiles, read through FileReader. ci/console github:generate-ci is unchanged.
  • PHP versions, web servers, the -dev variant, the -alpine suffix and the Debian release (from the base image of webdevops/php, e.g. bookworm in php:8.5-fpm-bookworm) come from the Dockerfiles. The platforms come from the build matrix, which now lives in GithubJobBuilder::PLATFORMS. Texts are in conf/readme-banner.yml.
  • A new step in validate-automation runs readme-banner:generate and git diff --exit-code, so a stale banner fails CI.

It is prepared for PHP 8.6 on Debian trixie while the older versions stay on bookworm, with the same tags as today: once the base images differ, BASE OS shows "Debian" with one line per release, e.g. "bookworm: 8.2–8.5" and "trixie: 8.6".

The generator shows every PHP tag or stops with a message that says what to change: for a tag it cannot take apart, a suffix without a text, a base image without a release, a missing setting, a missing font, a file it cannot write or anything that no longer fits.

GitHub does not load web fonts in SVG images, so all text is drawn as outlines. ci/resources/readme-banner/glyphs.json holds outlines, widths and kerning for printable ASCII from Inter and JetBrains Mono (both OFL-1.1). ci/console readme-banner:build-glyphs writes it from the Google Fonts .ttf files; ci/resources/readme-banner/README.md describes how. Neither command needs extra PHP packages.

FileReader now also accepts flags such as --platform in FROM lines and returns the base image.

Documentation

  • README.md: banner at the top with an alt text that does not list tags; "Building in CI" lists readme-banner:generate, what the banner takes from the built images, where its texts are and that the CI fails if it is out of date.
  • AGENTS.md: repository map lists both generators, the banner sources and the generated SVGs; "Keep lists in sync" says the banner follows the built tags.
  • ci/resources/readme-banner/README.md: where the fonts come from, how to rebuild glyphs.json, and that its kerning leaves out glyph substitutions (GSUB).

How I verified it

  • github:generate-ci: build.yaml only gains the new validation step.
  • readme-banner:generate gets the same 48 PHP tags from FileReader as build.yaml pushes (without php-official).
  • Inside webdevops/php:8.4-alpine (PHP 8.4.27), composer install, github:generate-ci and readme-banner:generate leave build.yaml and both SVGs unchanged; two runs give byte-identical files. A changed text in conf/readme-banner.yml makes the new step fail.
  • Rendered both SVGs to PNG and checked them visually in both themes; both are valid XML without <text> elements or external references.
  • readme-banner:build-glyphs writes byte for byte the same glyphs.json as a reference script built on fontTools and HarfBuzz, for three font sets.
  • Simulated inputs: PHP 8.6 on trixie (version chips wrap, example tag becomes 8.6-alpine, release lines appear, height stays), 8.7 also on trixie ("trixie: 8.6–8.7"), releases not in a row, 8.6 without -alpine (example stays 8.5-alpine), and base images with RC or zts tags, a digest, --platform, several stages or a registry port. Each error case above stops with its message, e.g. for php:8.6-fpm, an unknown suffix, the tag 8.5.1, a missing setting or file, a missing font or glyph, a new image without a description and a footer that is too long.

Kanti and others added 9 commits November 9, 2026 09:31
The banner takes webdevops/php-nginx-dev:<newest>-alpine apart into web
server, variant, PHP version and base OS. ci/console github:generate-ci
renders it in a light and a dark version next to build.yaml, from the
images that get a build job, so new or dropped PHP versions, web servers,
the Debian release and the platforms update it without manual work.
Texts live in conf/readme-banner.yml.

Text is drawn as outlines from a glyph table derived from Inter and
JetBrains Mono (OFL-1.1), because GitHub does not load web fonts in SVG
images. The existing validate-automation step regenerates and diffs it,
so a stale banner fails CI.
ci/console readme-banner:build-glyphs replaces build-glyphs.py. It reads
TrueType fonts directly: character map, advance widths, outlines with
their components, and the GPOS kerning a text shaper applies with its
default features. It needs no extra PHP packages.

For the same font files it writes the same glyphs.json as the Python
script did, byte for byte. glyphs.json is now built straight from the
Google Fonts .ttf files, as ci/resources/readme-banner/README.md
describes. The previous table also had overlapping contours merged in a
step that was not part of the script; the banner only differs in the
anti-aliasing where contours overlap.
The BASE OS card now shows every tag suffix after the PHP version that
is built, not only -alpine, in the order of conf/readme-banner.yml. A
suffix without a text there stops the generator. Texts for -trixie and
-bookworm are already in place, so Debian trixie images next to
bookworm show up without further changes, whichever of them gets the
suffix.

{release} in a text is the release in the FROM line of webdevops/php.
It is left out if the PHP versions use different releases, because
there is no room for all of them.

The example tag takes its suffix from the configuration and uses the
newest PHP version that is built with -dev and that suffix.

The banner for the current images stays the same.
PHP 8.6 will be built on Debian trixie while the older versions stay on
bookworm, with the same tags as before. If the FROM lines of
webdevops/php name different releases, the BASE OS card now shows
"Debian" and below it one line per release with its PHP versions, e.g.
"bookworm: 8.2–8.5" and "trixie: 8.6". The format of these lines is in
conf/readme-banner.yml.

The texts for -trixie and -bookworm suffixes are gone again, as there
will be no such tags.

The banner for the current images stays the same.
ci/console readme-banner:generate renders the banner;
github:generate-ci only writes build.yaml again and is unchanged. The
banner command reads the Dockerfiles through FileReader, which yields
the same PHP tags as the build jobs, and takes the platforms from
GithubJobBuilder::PLATFORMS.

validate-automation gets its own step that runs the command and fails
if the banner changes; the step for build.yaml has its old name again.
- A PHP tag the banner cannot take apart, such as 8.5.1, stops the
  generator; any suffix after the PHP version, such as -alpine3.24,
  needs a text in conf/readme-banner.yml instead of being left out.
- The release is read from the image tag of the last FROM line, also
  with --platform, a digest or "AS name".
- glyphs.json must contain every font the banner draws with;
  readme-banner:build-glyphs asks for missing ones before writing.
- A missing setting in conf/readme-banner.yml is named in the error.
- A release that comes back after another one gets one line with all
  its versions, e.g. "bookworm: 8.2, 8.4".
- The example suffix is no longer put into a regular expression, the
  Dockerfiles are read once, font tables are copied once, and unused
  code is gone.
- The alt text of the banner no longer lists web servers or suffixes,
  so it does not go out of date.

The banner for the current images stays the same.
- FileReader returns the image of the last FROM line, also after flags
  such as --platform; the banner reads the release from it instead of
  parsing the Dockerfiles again.
- A base image tag without a release, such as php:8.6-fpm, stops the
  banner instead of showing "fpm" as the release.
- Numeric tag suffixes are no longer lost to integer array keys.
- conf/readme-banner.yml needs exactly one file per theme, and failing
  to write a file stops both readme-banner commands.
- The list of fonts glyphs.json has to contain lives in GlyphFont, so
  the glyph table builder no longer depends on the renderer.
- The README of the glyph table says that the kerning leaves out glyph
  substitutions (GSUB).

The banner and build.yaml stay the same.
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@Kanti
Kanti marked this pull request as ready for review November 9, 2026 12:12
@Kanti
Kanti merged commit 56b22b8 into webdevops:master Nov 9, 2026
177 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant