docs(release): describe the Gitea xbps release and the template bump pull request

Cover the one-time setup (the XBPS_SIGNING_KEY secret, the committed public
key and its fingerprint, the runner and token needs), the tag-push gates and
what the workflow publishes to the tag release and to latest, and the
checklist items for verifying the run. The template version and checksum
bump stays a normal pull request, never a bot commit to main, and now says
the checksum is the sha256 of the fork's own release asset.

The cherry-pick policy from ticket #30 was already in this file and is
enforced by tests/test_upstream_intake_policy.py. Correct what it names as
the retained internal module: it is vocalinux (src/vocalinux/), not
voculinux.
This commit is contained in:
2026-11-06 18:28:11 +05:30
parent 3c33aa62b8
commit d3a3f54204
+78 -11
View File
@@ -37,6 +37,24 @@ publish succeeds.
`publish-aur` skips itself when `AUR_SSH_PRIVATE_KEY` is unset. See docs/AUR.md.
### Void xbps repository (required for a Void release)
The signed Void repository is released by `.gitea/workflows/xbps-release.yml`
on the fork's Gitea host, not by `release.yml`. Set it up once:
| what | value |
|---|---|
| Secret | `XBPS_SIGNING_KEY`: the PEM-encoded RSA 4096 repository private key (Gitea repository settings, Actions, Secrets) |
| Public key | `packaging/void/repository-key.plist`, committed, fingerprint `fa:d1:00:32:ce:b1:b9:fd:73:05:05:76:75:54:37:25` |
| Runner | `bongbetic-ci` with podman (the workflow installs it with apt when absent). Never Docker |
| Token | the job token must be allowed to create releases and upload release assets |
Without the secret the workflow fails and publishes nothing; it never signs
with a different key either, because the fingerprint of the key that signed
must equal the one above. The private key is never committed; only the public
`.plist` is. Key generation and the check that a private key matches the
committed public key are in `packaging/void/README.md`.
## Quick Release Checklist
Use this checklist for every release:
@@ -81,7 +99,7 @@ Install `just` from https://just.systems or the distro package `just`.
- [ ] Commit all version changes
- [ ] Push branch and create PR
- [ ] After PR merge, create tag: `git tag -a vX.Y.Z-PHASE -m "Release X.Y.Z-PHASE"`
- [ ] Push tag: `git push origin vX.Y.Z-PHASE`
- [ ] Push tag: `git push origin vX.Y.Z-PHASE` (this also starts the Gitea xbps workflow, see Step 8)
### After the release run finishes
- [ ] Run `just verify-release` - the published release verifies as published
@@ -316,13 +334,21 @@ Update the supported versions table:
After the tag is cut, the Void templates in `packaging/void/srcpkgs/` must
point at the new release: bump `version` in the `voculinux` template (and
any template whose upstream moved) and refresh every pinned `checksum`
(`sha256` sums of the release sdist and distfiles). Land the bump as a
**pull request** through the normal test, lint, and type gates — never as
a direct or bot commit to `main`, and never hand-edited onto the release
itself (see `just verify-release`). `tests/test_void_app_template.py`
fails if the template version or checksum drifts from
`src/vocalinux/version.py` and the published sdist, and the signed xbps
repository for the *next* release builds from these templates.
(`sha256` sums of the release sdist and distfiles). The `voculinux` template
builds the fork's release asset `voculinux-X.Y.Z.tar.gz`; its `checksum` is
the sha256 of that exact downloaded asset, never a value copied from
upstream, and stays `PENDING_FORK_RELEASE_SHA256` (which fails closed in
`xbps-src`) until the asset exists. Land the bump as a **pull request**
through the normal test, lint, and type gates, never as a direct or bot
commit to `main`, and never hand-edited onto the release itself (see
`just verify-release`). `tests/test_void_app_template.py` fails if the
template version or checksum drifts from `src/vocalinux/version.py` and the
published sdist.
Nothing automates this: the xbps workflow never commits or pushes. The
signed repository a tag publishes is built from the templates as committed
at that tag, so a bump merged after tag `vX.Y.Z` first ships with the next
tag push.
### Step 4: Update Website
@@ -383,7 +409,7 @@ bash -n install.sh
### Upstream Fix Intake (Cherry-Pick Policy)
Upstream Voculinux fixes enter this fork only as hand cherry-picks: taken at
Upstream Vocalinux fixes enter this fork only as hand cherry-picks: taken at
defined sync points, never as continuous tracking and never as wholesale
merges. Like every other change, each port goes through the pull request flow
with the standard test, lint, and type gates. Never land one as a direct or
@@ -404,8 +430,10 @@ worktree per branch, every change via a pull request, never commit on `main`
renames on top. Conflicts concentrate at the renamed user-visible surfaces
(application name, entry points, desktop and D-Bus identity, configuration
and data directories, package, website) precisely because the internal
Python module name stays `voculinux` as a retained internal name — that
split is what keeps hand cherry-picks nearly conflict-free everywhere else.
Python module name stays `vocalinux` (`src/vocalinux/`) as a retained
internal name, so only the user-visible surfaces diverge from upstream, and
that split is what keeps hand cherry-picks nearly conflict-free everywhere
else.
Upstream URLs and changelog history stay untouched for provenance.
- **What qualifies.** Fixes and documentation that changes user instructions
port. Features are re-decided per release, not ported automatically.
@@ -507,6 +535,39 @@ After pushing the tag, the GitHub Actions workflow will automatically:
Monitor at: https://github.com/VocaHQ/vocalinux/actions
#### Void xbps repository (Gitea tag workflow)
Pushing the tag to `origin` (the fork's Gitea repository) also starts
`.gitea/workflows/xbps-release.yml`. Pushing a tag is a human act and is
approved each time: the workflow has no schedule and no manual trigger.
1. **Tag equals version.** The tag must be exactly `v` plus `__version__` in
`src/vocalinux/version.py`. Any other tag, including one that merely
contains the version, exits 1 and publishes nothing.
2. **Signing key required.** An empty `XBPS_SIGNING_KEY` exits 1 before any
container runs. The key is written to a 0600 temp file, passed to
`packaging/void/repo.sh`, and removed by a step that always runs.
3. **Build and sign.** `repo.sh` is the only path that builds or signs: the
pinned Void glibc container under podman, every template in smoke-gate
order, the full `x86_64` index, every package and the metadata signed.
4. **Verify.** Packages, signatures, repodata, `FINGERPRINT` and the client
key must all be present, nothing but glibc `x86_64` data may be present,
every package must be signed, and the signing fingerprint must be the
pinned one. A partial or unsigned repository never attaches.
5. **Publish.** The complete signed set attaches to the tag's release on
Gitea and replaces the assets of the rolling `latest` release, which the
client registration URL
(`https://git.bongbetic.com/xavierk/voculinux/releases/download/latest`)
serves. Push tags in version order: pushing an older tag refreshes
`latest` with the older repository.
The workflow never commits or pushes to any branch and never bumps a
template; that is the pull request in section 3.5. The `voculinux` template
fetches the fork's `vX.Y.Z` release asset, so that asset must exist and its
checksum must be in the template before the build can pass. A tag whose
templates still carry the pending checksum fails at the build step, by
design.
### Step 9: Post-Release Tasks
- [ ] Verify GitHub Release was created correctly
@@ -526,6 +587,12 @@ Monitor at: https://github.com/VocaHQ/vocalinux/actions
- [ ] Verify PyPI package was published (if applicable), and that its wheel sha256
matches the line for that wheel in `SHA256SUMS`
- [ ] Verify website was deployed (check voculinux.com)
- [ ] Verify the Gitea xbps run succeeded, and that both the tag release and
`latest` carry the full signed set (`*.x86_64.xbps`, `*.sig2`,
`x86_64-repodata`, `FINGERPRINT`, the `.plist`) and that the fingerprint
matches the one in `README.md`
- [ ] Open the Void template bump pull request (section 3.5); never commit
it directly to `main`
- [ ] If the Flatpak remote is configured, verify it picked up the tag:
`flatpak remote-info vocahq com.voculinux.Voculinux` (docs/FLATPAK_REMOTE.md)
- [ ] Announce on social media/communities