feat(ci): render Docker Hub readme from versions.yml at build time#715
Merged
kojiromike merged 1 commit intoMay 13, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Automates Docker Hub README updates for openemr/openemr by rendering a deterministic Markdown document from tools/release/versions.yml at build time, replacing the prior manual-edit + standalone workflow approach.
Changes:
- Add a Twig-based README template and a PHP renderer + CLI/Taskfile entry to render from
versions.yml. - Add a composite GitHub Action to render and push the Docker Hub description via
peter-evans/dockerhub-description@v5. - Wire the composite action into production build workflows and remove the old
dockerhub-description.ymlworkflow.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/release/versions.yml | Removes the retired OVERVIEW.md mapping entry from the rotation registry. |
| tools/release/templates/dockerhub-overview.md.twig | New Docker Hub README template parameterized by slot scalars. |
| tools/release/src/DockerHubOverviewRenderer.php | New renderer to load versions.yml slots and render the Twig template. |
| tools/release/bin/render-dockerhub-overview.php | New CLI wrapper to render to stdout or a file for CI usage. |
| tools/release/Taskfile.yml | Adds a release:render-dockerhub-overview task (deps: setup). |
| tools/release/tests/DockerHubOverviewRendererTest.php | Adds unit tests for slot interpolation, determinism, and error cases. |
| .github/actions/push-dockerhub-readme/action.yml | New composite action to checkout, render README, and push to Docker Hub. |
| .github/workflows/build-704.yml | Runs the composite action after pushing the legacy 7.0.4 image. |
| .github/workflows/build-800.yml | Runs the composite action after pushing the current production image. |
| .github/workflows/build-810.yml | Runs the composite action after pushing the next-track manifest/tags. |
| .github/workflows/build-811.yml | Runs the composite action after pushing the dev-track manifest/tags. |
| .github/workflows/dockerhub-description.yml | Removes the old workflow that pushed a hand-edited README file. |
Comments suppressed due to low confidence (1)
tools/release/templates/dockerhub-overview.md.twig:21
- The dated-tag example hard-codes
2026-03-25, which will become stale and potentially confusing over time. Consider using a generic placeholder (e.g.{{ current.patch }}-YYYY-MM-DD) or wording that avoids a specific date in the example while still illustrating the format.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This was referenced May 12, 2026
kojiromike
added a commit
that referenced
this pull request
May 12, 2026
) Refs #714 #### Short description of what this resolves: Adds a `workflow_dispatch` workflow that proves `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` are valid for the readme-push API path, without triggering an image build or modifying the readme content. Whoever rotates the secret in the future (per #714) can click "Run workflow" and know in seconds whether the new credential works. #### Why two checks A Docker Hub token can pass `docker login` (registry auth) and still fail on `PATCH /v2/repositories/openemr/openemr/` (API auth), because the API path needs Read+Write+Delete scope on the specific repo while the registry only requires push permission. That is exactly the failure mode #714 had to recover from — the `Update Docker Hub Description` workflow was 403'ing while image pushes kept working. #### Side effect to be aware of The API check writes the current description back to itself via a no-op `PATCH` so it actually exercises the write scope (a read-only token would 200 on a `GET` and 403 on the `PATCH`). The readme content does not change, but Docker Hub's `last_modified` timestamp on the repo is bumped. The real readme push already does this on every run, so nothing novel. #### Changes proposed in this pull request: - New `.github/workflows/dockerhub-credential-check.yml` — `workflow_dispatch` only. Steps: checkout → `docker/login-action` (validates registry auth) → setup PHP + Task → `task ci:check-dockerhub-credential` (validates the API-path auth via login + GET + no-op PATCH). - New PHP tooling under `tools/release/` matching the existing pattern (cf. `bin/render-dockerhub-overview.php` in #715): - `src/DockerHubCredentialChecker.php` — orchestrates `POST /v2/users/login/`, `GET /v2/repositories/<repo>/`, then no-op `PATCH /v2/repositories/<repo>/` via `ext-curl`. Catches `JsonException` internally and `RuntimeException` from the HTTP layer so the workflow always emits exactly one diagnostic line. - `src/DockerHubCredentialCheckResult.php` — pure result interpretation; the testable surface, no HTTP mocking required. Maps 401/403 to credential/scope failures and other non-200s to `UNEXPECTED_RESPONSE` with the actual HTTP status surfaced. - `src/DockerHubCredentialCheckStatus.php` — `OK` / `INVALID_CREDENTIAL` / `INSUFFICIENT_SCOPE` / `UNEXPECTED_RESPONSE` / `NETWORK_ERROR` enum. - `bin/check-dockerhub-credential.php` — Symfony Console one-shot. - `tests/DockerHubCredentialCheckResultTest.php` — covers every status / step-failure path (16 cases). - New Taskfile entry `ci:check-dockerhub-credential`. - `ext-curl` added to `composer.json` requires (declared explicitly so `composer-require-checker` stays clean). #### Test plan - `composer check` clean (phpcs, phpstan, rector dry-run, require-checker, 93 phpunit tests). - `actionlint` clean. - After merge: trigger from the Actions tab; with the currently-revoked token, expect a clear `::error::` line distinguishing "invalid credential" (HTTP 401/403 from `/users/login/`) from "lacks scope" (login OK but 403 from the repo endpoint). After #714 lands and the secret is rotated, re-trigger and expect a `::notice::` "Credential is valid" line and a green check.
Open
5 tasks
e8e7018 to
87c4626
Compare
The Docker Hub readme update for openemr/openemr was previously triggered by edits to docker/openemr/OVERVIEW.md, which release runbook step 15 required maintainers to update by hand. The peter-evans/dockerhub-description workflow then propagated the file. This left the readme out of sync whenever the manual edit was forgotten and was the sole reason a maintainer had to touch a markdown file as part of the release runbook. Replace the hand-edited file with a Twig template (tools/release/templates/dockerhub-overview.md.twig) rendered from tools/release/versions.yml — the same registry that already drives slot rotation for build workflows and Dockerfiles. A new composite action (.github/actions/push-dockerhub-readme) renders the template and pushes to the Docker Hub API. Each production build workflow (build-704, build-800, build-810, build-811) calls it after a successful image push. Render is deterministic from versions.yml so the same-day race between nightly cron builds is benign — last writer wins with identical content. Drop the per-build dated tags (e.g. 8.0.0.3-2026-03-25) from the readme. Each build still pushes the immutable dated tag for pinning; users who want a specific build find it on the Docker Hub Tags page or via docker inspect. The readme now explains the scheme in one sentence instead of mirroring listings Docker Hub already displays natively. Closes openemr#709. Assisted-by: Claude Code
87c4626 to
ad5d8d8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #709
Short description of what this resolves:
Step 15 of the release runbook — updating the Docker Hub readme on https://hub.docker.com/r/openemr/openemr — was manual: maintainers edited
docker/openemr/OVERVIEW.mdby hand, then a workflow propagated it to Docker Hub. This PR removes that manual step. The readme is now rendered fromtools/release/versions.yml(the same registry the slot rotation workflow already uses) and pushed by each production build workflow after a successful image push.Changes proposed in this pull request:
tools/release/templates/dockerhub-overview.md.twig(renamed fromdocker/openemr/OVERVIEW.md, with version-dependent values parameterized on slot scalars).OpenEMR\Release\DockerHubOverviewRenderer(tools/release/src/) with a thin Symfony Console wrapper attools/release/bin/render-dockerhub-overview.phpand arelease:render-dockerhub-overviewTask entry. Unit tests cover slot interpolation, determinism, and error paths..github/actions/push-dockerhub-readmethat checks out, renders, then callspeter-evans/dockerhub-description@v5.build-704,build-800,build-810,build-811call the composite action as their final step (last-writer-wins is benign because renders are deterministic)..github/workflows/dockerhub-description.ymland the hand-editeddocker/openemr/OVERVIEW.md. Drop the corresponding entry fromtools/release/versions.yml.8.0.0.3-2026-03-25) from the readme — they're an immutable-naming mechanism for pinning, not date-display, and Docker Hub's Tags page already lists them. Replaced with one sentence explaining the scheme.Notes
Forbiddenon its last two runs. The new push uses the sameDOCKERHUB_USERNAME/DOCKERHUB_TOKENsecrets, so the same fix unblocks both.build-322,build-323,build-edge,build-flex-core) are intentionally not wired up — they aren't in the rotation registry and their portion of the readme is hand-curated. Easy follow-up if/when they join the rotation.openemr/openemrto remove step 15 fromdocs/RELEASE_PROCESS.md's release runbook.Test plan
composer checkclean intools/release/(phpcs, phpstan, rector dry-run, require-checker, phpunit — 83 tests).actionlintclean on the four modified build workflows.versions.ymlproduces the expected markdown.build-800.ymlfrom a topic branch and confirm the Docker Hub readme reflects the rendered output.