Moves plan 017 to completed with a recap, and lifts the three findings that generalise into NOTES.md: a preset major that renders empty notes with everything green, a 403 that looks like branch protection and is a token scope, and tag-triggered workflows running the tagged commit's own definitions.
88 lines
4.4 KiB
Markdown
88 lines
4.4 KiB
Markdown
# 017 — Releases that happen by themselves
|
|
|
|
**Shipped as `v0.0.1`.** A merge to `main` now reads the Conventional
|
|
Commits since the last tag, cuts the tag and the Gitea release whose body
|
|
is the generated changelog, and the four publishing workflows build that
|
|
tag and attach their artifacts. Nothing is released by hand.
|
|
|
|
## What it looks like now
|
|
|
|
`release.yml` on push to `main` → semantic-release → tag → four `v*`
|
|
workflows in parallel (serialised in practice by the capacity-1 runner):
|
|
|
|
| workflow | publishes | attaches |
|
|
| --- | --- | --- |
|
|
| `arch-package` | pacman registry | `…-x86_64.pkg.tar.zst` |
|
|
| `android-apk` | generic registry (Obtainium) | `…-android-arm64.apk` |
|
|
| `desktop-assets` | — | `…-linux-amd64.tar.gz` |
|
|
| `homebrew-formula` | the public tap | — (builds from source) |
|
|
|
|
Verified on the real thing: all five green, three assets on the release,
|
|
the tap at `0.0.1`, and the Obtainium `latest` URL serving 200.
|
|
|
|
## The five decisions, and what they cost
|
|
|
|
1. **semantic-release, not a shell script.** The first draft of this plan
|
|
proposed hand-rolling it and the argument did not survive checking:
|
|
`@semantic-release/exec` is first-party and current, and the
|
|
Gitea-shaped part is one `curl`. What I would have hand-rolled —
|
|
commit parsing, semver ordering, note rendering — is the part with the
|
|
edge cases and none of it is Gitea-shaped.
|
|
2. **`@saithodev/semantic-release-gitea` is a dead end** and was offered
|
|
before it was checked: last published 2022, `got@10`, and no peer
|
|
dependency on semantic-release at all.
|
|
3. **No `@semantic-release/git`.** `main` is protected, so a changelog
|
|
commit-back is rejected by the pre-receive hook — and would be
|
|
rejected *after* the tag was pushed, leaving a tagged release the run
|
|
reports as failed. The release page is the changelog;
|
|
`.release-notes.md` is a gitignored carrier and `CHANGELOG.md` is a
|
|
signpost.
|
|
4. **Versions restart at `0.0.1`**, a downgrade on every channel. No
|
|
`epoch`, no `versionCode` offset: both are permanent, a reinstall is
|
|
once. Documented in `packaging/homebrew/README.md` and
|
|
`docs/android-release.md`.
|
|
5. **No macOS and no Windows.** `GOOS=darwin CGO_ENABLED=0` fails at
|
|
`wails/v3/pkg/mac` and there is no macOS runner, so Homebrew-from-source
|
|
stays that channel. Windows cross-compiles in ~2.5 s and is withheld
|
|
because no build of it has ever been *run*.
|
|
|
|
## Four things that only showed up by running it
|
|
|
|
- **`conventional-changelog-conventionalcommits@10` renders empty
|
|
notes.** Silently: right version, right tag, every step green, and a
|
|
release body that is a bare `## 0.0.1 (date)` heading with nothing
|
|
beneath it. Held at `9`, in `release.yml` and `make release-dry`, with
|
|
the reason beside both. **Check the rendered notes, never the exit
|
|
code.**
|
|
- **semantic-release core dry-run-pushes to the release branch** as a
|
|
permission check, independently of any plugin. `PACKAGE_TOKEN` had
|
|
package-write and repo-*read* — enough to clone, not enough for this —
|
|
and it failed with a flat `403 Forbidden` that reads exactly like
|
|
branch protection. It is not: a `--dry-run` push never reaches the
|
|
pre-receive hook, which a one-line experiment settled. The token needed
|
|
`write:repository`.
|
|
- **The floor tag must go on `HEAD^`, not `HEAD`.** Seeded on the merge
|
|
commit itself it leaves nothing between the floor and HEAD, and
|
|
semantic-release correctly reports there is nothing to release. The
|
|
first run did exactly that and cut nothing.
|
|
- **A tag-triggered workflow runs from the tagged commit's tree.**
|
|
Moving `v0.0.0` back to `6fb7b5e` ran the *pre-merge* homebrew
|
|
workflow, which predates the `v0.0.0` skip guard, and pushed a `0.0.0`
|
|
formula to the public tap. Self-corrected at `0.0.1`. The corollary is
|
|
general: a guard added today does not protect a tag pointing at
|
|
yesterday.
|
|
|
|
## Two mechanisms confirmed, having been assumptions
|
|
|
|
- **A tag pushed with a user PAT does start the `v*` workflows**; one
|
|
pushed with the Actions token does not (go-gitea#33123). Both halves
|
|
are load-bearing and both were observed: the floor seed triggered
|
|
nothing, and the release tag triggered all four.
|
|
- **Tags are not protected** on this repo, only `main` — which is what
|
|
lets semantic-release tag at all.
|
|
|
|
## Left behind deliberately
|
|
|
|
`v0.0.0` stays on `origin` as the floor. It carries no release, and all
|
|
four publishers skip it by name.
|