feat: auto-release images from conventional commits on main
Build and publish container / build (pull_request) Successful in 2m58s

On each push to main, derive the next semantic version from the
conventional-commit messages since the last v* tag (feat -> minor,
fix/perf -> patch, \! or BREAKING CHANGE -> major) and, when a release is
warranted, build and publish the image tagged X.Y.Z, X.Y, X and latest,
then record an annotated vX.Y.Z tag for the next computation. Non-release
pushes publish a sha-<short> image only.

Configure Renovate to commit updates as fix(deps): so each merged Renovate
PR registers as a patch change and is released and tagged automatically.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Emma Thorpe
2026-06-11 17:04:40 +01:00
parent d296d88c4c
commit 99084cc597
3 changed files with 122 additions and 33 deletions
+27 -8
View File
@@ -45,9 +45,8 @@ docker run --rm -p 8080:8080 dlr
## CI
`.gitea/workflows/build-and-publish.yml` builds the container with Gitea Actions
and publishes it to this Gitea instance's container registry on pushes to `main`
and on `v*` tags. Pull requests build the image but do not push. The registry
host is derived from the Gitea server URL.
on every push to `main` and on pull requests. Pull requests build the image but
do not push. The registry host is derived from the Gitea server URL.
Authentication requires a Personal Access Token with package read/write scope,
because the automatically provided `GITEA_TOKEN` does not carry container
@@ -55,11 +54,27 @@ registry write permission on most Gitea instances. Create the token under an
account with write access to the target package namespace, then store it as a
repository Actions secret named `PACKAGES_TOKEN`.
The published image is `<gitea-host>/<owner>/<repo>`. Pushing a `v*` git tag
produces semantic-version tags (`{{version}}`, `{{major}}.{{minor}}`,
`{{major}}`), and `latest` is moved to that build when it is not a pre-release.
Non-release builds on `main` are tagged by branch name and commit SHA only, so
`latest` always points at the most recent release rather than the newest commit.
### Automatic releases
The published image is `<gitea-host>/<owner>/<repo>`. Releases are derived from
[Conventional Commits](https://www.conventionalcommits.org/). On each push to
`main`, the workflow inspects the commits since the last `v*` tag and computes
the next version:
- `feat:` → minor bump,
- `fix:` / `perf:` → patch bump,
- `!` or `BREAKING CHANGE` → major bump,
- anything else (`chore`, `ci`, `docs`, `build`) → no release.
When a release is warranted, the image is published with `X.Y.Z`, `X.Y`, `X` and
`latest` tags, and the workflow records an annotated `vX.Y.Z` git tag so the next
release is computed from it. Pushes to `main` that warrant no release are
published under a `sha-<short>` tag only, so `latest` always points at the most
recent release rather than the newest commit.
Recording the release tag requires the workflow's `contents: write` permission;
if the instance forbids the automatic token from pushing, supply a PAT with
repository write scope and push the tag with it instead.
## Dependency updates
@@ -80,6 +95,10 @@ CDN, Renovate will track it if it is either annotated with a comment, e.g.
or referenced through a versioned jsDelivr / unpkg npm URL, which is detected
automatically.
Renovate is configured to commit updates as `fix(deps): …`. Each merged Renovate
PR therefore registers as a patch-level change, so the release workflow above
cuts a new patch release and tags the image automatically.
## Files
| File | Purpose |