Files

176 lines
5.9 KiB
Markdown

# Releasing the Sprout Desktop App
This guide covers the end-to-end process for releasing the Sprout desktop app,
including secrets setup, cutting releases, and troubleshooting.
---
## Prerequisites / Secrets Setup
The following GitHub repository secrets must be configured before the first
release:
| Secret | Description |
| ---------------------------------- | ------------------------------------------------------------------ |
| `SPROUT_RELAY_URL` | WebSocket relay URL baked into the release binary (for example `wss://...`) |
| `SPROUT_UPDATER_PUBLIC_KEY` | Tauri updater public key (generate with `pnpm tauri signer generate`) |
| `TAURI_SIGNING_PRIVATE_KEY` | Tauri updater private key |
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Password for the private key |
| `OSX_CODESIGN_ROLE` | IAM role ARN for Block's Apple codesigning service |
| `CODESIGN_S3_BUCKET` | S3 bucket for codesigning artifacts |
---
## Generating Tauri Updater Keys
```bash
cd desktop
pnpm tauri signer generate -w ~/.tauri/sprout.key
```
This generates a keypair:
- The **public key** goes in the `SPROUT_UPDATER_PUBLIC_KEY` secret.
- The **private key** goes in the `TAURI_SIGNING_PRIVATE_KEY` secret.
Store the password you chose in `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`.
---
## Cutting a Release
From any branch (typically `main`):
```bash
just desktop-release 0.3.0
```
Or equivalently:
```bash
git tag desktop/v0.3.0
git push origin desktop/v0.3.0
```
That's it. CI extracts the version from the tag and writes it into
`package.json`, `tauri.conf.json`, and `Cargo.toml` at build time. The
versions checked into the repo are not used for releases — the tag is the
source of truth.
### Verify
Check GitHub Releases for:
- The **versioned release** (e.g. `desktop/v0.3.0`)
- The **`sprout-desktop-latest` rolling release** (updated with every release)
---
## What CI Does
The `sprout-desktop-release.yml` workflow:
1. **Extracts the version** from the git tag once into `RELEASE_VERSION`.
2. **Sets the version** into `package.json`, `tauri.conf.json`, and
`Cargo.toml` using `set-version-from-tag.mjs`.
3. **Regenerates `Cargo.lock`** to match the patched `Cargo.toml`.
4. **Validates** all required secrets are present.
5. **Builds** the release config with the updater public key and endpoint.
6. **Builds** the Tauri app (unsigned).
7. **Signs and notarizes** the macOS bundle via `block/apple-codesign-action`.
8. **Re-packages** the signed app into a DMG and updater archive.
9. **Signs** the updater archive with the Tauri updater key.
10. **Publishes** the updater manifest (`latest.json`) to the rolling
`sprout-desktop-latest` release.
11. **Publishes** the DMG to both the versioned and rolling releases.
---
## Local Release Build (Testing)
Local builds will not be codesigned or notarized — that only happens in CI
via `block/apple-codesign-action`. Local builds are useful for testing the
updater runtime config and DMG packaging.
```bash
# Set updater env vars
export SPROUT_UPDATER_PUBLIC_KEY="your-public-key"
export SPROUT_UPDATER_ENDPOINT="https://github.com/block/sprout/releases/download/sprout-desktop-latest/latest.json"
# Generate release config
cd desktop
pnpm run tauri:release:config
# Build (unsigned) — pass a version to set it before building
just desktop-release-build version=0.3.0
```
You can also set the version separately without building:
```bash
just desktop-set-version 0.3.0
```
---
## Auto-Updates
The app uses `tauri-plugin-updater` to check for updates. The updater endpoint
is:
```
https://github.com/block/sprout/releases/download/sprout-desktop-latest/latest.json
```
This `latest.json` is updated on every release and contains the download URL
and signature for the latest version.
---
## Relay URL Configuration
The app connects to the relay via the `SPROUT_RELAY_URL` environment variable.
- **Production releases**: The GitHub release workflow builds the app with
`SPROUT_RELAY_URL` sourced from the `SPROUT_RELAY_URL` repository secret,
which is baked into the release binary as its default relay URL.
- **Local release builds**: Export `SPROUT_RELAY_URL` before running
`just desktop-release-build` if you want a non-localhost relay URL compiled
into the app.
- **Development**: If not set, it defaults to `ws://localhost:3000`.
---
## How Versioning Works
The git tag is the single source of truth for the release version. The version
fields in `package.json`, `tauri.conf.json`, and `Cargo.toml` on `main` are
**not** used for releases — CI overwrites them at build time from the tag.
This means the tagged commit will show a different version in its source files
than what the release actually contains. This is an accepted tradeoff — the tag
is the canonical version, the commit is just the code state at release time.
This is standard practice in ecosystems like Docker, Go, and Rust where the
tag drives the version.
---
## Troubleshooting
- **"Missing required desktop release secrets"**: Ensure all secrets listed in
[Prerequisites](#prerequisites--secrets-setup) are configured in GitHub repo
settings.
- **Codesigning failures**: Verify `OSX_CODESIGN_ROLE` and
`CODESIGN_S3_BUCKET` are configured correctly. Check the
`block/apple-codesign-action` step logs for details.
- **Build failures**: If versions are wrong, check that the tag follows the
format `desktop/v<semver>` (e.g. `desktop/v0.3.0`). CI extracts the version
from the tag automatically.
- **"A public key has been found, but no private key"**: The Tauri build should
not require `TAURI_SIGNING_PRIVATE_KEY`. If you see this, the build is trying
to generate updater artifacts before the signed app bundle exists. The updater
archive is supposed to be created and signed later from the notarized app.