chore(release): tool/release.sh goes, and the snap goes to the Store's edge
Build 21 (v0.18.0) was the release tool/release.sh was kept for, the one going with ADR 0014's breaking deploy; every release since is `dart run tool/release.dart learn`. The comments that named the script (the F-Droid script, the certificate pin, the Gradle signing) now name the Dart tool. Learn's release uploads the snap to the Snap Store's edge channel last, where v0.18.0 went by hand; the release refuses to start unless `snapcraft whoami` shows a login. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
8d6785f5c6
commit
87ae5fca89
1 changed files with 12 additions and 368 deletions
|
|
@ -68,7 +68,7 @@ A spaced-repetition learning app: studysets of flashcards, reviewed on an FSRS s
|
|||
- **From the single repository** (ADR 0015): learn.halkyon.eu deploys this repository's `main`, whichever app or shared package a push changed. Its images are built from the repository's root with only what they need (Learn's server and the module it builds on, with the module's client, which the module's tests depend on; the curator), each Dockerfile narrowing the workspace to those packages (`tool/workspace_only.sh`). The first deploy after the move starts the server once more than it needs to, as the deployed copy of `redeploy.sh` looks for migrations at their old path.
|
||||
- **Sidecars** (`deploy/sidecars/README.md`, decided 2026-10-14): services an instance may run beside itself, each a compose file of its own beside `deploy/compose.yaml` (`compose.jellyfin.yaml`; later LanguageTool, Fedify), switched on in `deploy/.env` (`COMPOSE_FILE=compose.yaml:compose.jellyfin.yaml`), so `redeploy.sh` deploys them with the instance. The instance's compose has two networks: `edge` (`halkyon-learn-edge`, 172.30.80.0/24 and the unique local fd4a:6c6b:7e80::/64, so Docker hands Caddy IPv6 visitors' own addresses), Caddy's at fixed addresses (172.30.80.2, fd4a:6c6b:7e80::2; the server's `TRUSTED_PROXIES`), shared with the server, and the internal default one, where the server reaches Postgres; a sidecar joins `edge` alone and publishes no port (the CI runner may reach `127.0.0.1`, never Docker's 172.16.0.0/12 or fd00::/8). A sidecar reached from outside mounts its site from `deploy/sidecars/` into Caddy's `/etc/caddy/sidecars/`, which the Caddyfile imports (none without), and `redeploy.sh` recreates Caddy when a site changes. Each runs as a user ID of its own (Jellyfin 61096), never one a person, another container or the runner uses; its files on the server are git-ignored (`deploy/jellyfin/`). The Jellyfin sidecar sets the server's `JELLYFIN_URL`, so the instance suggests it.
|
||||
- **Backups** (`deploy/backups.md`): every hour, `deploy/backup.sh` (a systemd timer, as `deploy`) dumps the database, which holds people's files too, then bundles each published studyset's repository (`git bundle`, from the server's `repositories` volume), and restic stores both in a Hetzner Storage Box (24 hourly, 7 daily, 4 weekly, 3 monthly); the box's own snapshots protect it from a taken-over server. A restore takes the instance back up to an hour, and people who started since lose what their device held: their app no longer finds its session, starts a new anonymous account and deletes the old folder. So a change that makes devices lose their session, or keeps deleted people's data longer, changes what a restore costs; say so in `deploy/backups.md`.
|
||||
- **Releases** are the project's, not an instance's: the release, the Snap Store listing and the F-Droid listing point to the project's page on Halkyon's website, halkyon.app/learn (its own repository, `project-halkyon/website`; learn.halkyon.app redirects there); the builds name learn.halkyon.eu, the project's instance (`SERVER_URL`), which a new install offers first (see *Instances*). They come from a developer's laptop, never from CI: `dart run tool/release.dart learn` on `main` as pushed and green in CI (the apps' shared release tool, ADR 0015, configured in `apps/learn/release.dart`; `--dry-run` shows the version, the commits that count, every step and the notes without changing anything). Build 21 alone comes from `tool/release.sh`, the Bash script it replaces, tagged `v0.18.0`; then that script goes. Versions follow semantic versioning, worked out from the commits touching Learn since its last release (`apps/learn/`, the shared packages it uses, the root pubspec and lock, its release files, and its packages' folders at the root from before the move; `feat` raises the minor number, `fix`/`perf` the patch number, breaking ones the major from 1.0 on; other types release nothing), so **commit messages keep their type prefix**. It writes the version and a raised build number into the app's pubspec in a signed release commit (`chore(release): learn-vX.Y.Z`) with a signed tag (`learn-vX.Y.Z`, by a key in `deploy/allowed-signers`; Learn's earlier `vX.Y.Z` tags count as its history), builds one universal APK from a checkout of the tag, signed with the app's key, and the snap (`snap/snapcraft.yaml`, the committed HEAD, built in LXD), both with `SERVER_URL=https://learn.halkyon.eu/`; signs `SHA256SUMS` with GPG; pushes only once both builds passed their checks; and publishes on code.halkyon.app through Forgejo's API and in the F-Droid repository. The Snap Store upload is off until `storeChannel` in `apps/learn/release.dart` names a channel. A run that stopped after its release commit and tag carries on with them. The key's password and the Forgejo token are asked for at each run and never stored. The app's key is a PKCS #12 keystore outside the repository (also in the maintainer's password manager); there is no Google Play, so it is the app's identity: lost, installed apps can't be updated. Its certificate's SHA-256 is in `tool/release/android-certificate.sha256`, and the release tool releases no APK signed otherwise; other release builds fall back to the debug key (`android/app/build.gradle.kts`), so `flutter run --release` works anywhere. The APK also goes into the project's own F-Droid repository, https://halkyon.app/fdroid/repo, through `tool/fdroid_repo.sh` (fdroidserver v2.4.5): its settings and the app's listing are in `tool/release/fdroid/` (the anti-feature NonFreeNet declared with its reasons and F-Droid's own icon; not TetheredNet, as the app chooses its instance); its index is signed with a key of its own (a PKCS #12 keystore beside the app's, password asked for, certificate pinned in `tool/release/fdroid-index-certificate.sha256`, since a new key makes the F-Droid app refuse the repository); and it is uploaded to the halkyon.app server (`ssh ramiel-fdroid`) as the user `fdroid`, whose key can only write into the folder Caddy serves (rrsync), the APKs first and the indexes last.
|
||||
- **Releases** are the project's, not an instance's: the release, the Snap Store listing and the F-Droid listing point to the project's page on Halkyon's website, halkyon.app/learn (its own repository, `project-halkyon/website`; learn.halkyon.app redirects there); the builds name learn.halkyon.eu, the project's instance (`SERVER_URL`), which a new install offers first (see *Instances*). They come from a developer's laptop, never from CI: `dart run tool/release.dart learn` on `main` as pushed and green in CI (the apps' shared release tool, ADR 0015, configured in `apps/learn/release.dart`; `--dry-run` shows the version, the commits that count, every step and the notes without changing anything). Build 21 (`v0.18.0`) was the last from `tool/release.sh`, the Bash script it replaced, removed since. Versions follow semantic versioning, worked out from the commits touching Learn since its last release (`apps/learn/`, the shared packages it uses, the root pubspec and lock, its release files, and its packages' folders at the root from before the move; `feat` raises the minor number, `fix`/`perf` the patch number, breaking ones the major from 1.0 on; other types release nothing), so **commit messages keep their type prefix**. It writes the version and a raised build number into the app's pubspec in a signed release commit (`chore(release): learn-vX.Y.Z`) with a signed tag (`learn-vX.Y.Z`, by a key in `deploy/allowed-signers`; Learn's earlier `vX.Y.Z` tags count as its history), builds one universal APK from a checkout of the tag, signed with the app's key, and the snap (`snap/snapcraft.yaml`, the committed HEAD, built in LXD), both with `SERVER_URL=https://learn.halkyon.eu/`; signs `SHA256SUMS` with GPG; pushes only once both builds passed their checks; and publishes on code.halkyon.app through Forgejo's API and in the F-Droid repository. The snap goes to the Snap Store's edge channel last (`storeChannel` in `apps/learn/release.dart`; the release refuses to start unless `snapcraft whoami` shows a login). A run that stopped after its release commit and tag carries on with them. The key's password and the Forgejo token are asked for at each run and never stored. The app's key is a PKCS #12 keystore outside the repository (also in the maintainer's password manager); there is no Google Play, so it is the app's identity: lost, installed apps can't be updated. Its certificate's SHA-256 is in `tool/release/android-certificate.sha256`, and the release tool releases no APK signed otherwise; other release builds fall back to the debug key (`android/app/build.gradle.kts`), so `flutter run --release` works anywhere. The APK also goes into the project's own F-Droid repository, https://halkyon.app/fdroid/repo, through `tool/fdroid_repo.sh` (fdroidserver v2.4.5): its settings and the app's listing are in `tool/release/fdroid/` (the anti-feature NonFreeNet declared with its reasons and F-Droid's own icon; not TetheredNet, as the app chooses its instance); its index is signed with a key of its own (a PKCS #12 keystore beside the app's, password asked for, certificate pinned in `tool/release/fdroid-index-certificate.sha256`, since a new key makes the F-Droid app refuse the repository); and it is uploaded to the halkyon.app server (`ssh ramiel-fdroid`) as the user `fdroid`, whose key can only write into the folder Caddy serves (rrsync), the APKs first and the indexes last.
|
||||
|
||||
## Rules the code relies on
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue