Repository navigation
feat: shared CI workflows, release automation, Renovate presets and org defaults - #1
Merged
Merged
Conversation
…linting Adds docker-image.yml, pr-image-cleanup.yml, pr-title-lint.yml and actionlint.yml as reusable workflows (consumed via @v1), plus CI that runs actionlint on this repository's own workflows. Refs Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add renovate/default (base for every repo), renovate/node and renovate/docker add-on presets, derived from the configs the repos already share, plus docs on extending them and how repo settings merge with the presets. Refs Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… deleting The usual cause of leaked pr-<n> images is a PR build that is still running when the PR is merged and pushes the tag after the cleanup. Refs Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub keeps only one pending run per concurrency group, so a group per package could cancel cleanups while one run waits for PR builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Combines the shared Renovate presets (formerly #2) into the single consolidated PR for Aam-Digital/internal#392. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- native-runners: build each platform on a native runner (linux/amd64 on ubuntu-latest, linux/arm64 on ubuntu-24.04-arm), push by digest and merge the multi-platform image with all tags in a merge job - cleanup-replaced (default on): after the push, delete the ghcr.io image a tag pointed to before if no tag is left on it, with its platform and attestation manifests unless another tagged image still uses them; in native mode also the merged per-platform pushes. Failures only warn. Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pull_request_target Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… prereleases type release: full release from the default branch, after deleting the *-<prerelease-id>.* and *-master.* prereleases and tags. type prerelease: <next version>-<prerelease-id>.<n>, computed by a semantic-release dry run (semantic-release cannot use the default branch alone as prerelease branch) and created as GitHub prerelease with the PAT. Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wildcard tag patterns (default *-edge.*,*-master.*) via ghcr-cleanup-action; images that carry an excluded tag (edge, master, stable, latest) are never deleted or untagged, untagged versions are never touched. Also log "still tagged" before "still used" when docker-image keeps a replaced image. Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generalised from the aam-services issue templates (org issue types instead of labels) and ndb-core's security policy and contribution guide, in wording that also fits private repositories. Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leanup and the release model Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rerelease frequency Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e runners Part of Aam-Digital/internal#392 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 13, 2026
…tatic native job name, permissions in examples
- release.yml: job-level if on the default branch, concurrency group per ref
and type, so a no-op run of another branch cannot replace a pending release
- docker-image.yml: static job name build-native; skipped jobs no longer show
the unexpanded matrix expression, native runs keep build-native (<platform>)
- README: all caller examples set top-level permissions: {} (checkov CKV2_GHA_1)
Part of Aam-Digital/internal#392
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…it secrets Passed to build-push-action in the default and the native builds, masked in the logs, a no-op when unset. Tested with a probe secret in both modes. Part of Aam-Digital/internal#392 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
sleidig
commented
Oct 16, 2026
sleidig
commented
Oct 16, 2026
sleidig
commented
Oct 16, 2026
Co-authored-by: Sebastian <sebastian@aam-digital.com>
sleidig
commented
Oct 16, 2026
sleidig
commented
Oct 16, 2026
…ep in pr-image-cleanup docker-image.yml no longer deletes the images a push replaces (input `cleanup-replaced`, about 230 lines of registry and package API bash). Instead, pr-image-cleanup.yml now also deletes the untagged images of the package that are older than `untagged-older-than` (default 2 days), using ghcr-cleanup-action, which never deletes children of tagged images. This covers earlier PR pushes, moving branch tags such as `main`, the per-platform pushes of native-runner builds, and images left behind by overlapping pushes, which the old step missed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h Renovate - ci.yml moves the major tag (`MAJOR_TAG: v1`) to every new commit on main once actionlint passes, so there are no manual v1.x.y releases. For a breaking change, set MAJOR_TAG to v2 in the same PR. - renovate.json extends the org preset for the github-actions manager, so the actions used by the shared workflows get updated and reach every repository through the moving v1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/ndb-core
that referenced
this pull request
Oct 16, 2026
The shared docker-image workflow no longer deletes replaced images itself; pr-image-cleanup now deletes untagged images older than 2 days (Aam-Digital/.github#1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/aam-services
that referenced
this pull request
Oct 16, 2026
The shared docker-image workflow no longer deletes replaced images itself; pr-image-cleanup now deletes untagged images older than 2 days (Aam-Digital/.github#1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The input, secret and output tables duplicated the workflow_call descriptions in each file, and the rationale paragraphs duplicated the comments there. The README now has one table (purpose, trigger, permissions, check name), one generic caller snippet with the rules that trip callers up, links to two complete callers, and short sections on the release model and v1. The ndb-core-specific Renovate note moves to ndb-core's renovate.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/ndb-core
that referenced
this pull request
Oct 16, 2026
Moved here from the shared preset's README (Aam-Digital/.github#1), since it only concerns this repo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… for full releases only Every push to the default branch is built as an edge version: the last full release with the patch number bumped, plus the commits since (1.4.1-edge.5). edge-version.yml computes it from git and says whether the commit is still the head of the default branch (only then may the build move `edge`). No semantic-release dry run, no tag, no GitHub release. release.yml loses `type`, `prerelease-id` and `cleanup-prereleases` and only creates full releases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/ndb-core
that referenced
this pull request
Oct 16, 2026
…prereleases Uses the shared edge-version workflow (Aam-Digital/.github#1): version <last release, patch + 1>-edge.<commits since>, tagged `edge` too while it is the newest commit. Edge images of a finished cycle are pruned after the next full release. The shared release workflow no longer takes `type`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/replication-backend
that referenced
this pull request
Oct 16, 2026
…prereleases Uses the shared edge-version workflow (Aam-Digital/.github#1): version <last release, patch + 1>-edge.<commits since>, tagged `edge` too while it is the newest commit. Edge images of a finished cycle are pruned after the next full release. The shared release workflow no longer takes `type`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/platform-admin-services
that referenced
this pull request
Oct 16, 2026
…prereleases Uses the shared edge-version workflow (Aam-Digital/.github#1): version <last release, patch + 1>-edge.<commits since>, tagged `edge` too while it is the newest commit. Edge images of a finished cycle are pruned after the next full release. The shared release workflow no longer takes `type`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/aam-services
that referenced
this pull request
Oct 16, 2026
…prereleases Uses the shared edge-version workflow (Aam-Digital/.github#1): version <last release, patch + 1>-edge.<commits since>, tagged `edge` too while it is the newest commit. Edge images of a finished cycle are pruned after the next full release. The shared release workflow no longer takes `type`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
commented
Oct 20, 2026
sleidig
commented
Oct 20, 2026
sleidig
commented
Oct 20, 2026
sleidig
commented
Oct 20, 2026
sleidig
commented
Oct 20, 2026
sleidig
left a comment
Member
Author
There was a problem hiding this comment.
Seems good but let's check one more time if any actions can reuse code or be simplified in any way
…e no git tag (but an image tag) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and version label - Every platform is built on a native runner (`build (<platform>)`, then `merge`); the QEMU mode and the `native-runners` input are removed. Check names are now `<job> / build (<platform>)` and `<job> / merge`. - Log in to ghcr.io whenever pushing and to Docker Hub when DOCKERHUB_USERNAME is set, instead of parsing the registry hosts of the image names. - The `org.opencontainers.image.version` label is left to docker/metadata-action (first tag = the version). - No separate masking step for BUILD_SECRETS (the secrets passed in are already masked). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-cleanup.yml One workflow deletes the `pr-<n>` image when a PR closes (default) or the given tag patterns (e.g. `*-edge.*` after a release), then the untagged images older than 2 days, now also after releases. `exclude-tags` defaults to `edge,main,master,stable,latest`. Callers grant `actions: write` and `packages: write`; check name `<job> / cleanup`. (The two old files were already removed in the previous commit.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-prefixed release tags All repositories now tag releases without `v`; a remaining `v` tag (e.g. the last release before a switch) no longer leaks into the edge version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/ndb-core
that referenced
this pull request
Oct 20, 2026
Aam-Digital/.github#1 is merged and tagged `v1`; its branch is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/replication-backend
that referenced
this pull request
Oct 20, 2026
Aam-Digital/.github#1 is merged and tagged `v1`; its branch is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/aam-services
that referenced
this pull request
Oct 20, 2026
Aam-Digital/.github#1 is merged and tagged `v1`; its branch is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sleidig
added a commit
to Aam-Digital/platform-admin-services
that referenced
this pull request
Oct 20, 2026
Aam-Digital/.github#1 is merged and tagged `v1`; its branch is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Part of Aam-Digital/internal#392. This is the single consolidated PR for
Aam-Digital/.github. It now also contains the Renovate presets from #2, which is closed in favour of this PR.What
Reusable workflows (
.github/workflows/, details in.github/workflows/README.md)docker-image.yml<job> / build (linux/amd64),<job> / build (linux/arm64),<job> / mergecontents: read,packages: writeedge-version.yml1.4.1-edge.5), and whether the commit is still the head<job> / versioncontents: readrelease.yml<job> / releasecontents: read(writes use thetokenPAT)image-cleanup.ymlpr-<n>image when the PR closes, or the edge images (tags: "*-edge.*") after a full release; then untagged images older than 2 days<job> / cleanupactions: write,packages: writepr-title-lint.yml<job> / Validate PR titlepull-requests: readactionlint.yml<job> / actionlintcontents: readdocker-image.ymlbuilds every platform on a native runner (ubuntu-latest/ubuntu-24.04-arm, no QEMU): one jobbuild (<platform>)per platform pushes by digest, then amergejob creates the multi-arch image with all tags (skipped withpush: false). It logs in to ghcr.io whenever it pushes, and to Docker Hub whenDOCKERHUB_USERNAMEis set. docker/metadata-action sets theorg.opencontainers.image.versionlabel from the first tag (the version, or e.g.pr-123).It deletes nothing itself. An image whose last tag moves to a newer push (an earlier
pr-<n>push, the previous image of a branch tag likemain) stays in the package untagged until the next run ofimage-cleanup.yml(below). Movingedge/latest/stableleaves the previous image tagged with its version.Steps shared between the jobs use YAML anchors.
edge-version.ymlcomputes the version of an edge build from git: the last full release with the patch number bumped, plus the commits since (1.4.1-edge.5). Its outputis-headsays whether the commit is still the head of the default branch; only then does the caller add theedgetag. Inputs:tag-prefix(e.g.aam-backend-service/),identifier(defaultedge). The version is always plain, also after av-prefixed release tag (all repos release withoutvnow).release.ymlcreates full releases only. It takesextra-plugins,node-version-file, the secretstoken(required PAT) andslack-webhook, and has the outputsversionandpublished. It overrides onlybranches(the caller's default branch); the plugin config stays in the repo.image-cleanup.ymldeletes the giventags(defaultpr-<n>of the closed PR; wildcards such as*-edge.*allowed, a bare*is rejected) withdataaxiom/ghcr-cleanup-action, after cancelling and awaiting unfinished PR builds (build-workflows). Images carrying one ofexclude-tags(defaultedge,main,master,stable,latest) are neither deleted nor untagged. Then it deletes all untagged images of the package older thanuntagged-older-than(default2 days, empty to skip) as a best-effort step, after PR closes and releases alike. ghcr-cleanup-action never deletes children of tagged images (reference-counted), and the age limit protects builds in progress. This replaces an earliercleanup-replacedstep indocker-image.yml(about 230 lines of bash) and the former separateimage-prune.yml/pr-image-cleanup.yml.Renovate presets (
renovate/default,renovate/node,renovate/docker, from #2, unchanged; seerenovate/README.md.)Updates and versioning of this repo:
renovate.jsonextendsrenovate/defaultfor thegithub-actionsmanager, so the actions inside the shared workflows (SHA pins and majors) get updated too.ci.ymlmoves thev1tag to every new commit onmainonceactionlint / actionlintpasses (jobmove-major-tag; it createsv1on the first run). There are nov1.x.yreleases: a merged PR, Renovate's included, reaches every repository on its next run. A breaking change setsMAJOR_TAG: v2inci.ymlin the same PR, sov1stays where it is.Org-wide community health defaults:
.github/ISSUE_TEMPLATE/: bug report, feature request, technical task. They are generalized from aam-services and set the org issue types (Bug,New Feature,Task) instead of repo-specific labels.SECURITY.mdandCONTRIBUTING.md, generalized from ndb-core. The wording is neutral, so it also fits private repos. There is no org PR template.Docs:
v1moves. Inputs are documented in each workflow file.renovate/README.md.# zizmor: ignore[dangerous-triggers]comment with its reason (qlty's cloud defaults block on it otherwise).Edge builds instead of prereleases
The issue planned semantic-release prereleases (
branches: [{name: <default>, prerelease: edge}]). semantic-release rejects a lone prerelease branch (ERELEASEBRANCHES), and the workaround (a dry run plus tags and GitHub prereleases created by the workflow) was complex. Prereleases also filled the GitHub releases list: 22 of the first 30 entries of ndb-core's list are prereleases, and both the app's "latest changes" and ndb-setup'screate-instance.shonly read that first page.Instead, every push to the default branch is an edge build with no tag and no GitHub release:
edge-version.yml(see above), e.g.3.93.1-edge.39. It sorts above the last release and below the next one.<version>, plusedgewhile the commit is the head. The caller's image job uses aconcurrencygroup withcancel-in-progress: true, so an older run can't moveedgeback.image-cleanup.yml(tags: "*-edge.*") deletes the edge images of the finished cycle.Testing
ghcr.io/aam-digital/ci-test(package, caches and test branch deleted afterwards): the former QEMU mode, native runners (amd64 + arm64) →merge, and movingedgewhile the old image keeps its version tag. (These runs also tested the formercleanup-replacedstep, which is removed now.)build (linux/amd64)→merge. ndb-core's run logged in to Docker Hub and ghcr.io and createdpr-4507in both registries; on ghcr.io itsorg.opencontainers.image.versionlabel ispr-4507(from metadata-action), while replication-backend's own label override0.0.0-pr.381is kept. Consumer workflows linted with actionlint against the shared workflows resolved locally.image-prune.yml), with*-test.*and excludeedge: the old prerelease image and its children were deleted. The image taggededge+0.0.2-test…kept both tags. The dry run deleted nothing.3.93.1-edge.39, with the old-master.*tags ignored), replication-backend (1.15.6-edge.0), platform-admin-services (thenv1.7.5-edge.0; thevis dropped now) and aam-services (2.3.2-edge.0withtag-prefix: aam-backend-service/).docker-image.ymlwith two platforms (an arm64 leg plusmergeof two digests, and for ndb-core two digests × two registries) since the rework: first exercised by each consumer's first edge build on its default branch, and by keycloak-aam's next release (private repo, arm64 runner);release.yml(a real release) andedge-version.yml'sis-headcheck (both only run on the default branch);image-cleanup.yml(it only runs when a PR closes or after a release). Its child handling was checked in the action's source (image-deleter.ts: a shared child is only deleted with its last parent). Check the first PR-close run after merging.After merging
See the rollout checklist in Aam-Digital/internal#392:
feat/reusable-workflowsis deleted on merge and no consumer keeps running it unnoticed.move-major-tagcreatedv1, then set up the ruleset withactionlint / actionlint.@feat/reusable-workflowsto@v1before merging them.🤖 Generated with Claude Code