Move releases to GitHub, with one bridge release on Gitea

GitHub has no generic package registry, so releases become GitHub
release assets. The updater and install.sh read releases/latest/download
and releases/download/<v>/, plain redirects with no API rate limit.
make release publishes a draft with all assets, then makes it latest.
make release-gitea publishes the same version to the old Gitea registry
for binaries that still update from there, and refuses until GitHub
serves it. See D33.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 22:38:50 +01:00
co-authored by Claude Opus 5.5
parent c9932932bb
commit 1ee394cfdf
12 changed files with 182 additions and 93 deletions
+59 -45
View File
@@ -1,23 +1,23 @@
---
name: release
description: Prepare and publish a submarine release. Finds the latest release, picks the next semver from the changes since, runs a release check, creates and pushes the git tag, hands over to the developer for `make release`, then creates the Gitea release with MCP. Use only when the user asks to release.
description: Prepare and publish a submarine release. Finds the latest release, picks the next semver from the changes since, runs a release check, creates and pushes the git tag, writes the release notes, hands over to the developer for `make release`, then verifies the GitHub release. Use only when the user asks to release.
disable-model-invocation: true
---
# Release submarine
A release is built on the developer's machine (`make release`, see
`docs/architecture.md#distribution`). `make release` publishes the binaries
of the **clean `vX.Y.Z` tag at HEAD** to the Gitea package registry. This
skill does everything around it. The developer runs `make release`
themselves, in the middle: you never run it and never read or print `.env`
or `GITEA_TOKEN`.
`docs/architecture.md#distribution`). `make release` creates the GitHub
release of the **clean `vX.Y.Z` tag at HEAD**, with the binaries as assets.
This skill does everything around it. The developer runs `make release`
themselves, in the middle: you never run it and never read or print `.env`,
`GH_TOKEN` or `GITEA_TOKEN`.
Pushing a tag and creating a release are outward-facing and hard to undo.
Do them only after the confirmation in step 5, and never force-push, move or
delete a tag without asking.
Gitea: owner `simonfranken`, repo `submarine`, `https://git.simon-franken.de`.
GitHub: owner `simonfranken`, repo `submarine`, remote `origin`.
## 1. Preconditions
@@ -29,7 +29,7 @@ git branch --show-current # main
git status --porcelain # empty: make release refuses a dirty tree
git rev-parse HEAD origin/main # equal: HEAD is pushed, nothing to release from a local-only commit
git tag --points-at HEAD # empty: HEAD is not released yet
grep -q '^GITEA_TOKEN=.\+' .env # exists: only test it, never print it
gh auth status >/dev/null 2>&1 || grep -q '^GH_TOKEN=.\+' .env # one holds: only test, never print
```
## 2. Latest release
@@ -38,11 +38,12 @@ grep -q '^GITEA_TOKEN=.\+' .env # exists: only test it, never print i
git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -1
```
Cross-check with the `mcp__gitea__get_latest_release` MCP tool (load it with
ToolSearch first). If the tag and the Gitea release differ (a tag without a
Cross-check with the `mcp__github__get_latest_release` MCP tool (load it with
ToolSearch first). If the tag and the GitHub release differ (a tag without a
release is normal for the one in progress, a release without a tag is not),
tell the user and ask before going on. With no tag at all, the first release
is `v0.1.0`.
is `v0.1.0`. While the Makefile has `release-gitea` (step 10), GitHub has
no releases yet: cross-check with `mcp__gitea__get_latest_release` instead.
## 3. Changes since
@@ -55,7 +56,7 @@ No commits since the last tag: stop, there is nothing to release. Read the
commits, and where a subject is not clear, the diff. Sort each change as:
- **breaking**: removes or changes a key, a command or flag, the on-disk or
registry contract (`install.sh`, asset names, `submarine-latest/latest/VERSION`,
release contract (`install.sh`, asset names, `latest/download/VERSION`,
`submarine update`), or behavior users rely on;
- **feature**: a new key, action, view or option, or a visible behavior;
- **fix / other**: bug fixes, docs, refactoring, tests, performance.
@@ -108,51 +109,64 @@ git ls-remote --tags origin vX.Y.Z # the tag is on the remote
If the push fails, report git's message. Do not retry with force. If the tag
is wrong after it was pushed, ask before deleting it.
## 7. Hand over: the developer runs `make release`
## 7. Write the release notes
Write them to `/tmp/submarine-vX.Y.Z-notes.md` (outside the repository:
`make release` refuses a dirty tree). They are for users of the tool, not a
commit dump: short, grouped under **Breaking changes** (only if any),
**New**, **Fixes** (leave out empty groups and pure refactoring/tests), each
item one line naming the key or behavior (`b` switches the branch of a
repository...). End with:
```
Install or update: `curl -fsSL https://raw.githubusercontent.com/simonfranken/submarine/main/install.sh | sh`, or `submarine update`.
Full changelog: https://github.com/simonfranken/submarine/compare/<last>...vX.Y.Z
```
Show the notes to the user; they can change them before the next step.
## 8. Hand over: the developer runs `make release`
HEAD is now the clean tag, which is what `make release` needs. Tell the
developer to run, in the repository:
```sh
make release
make release NOTES=/tmp/submarine-vX.Y.Z-notes.md
```
(it reads `GITEA_TOKEN` from `.env`, tests, builds, uploads, and points
`submarine-latest` at the version last). **Stop here and wait** until they
say it finished. If it failed, help with the output; do not run it yourself.
(it uses `gh`, tests, builds, creates the release as a draft with all
assets and publishes it last). **Stop here and wait** until they say it
finished. If it failed, help with the output; do not run it yourself. A
leftover draft from a failed run must be deleted (ask first) before a retry.
## 8. Verify the upload, create the Gitea release
## 9. Verify the release
Once the developer reports success:
```sh
curl -fsSL https://github.com/simonfranken/submarine/releases/latest/download/VERSION
```
must print `vX.Y.Z` (this is what `install.sh` and `submarine update`
read). Check with `mcp__github__get_release_by_tag` that it is not a draft
and has the assets `submarine_{linux,darwin}_{amd64,arm64}`,
`checksums.txt` and `VERSION`. If anything is missing, report it. Finish
with the link to the release and the version.
## 10. Bridge release (only while the Makefile has `release-gitea`)
The first GitHub release is also published to the old Gitea registry, so
binaries that still update from Gitea pick it up (D33). After step 9, and
after asking the user, push the tag to the `gitea` remote and hand over
again:
```sh
git push gitea main vX.Y.Z
make release-gitea # run by the developer, needs GITEA_TOKEN
curl -fsS https://git.simon-franken.de/api/packages/simonfranken/generic/submarine-latest/latest/VERSION
```
must print `vX.Y.Z` (the registry is public; `install.sh` reads it the same
way). If it doesn't, the upload did not complete: do not create the release,
report it.
Then create the release with `mcp__gitea__create_release` (load it with
ToolSearch first):
- `owner`: `simonfranken`, `repo`: `submarine`
- `tag_name`: `vX.Y.Z`
- `target`: the tag's commit, `git rev-parse vX.Y.Z^{commit}`
- `title`: `vX.Y.Z`
- `is_draft`: false, `is_pre_release`: false
- `body`: release notes, see below
Release notes are for users of the tool, not a commit dump: short, grouped
under **Breaking changes** (only if any), **New**, **Fixes** (leave out empty
groups and pure refactoring/tests), each item one line naming the key or
behavior (`b` switches the branch of a repository...). End with:
```
Install or update: `curl -fsSL https://git.simon-franken.de/simonfranken/submarine/raw/branch/main/install.sh | sh`, or `submarine update`.
Full changelog: https://git.simon-franken.de/simonfranken/submarine/compare/<last>...vX.Y.Z
```
The binaries live in the package registry, not on the release: attach
nothing. Finish with the link to the release and the version.
The last command must print `vX.Y.Z`. Then create a Gitea release for the
tag with `mcp__gitea__create_release`, its body saying that submarine moved
to https://github.com/simonfranken/submarine.