Anyone who installed an AppImage or ran the Windows installer was frozen
on that version forever. Nothing in the app ever mentioned a new release
existed, and the release notes were the only announcement.
Desktop now checks a signed manifest, shows the version and its notes in
Settings, and installs and relaunches on request. The signature check is
the whole point: it is what stops a substituted download from being
installed by the app itself. Windows binaries stay unsigned for
SmartScreen purposes -- that is a code-signing certificate, a separate
problem -- but the update payload is verified against our own key.
Android is deliberately not wired to the updater. An app may not replace
its own APK; that is the package installer's job, and the plugin has no
Android implementation. It gets a link to the releases page instead of a
button that would throw.
The plugins are gated with a target-triple cfg rather than
cfg(desktop). Cargo only evaluates target cfgs in a [target.'cfg(..)']
table, so cfg(desktop) matches nothing, silently drops the dependency,
and fails much later with "Permission updater:default not found" -- which
is exactly what the first attempt here did.
Where the manifest lives took some finding. This Gitea serves
/releases/download/<tag>/<asset> but 404s on
/releases/latest/download/<asset> (verified against a real asset), so
there is no stable latest-release URL. The gitea-pages branch is
force-pushed wholesale by publish-docs.yml, so it cannot host the file
either. latest.json therefore gets its own orphan branch, read over the
raw-file URL, and is published from a scratch repo in RUNNER_TEMP rather
than by switching branches in the checkout -- doing that would have left
the following steps standing on a one-commit history, and the next step
but one runs release:notes against the real commit range.
Also fixed, all of it release-integrity:
- "appimage" is in bundle.targets. The release notes have advertised an
AppImage for months; tauri.conf.json never built one, the artifact
step globbed for *.AppImage, found nothing, and said nothing. The
step now fails instead.
- The .AppImage.tar.gz/.sig pair and the NSIS .sig are collected. A
manifest referencing a signature that was never uploaded fails only
on the user's machine, so the manifest step also refuses to write an
entry with an empty signature.
- Release notes are generated by release:notes from the traceability
graph, which is what CLAUDE.md has asked for all along, instead of a
fixed heredoc that said "see CHANGELOG.md for detailed changes" and
linked "GitHub Issues" on a Gitea-hosted project.
- The notes tell users how to verify a download with SHA256SUMS.
Requirements UR-077 / DR-217, tests UT-208 (12 cases over the version
comparison and the platform decision, including that a pre-release does
not offer itself as an upgrade to the matching release).
Verified: 1070 frontend tests, cargo check for both the host and
aarch64-linux-android (confirming the plugins are absent there), clippy
-D warnings, svelte-check 0 errors.
7.7 KiB
Release Checklist
Quick reference for creating a JellyTau release.
Pre-Release (1-2 days before)
- Code is on
master/mainbranch - All feature branches are merged and tested
- No failing tests locally:
bun run testandbun run test:rust - Requirement traceability check passes:
bun run traces:json - Type checking passes:
bun run check
Update Version (Day before)
-
Decide on version number (semantic versioning)
- Example:
v1.2.0(major.minor.patch) - Example:
v1.0.0-rc1(release candidate) - Example:
v1.0.0-beta(beta)
- Example:
-
Update version in files:
# Check these files for version numbers cat package.json | grep version cat src-tauri/tauri.conf.json | grep version cat src-tauri/Cargo.toml | grep version -
Update
CHANGELOG.md:- Add section for new version
- List all features added
- List all bugs fixed
- List breaking changes (if any)
- Add upgrade instructions (if needed)
- Format: Markdown with clear sections
-
Update
README.md:- Update any version references
- Update feature list if applicable
- Update requirements if changed
-
Commit changes:
git add . git commit -m "Bump version to v1.2.0" git push origin master
Final Check Before Release
-
Run full test suite:
bun run test # Frontend tests bun run test:rust # Rust tests bun run check # Type checking -
Build locally (optional but recommended):
# Test Linux build bun run tauri build # Test Android build bun run tauri android build -
No uncommitted changes:
git status # Should show clean working directory
Release (Tag & Push)
# 1. Create annotated tag with release notes
git tag -a v1.2.0 -m "Release version 1.2.0
Features:
- New feature 1
- New feature 2
Fixes:
- Fixed bug 1
- Fixed bug 2
Improvements:
- Performance improvement 1
- UI improvement 1
Breaking Changes:
- None (or list if applicable)
Migration:
- No action required (or include steps if applicable)"
# 2. Push tag to trigger workflow
git push origin v1.2.0
# 3. Monitor in Gitea Actions
# Go to Actions tab and watch the workflow run
During Release (While Workflow Runs)
- Watch workflow progress in Gitea Actions
- Monitor for test failures
- Monitor for build failures
- Check build logs if any step fails
After Release (Workflow Complete)
-
Download artifacts from release page:
JellyTau_*.AppImage(Linux)JellyTau_*.deb(Linux)JellyTau-*.rpm(Linux)jellytau-release.apk(Android)jellytau-release.aab(Android)
-
Basic testing of artifacts:
- Linux AppImage runs
- Linux DEB installs and runs
- Android APK installs (via
adbor sideload)
-
Verify release page:
- Title is correct: "JellyTau vX.Y.Z"
- Release notes are formatted correctly
- All artifacts are uploaded
- Release type is correct (prerelease vs release)
-
Verify integrity metadata (DR-216):
SHA256SUMSis present, andsha256sum -c SHA256SUMSpasses in the directory you downloaded into- SBOM files are present (
*.cdx.json,frontend-dependencies.txt)
-
Verify the update path (DR-217) — this is the step that catches a broken updater before users hit it, because a bad manifest fails only on their machine:
latest.jsonis live and names this version:curl -s https://gitea.tourolle.paris/dtourolle/jellytau/raw/branch/updater/latest.json | jq .version- Both platform entries carry a non-empty
signature - The
.AppImage.tar.gz, its.sig, and the NSIS.sigare among the release assets — the manifest points at them - Install the previous release, launch it, and use Settings → Updates: it should offer this version, install it, and relaunch
- On Android, Settings → Updates offers the releases page rather than an install button (the updater plugin is not compiled for that target)
-
Announce release:
- Post to relevant channels/communities
- Update website/docs
- Tag contributors if applicable
Rollback (If Issues Found)
If critical issues are found after release:
# Option 1: Delete tag locally and remotely
git tag -d v1.2.0
git push origin :refs/tags/v1.2.0
# Option 2: Mark as prerelease in release page
# Then plan immediate patch release (v1.2.1)
# Option 3: Create hotfix branch and release v1.2.1
git checkout -b hotfix/v1.2.1
# Fix issues
git commit -m "Fix critical issue"
git tag v1.2.1
git push origin hotfix/v1.2.1 v1.2.1
Version Examples
Major Release
v2.0.0 - Major version bump
- Significant new features
- Breaking API changes
- Major UI redesign
Minor Release
v1.2.0 - Feature release
- New features
- Backward compatible
- Bug fixes
Patch Release
v1.1.1 - Bug fix/patch
- Bug fixes only
- No new features
- Backward compatible
Pre-releases
v1.2.0-alpha - Early development
v1.2.0-beta - Late development, feature complete
v1.2.0-rc1 - Release candidate, minimal fixes only
File Locations
Key files for versioning:
package.json- Frontend versionsrc-tauri/tauri.conf.json- Tauri config versionsrc-tauri/Cargo.toml- Rust versionCHANGELOG.md- Release historyREADME.md- Project documentation
Troubleshooting
Tests Fail Before Release
- Don't push tag yet
- Fix failing tests locally
- Push fixes to master
- Re-run test suite
- Then tag and push
Build Fails in CI
- Check detailed logs in Gitea Actions
- Fix issue locally
- Delete tag:
git tag -d v1.2.0 && git push origin :refs/tags/v1.2.0 - Push fix to master
- Create new tag with fix
Release Already Exists
- If workflow runs twice, artifacts may conflict
- Check release page
- If duplicates exist, delete and re-release
Artifacts Missing
- Check build logs for errors
- Verify platform-specific dependencies
- Delete tag and retry after fixes
Performance Tips
- Tests: ~5-10 minutes
- Linux build: ~10-15 minutes
- Android build: ~15-20 minutes
- Total release time: ~30-45 minutes
First build takes longer (cache warming). Subsequent releases are faster due to caching.
Template: Release Notes
## 🎉 JellyTau vX.Y.Z
### ✨ Features
- New feature 1
- New feature 2
### 🐛 Bug Fixes
- Fixed issue #123
- Fixed issue #456
### 🚀 Performance
- Improvement 1
- Improvement 2
### 📱 Downloads
- [Linux AppImage](#) - Run on any Linux
- [Linux DEB](#) - Install on Ubuntu/Debian
- [Android APK](#) - Install on Android devices
- [Android AAB](#) - For Google Play Store
### 📋 Requirements
**Linux:** 64-bit, GLIBC 2.29+
**Android:** 8.0+
### 🔗 Links
- [Changelog](https://gitea.tourolle.paris/dtourolle/jellytau/src/branch/master/CHANGELOG.md)
- [Issues](https://gitea.tourolle.paris/dtourolle/jellytau/issues)
---
Built with Tauri, SvelteKit, and Rust 🦀
Quick Commands
# View existing tags
git tag -l
# Create release locally (dry run)
git tag -a v1.2.0 -m "Release v1.2.0" --dry-run
# List commits since last tag
git log v1.1.0..HEAD --oneline
# Show tag details
git show v1.2.0
# Rename tag (if needed)
git tag v1.2.0_old v1.2.0
git tag -d v1.2.0
git push origin v1.2.0_old v1.2.0
# Delete tag locally and remotely
git tag -d v1.2.0
git push origin :refs/tags/v1.2.0
Tips:
- ✅ Always test locally before release
- ✅ Use semantic versioning consistently
- ✅ Document changes in CHANGELOG
- ✅ Wait for full workflow completion
- ✅ Test release artifacts before announcing
Remember: A good release is a tested release! 🚀