release.yml fired on every push to main, so the trigger was "a PR was merged" and nothing else decided. That is a version per unit of *work* rather than per *shipment*: eight releases in twenty-two hours, v0.0.1 through v0.3.1, for one session -- each fanning out to four publishers on a runner with capacity 1, so roughly forty packaging jobs shipped three issues while ordinary PR CI queued behind them. pacman, Homebrew and Obtainium see every one. The push trigger is gone and workflow_dispatch, which was already there and already worked, is the whole mechanism. Nothing else had to change to batch releases, because semantic-release already reads every commit since the last tag: five fixes and two feats become one minor release with all seven in the notes. Release frequency was only ever how often this file fired. This is the rule index-artifact.yml states and is the other instance of: a job that mutates state which cannot be rebuilt in ten minutes is triggered deliberately, not by a push. A release here is a tag, a Gitea release, an Arch package, a Homebrew formula, a signed APK and desktop assets -- and an Android version going backwards costs the user their library. `dry_run` is what makes a manual trigger usable: the point of pulling a lever by hand is being able to look first, so the input runs semantic-release --dry-run -- the version and the notes, no tag, no release, no publishers. Anything but the literal string "true" releases for real, because a typo in a dispatch box must not silently turn a shipment into a green no-op. Two alternatives were considered and rejected, both recorded on the issue. A `beta` integration branch relocates the trigger rather than removing one: it needs a second protected branch carrying the same required checks, and it *adds* a full check + e2e run per batch on the very runner whose queue is the complaint. A schedule batches without anyone having to remember, but puts the decision back on a timer, which is the thing being removed. Closes #115
129 lines
4.9 KiB
YAML
129 lines
4.9 KiB
YAML
# semantic-release configuration.
|
|
#
|
|
# Run by hand from .gitea/workflows/release.yml, which has no push
|
|
# trigger: determine the version from the Conventional Commits since the
|
|
# last tag, write the changelog, push the tag, and create the Gitea
|
|
# release. A release is a shipment rather than a merge, and the commits
|
|
# accumulate until someone says so -- this file needs to know nothing
|
|
# about that, because reading everything since the last tag is what it
|
|
# already did.
|
|
#
|
|
# `branches` is main and only main. A `prerelease: true` channel is the
|
|
# obvious next edit here and is the one to think twice about: all four
|
|
# publishing workflows trigger on `v*`, which matches `v0.4.0-beta.1`.
|
|
# They carry a prerelease guard now, so the failure is a clean skip
|
|
# rather than a beta in a public tap -- but they are four separate files
|
|
# and this is the line that would turn them on.
|
|
#
|
|
# **There is no `@semantic-release/github` plugin here and there must not
|
|
# be.** Gitea's API is `/api/v1` and is not GitHub's surface. The Gitea
|
|
# community plugin (@saithodev/semantic-release-gitea) was considered and
|
|
# rejected: last published 2022, depends on got@10, and declares no peer
|
|
# dependency on semantic-release at all — i.e. untested against anything
|
|
# since v19, against a core now at v25. `exec` is first-party, current,
|
|
# and the Gitea-shaped part is one curl.
|
|
#
|
|
# The type list below is the one scripts/commit-check.sh enforces the
|
|
# grammar for — keep the two in step, or semantic-release will silently
|
|
# decline to release something the commit hook accepted.
|
|
branches:
|
|
- main
|
|
|
|
plugins:
|
|
# Analyze commits using conventional-commits preset.
|
|
- - "@semantic-release/commit-analyzer"
|
|
- preset: conventionalcommits
|
|
releaseRules:
|
|
- type: feat
|
|
release: minor
|
|
- type: fix
|
|
release: patch
|
|
- type: perf
|
|
release: patch
|
|
- type: refactor
|
|
release: patch
|
|
- type: revert
|
|
release: patch
|
|
- type: docs
|
|
release: false
|
|
- type: style
|
|
release: false
|
|
- type: chore
|
|
release: false
|
|
- type: ci
|
|
release: false
|
|
- type: test
|
|
release: false
|
|
- type: build
|
|
release: false
|
|
|
|
# Generate release notes from conventional commits.
|
|
- - "@semantic-release/release-notes-generator"
|
|
- preset: conventionalcommits
|
|
presetConfig:
|
|
types:
|
|
- type: feat
|
|
section: Features
|
|
- type: fix
|
|
section: Bug Fixes
|
|
- type: perf
|
|
section: Performance
|
|
- type: refactor
|
|
section: Refactoring
|
|
- type: revert
|
|
section: Reverts
|
|
- type: docs
|
|
section: Documentation
|
|
hidden: true
|
|
- type: chore
|
|
section: Miscellaneous
|
|
hidden: true
|
|
- type: ci
|
|
section: CI/CD
|
|
hidden: true
|
|
- type: test
|
|
section: Tests
|
|
hidden: true
|
|
- type: build
|
|
section: Build
|
|
hidden: true
|
|
|
|
# Render the notes to a file.
|
|
#
|
|
# **This plugin is here to carry the notes, not to maintain a document.**
|
|
# It is how they reach the Gitea API *without being interpolated into a
|
|
# shell command*: release notes are rendered commit messages — arbitrary
|
|
# text carrying backticks, quotes and `$` — so templating
|
|
# ${nextRelease.notes} into `publishCmd` would be a shell injection with
|
|
# the commit log as its input. scripts/gitea-release.sh reads the top
|
|
# section of this file instead, and the only thing interpolated below is
|
|
# a semver string.
|
|
#
|
|
# The target is a gitignored build artifact rather than CHANGELOG.md,
|
|
# because nothing commits it back — see below.
|
|
- - "@semantic-release/changelog"
|
|
- changelogFile: .release-notes.md
|
|
changelogTitle: "# Release notes"
|
|
|
|
# Create the Gitea release, whose body is that section.
|
|
# `publish` runs after `prepare`, so the tag already exists by here.
|
|
- - "@semantic-release/exec"
|
|
- publishCmd: "./scripts/gitea-release.sh ${nextRelease.version}"
|
|
|
|
# **There is deliberately no @semantic-release/git here.**
|
|
#
|
|
# `main` is a protected branch with `enable_push: false` and an empty
|
|
# push whitelist, so a changelog commit-back would be rejected by the
|
|
# pre-receive hook — *after* the tag had already been pushed, leaving a
|
|
# tagged release the run then reported as failed. The alternative was to
|
|
# whitelist the CI user, which weakens a protection someone set on
|
|
# purpose and lets a bot push to main without passing the checks every
|
|
# human PR has to.
|
|
#
|
|
# So the release page is the changelog. Tags are not protected, so the
|
|
# tag push semantic-release does itself is unaffected. CHANGELOG.md in
|
|
# the repo is a signpost to the releases page and is not written by any
|
|
# of this; a file that claimed to be a changelog and silently stopped
|
|
# updating would be worse than no file at all.
|
|
|