docs: add changelog, contributor guide, release process, and runner setup
- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
everything shipped so far (installer webapp, drive scoring, base
archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
and the release workflow (bump changelog, commit, tag, push, create
Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
upcoming CI workflow actually executes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:23:48 +02:00
# Releasing
2026-04-13 21:43:34 +02:00
Furtka uses calendar versioning: ** `YY.N-stage` ** — e.g. `26.0-alpha` is 2026, release 0, alpha stage. No `v` prefix.
docs: add changelog, contributor guide, release process, and runner setup
- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
everything shipped so far (installer webapp, drive scoring, base
archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
and the release workflow (bump changelog, commit, tag, push, create
Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
upcoming CI workflow actually executes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:23:48 +02:00
- `YY` — last two digits of the current year
- `N` — incrementing release number within the year, starting at 0 (next one in 2026 is `26.1-alpha` , then `26.2-alpha` …)
- `-alpha` — drop it when the installer boots end-to-end and wipe-and-reinstall is safe
When the year rolls over, the next release becomes `27.0-alpha` regardless of how many `26.x` releases shipped.
## Cadence
Tag per meaningful milestone, not on a calendar. A milestone is: ISO boots, a wizard screen works end-to-end, managed gateway serves its first real domain, etc. If a week goes by with no tag, that's fine — no tag is better than a noisy one.
## Release steps
1. **Move `[Unreleased]` in `CHANGELOG.md` to a new version heading.**
```markdown
## [Unreleased]
## [26.1-alpha] - 2026-05-20
### Added
- ...
```
Add a `[26.1-alpha]` link definition at the bottom:
```markdown
2026-04-13 21:43:34 +02:00
[26.1-alpha]: https://forgejo.sourcegate.online/daniel/furtka/releases/tag/26.1-alpha
docs: add changelog, contributor guide, release process, and runner setup
- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
everything shipped so far (installer webapp, drive scoring, base
archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
and the release workflow (bump changelog, commit, tag, push, create
Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
upcoming CI workflow actually executes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:23:48 +02:00
```
Update the `[Unreleased]` compare link to point at the new tag.
2. **Commit the changelog.**
```bash
git add CHANGELOG.md
git commit -m "chore: release 26.1-alpha"
```
3. **Tag the commit.**
```bash
git tag -a 26.1-alpha -m "Release 26.1-alpha"
```
4. **Push the tag and main.**
```bash
git push origin main
git push origin 26.1-alpha
```
feat(furtka): release CI + \`furtka update\` / \`furtka rollback\` CLI
Slice 2 of the self-update story. Tagging a release on main now
produces a downloadable self-update payload on the Forgejo releases
page, and a running box can pull it down, verify it, atomically swap
to the new version, and health-check the result.
New pieces:
- scripts/build-release-tarball.sh <version> — packages the furtka/
package + bundled apps/ + a root-level VERSION file as
dist/furtka-<version>.tar.gz, plus a .sha256 sidecar and a
release.json metadata blob.
- scripts/publish-release.sh <version> — uses the Forgejo v1 API to
create a release (body pulled from the CHANGELOG section for this
tag, pre-release auto-flagged on -alpha/-beta/-rc) and upload the
three assets sequentially. Needs \$FORGEJO_TOKEN.
- .forgejo/workflows/release.yml — tag-triggered, runs both scripts
with the new \$FORGEJO_RELEASE_TOKEN repo secret.
- furtka/updater.py — check_update, prepare_update, apply_update,
run_update, rollback. Atomic symlink swap, sha256 verify (TOCTOU-
safe: re-hashes on-disk file), health-check post-restart with
auto-rollback on failure, stage-by-stage progress persisted to
/var/lib/furtka/update-state.json so the UI can poll independent
of the (restarting) API process. Path overrides via FURTKA_ROOT /
FURTKA_STATE_DIR / FURTKA_LOCK_PATH so tests pin a tmpdir.
- furtka/cli.py — \`furtka update [--check] [--json]\` and
\`furtka rollback\`.
- tests/test_updater.py — 15 tests: version compare, sha256 verify,
tarball extract (including traversal refusal), lockfile, apply
happy + rollback paths, rollback CLI, check_update with stubbed
Forgejo.
- iso/build.sh — writes VERSION at the tarball root so the install
path matches the self-update path (previously assumed only the
release script did this).
RELEASING.md now points at the automated flow — no more manually
clicking "Create release" on the Forgejo UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:30:45 +02:00
5. **The release workflow does the rest.** `.forgejo/workflows/release.yml` fires on the tag push: `scripts/build-release-tarball.sh` builds the self-update payload (tarball + sha256 + release.json under `dist/` ), `scripts/publish-release.sh` uploads all three assets to the Forgejo release page. Pre-release is flagged automatically based on the suffix (`-alpha` /`-beta` /`-rc` ).
docs: add changelog, contributor guide, release process, and runner setup
- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
everything shipped so far (installer webapp, drive scoring, base
archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
and the release workflow (bump changelog, commit, tag, push, create
Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
upcoming CI workflow actually executes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:23:48 +02:00
feat(furtka): release CI + \`furtka update\` / \`furtka rollback\` CLI
Slice 2 of the self-update story. Tagging a release on main now
produces a downloadable self-update payload on the Forgejo releases
page, and a running box can pull it down, verify it, atomically swap
to the new version, and health-check the result.
New pieces:
- scripts/build-release-tarball.sh <version> — packages the furtka/
package + bundled apps/ + a root-level VERSION file as
dist/furtka-<version>.tar.gz, plus a .sha256 sidecar and a
release.json metadata blob.
- scripts/publish-release.sh <version> — uses the Forgejo v1 API to
create a release (body pulled from the CHANGELOG section for this
tag, pre-release auto-flagged on -alpha/-beta/-rc) and upload the
three assets sequentially. Needs \$FORGEJO_TOKEN.
- .forgejo/workflows/release.yml — tag-triggered, runs both scripts
with the new \$FORGEJO_RELEASE_TOKEN repo secret.
- furtka/updater.py — check_update, prepare_update, apply_update,
run_update, rollback. Atomic symlink swap, sha256 verify (TOCTOU-
safe: re-hashes on-disk file), health-check post-restart with
auto-rollback on failure, stage-by-stage progress persisted to
/var/lib/furtka/update-state.json so the UI can poll independent
of the (restarting) API process. Path overrides via FURTKA_ROOT /
FURTKA_STATE_DIR / FURTKA_LOCK_PATH so tests pin a tmpdir.
- furtka/cli.py — \`furtka update [--check] [--json]\` and
\`furtka rollback\`.
- tests/test_updater.py — 15 tests: version compare, sha256 verify,
tarball extract (including traversal refusal), lockfile, apply
happy + rollback paths, rollback CLI, check_update with stubbed
Forgejo.
- iso/build.sh — writes VERSION at the tarball root so the install
path matches the self-update path (previously assumed only the
release script did this).
RELEASING.md now points at the automated flow — no more manually
clicking "Create release" on the Forgejo UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:30:45 +02:00
The release workflow needs one secret set at repo **Settings → Secrets → Actions** :
- `FORGEJO_RELEASE_TOKEN` — a PAT with `write:repository` scope.
6. **Verify CI passed on the tag.** The Forgejo Actions run against the tagged commit should be green before you announce the release anywhere — both the CI workflow (lint/test) and the Release workflow (tarball published).
7. ** (Optional) Dogfood the update path.** On a VM running the previous version, `sudo furtka update --check` should now see the new tag, and `sudo furtka update` applies it without a reinstall.
docs: add changelog, contributor guide, release process, and runner setup
- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
everything shipped so far (installer webapp, drive scoring, base
archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
and the release workflow (bump changelog, commit, tag, push, create
Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
upcoming CI workflow actually executes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:23:48 +02:00
## First-time: find the current version
```bash
git describe --tags --abbrev=0
```
If the project is fresh and `git describe` fails, the next release is `26.0-alpha` .
## If the tag is wrong
Don't move published tags. Delete the release + tag, fix the problem, bump to the next number.
```bash
git tag -d 26.1-alpha
git push origin :refs/tags/26.1-alpha
# ... fix ...
git tag -a 26.2-alpha ...
```