ci: release pull requests, and conventional-commit PR titles (#1)
CI / build (push) Successful in 9s
Release / release (push) Successful in 2s
CI / image (push) Successful in 21s

Releases as pull requests, the same in all five app repos (hub, catalog, live, riftbound, karaoke). The Gitea side (PRs only into main, squash merges, required checks, `v*` tags only by release-bot, its `RELEASE_TOKEN` org secret) is dhkatz/infra `modules/app-repo`.

- **`.gitea/workflows/pull-request.yml`**: the PR title must be a conventional commit (`feat(api): …`, `fix: …`, `feat!: …`); it becomes the commit on main. `chore(release)` only from release-bot's `release` branch. Required to merge (`Pull request / title`).
- **`.gitea/default_merge_message/SQUASH_TEMPLATE.md`**: the squash commit is `<PR title> (#<n>)` plus the description.
- **`.gitea/workflows/release.yml`**, on every push to main, as release-bot (`RELEASE_TOKEN`):
  - if the commit is a merged `chore(release): vX.Y.Z`: tag it vX.Y.Z (lightweight), push the tag (CI builds the image, Komodo deploys prod), publish the release with git-cliff's notes;
  - otherwise, if anything releasable landed since the last tag: rewrite the `release` branch (CHANGELOG.md) and open or update `chore(release): vX.Y.Z`.
- **`cliff.toml`** (git-cliff 2.14.2, pinned by sha512): feat → minor, fix/perf/revert → patch, breaking → minor while 0.x; chore/ci/docs/test/style/build/refactor alone don't release. Only conventional commits count, so the history before this is left out.
- **`CHANGELOG.md`**: header only; release PRs fill it.
- Agent notes (CLAUDE.md / AGENTS.md): the PR flow and title format; never tag by hand.

After merging, `Release` runs on main and should report nothing to release (this PR is `ci:`); the first `feat:`/`fix:` PR merged after it opens the first release PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #1
Co-authored-by: dhkatz <[email protected]>
This commit was merged in pull request #1.
This commit is contained in:
dhkatz authored and dhkatz committed 2026-11-03 08:40:38 +00:00
1 parent f60ba346f8
commit fbf1e01314
6 files changed
+174

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
# A pull request's title becomes its commit on main (squash merges, .gitea/default_merge_message), so it must be a
# conventional commit: the release workflow versions releases and writes the changelog from them. Required to merge
# (branch protection, dhkatz/infra modules/app-repo).
name: Pull request
on:
pull_request:
types: [opened, edited, reopened, synchronize]
jobs:
title:
runs-on: ubuntu-latest
steps:
- name: Conventional commit title
env:
TITLE: ${{ github.event.pull_request.title }}
BRANCH: ${{ github.head_ref }}
AUTHOR: ${{ github.event.pull_request.user.login }}
run: |
types="feat|fix|perf|refactor|docs|test|build|ci|chore|style|revert"
conventional="^($types)(\([a-z0-9][a-z0-9./_-]*\))?!?: [^ ]"
if ! [[ "$TITLE" =~ $conventional ]]; then
echo "::error::The title becomes the commit on main, so it must be a conventional commit: type(scope): summary, e.g. \"feat(api): room bans\" or \"fix: crash on an empty catalog\" (! before the colon for a breaking change). Types: ${types//|/, }."
exit 1
fi
if [[ "$TITLE" =~ ^chore\(release\) ]] && [[ "$BRANCH" != release || "$AUTHOR" != release-bot ]]; then
echo "::error::chore(release) is release-bot's: merging its release pull request is what tags a release."
exit 1
fi
echo "OK: $TITLE"