docs: move the root-level build docs under docs/build/

build-release.md, build-desktop-packages.md and build-windows.md sat at
the docs/ root while docker.md and build-builder-image.md were already in
docs/build/, so "where do build docs live" had two answers. They now have
one.

Referrers updated: README.md, docs-site/SUMMARY.md, and the ../ links
inside the moved files themselves, which each gained a level of depth —
Dockerfile, Dockerfile.arch, packaging/arch/PKGBUILD, CHANGELOG.md,
README.md, src-tauri/src/lib.rs and src/lib/services/webviewAudio.ts.
Every one of those was caught by check-doc-links.sh rather than by
reading, which is the point of having it.

Two referrers are left for their owners: CLAUDE.md line 173 and the
comment at scripts/build-windows-cross.sh line 11.
This commit is contained in:
2026-08-20 19:32:04 +02:00
parent 3b55810a0e
commit 2de91ae76c
5 changed files with 15 additions and 15 deletions
+91
View File
@@ -0,0 +1,91 @@
# Desktop packaging (Linux, Arch, Windows)
How to produce distributable desktop packages for JellyTau. All three flows can
run in Docker so no host toolchain setup is required. Outputs land in `./dist`.
## One builder image (shared with CI)
The deb/rpm and Windows-cross flows build on the **unified registry builder**
([../Dockerfile.builder](../../Dockerfile.builder) →
`gitea.tourolle.paris/dtourolle/jellytau-builder`), the same image CI uses. It
carries every packaging tool: Android SDK/NDK, `rpm`/`file` (Linux bundler),
`cargo-xwin` + `lld` + `llvm` + `nsis` + the `x86_64-pc-windows-msvc` rust target
(Windows). There is **one** dependency source of truth — no per-stage tool
installs.
The desktop stages in [../Dockerfile](../../Dockerfile) are thin `FROM
${BUILDER_IMAGE}` environments; the actual build runs at container-run time on
your bind-mounted source (like the `dev` service), so source edits need no image
rebuild.
**If you changed `Dockerfile.builder`** (e.g. added a tool), rebuild and push it
first, or the packaging flows use the stale registry image:
```bash
scripts/build-builder-image.sh # build + push :latest to the registry
# ...or iterate locally without pushing:
docker build -f Dockerfile.builder -t jellytau-builder:latest .
BUILDER_IMAGE=jellytau-builder:latest bun run docker:build:windows
```
Arch uses a separate `archlinux` image ([../Dockerfile.arch](../../Dockerfile.arch))
because `makepkg` is Arch-specific — it is not part of the unified builder.
| Target | Format | Docker command | Functional? |
|--------|--------|----------------|-------------|
| Debian/Ubuntu, Fedora | `.deb`, `.rpm` | `bun run docker:build:linux` | ✅ yes |
| Arch Linux | `.pkg.tar.zst` | `bun run docker:build:arch` | ✅ yes |
| Windows | NSIS installer + `.exe` | `bun run docker:build:windows` | ✅ yes (unsigned) |
## Linux: deb + rpm
Tauri's bundler produces these natively. The build runs on the existing Ubuntu
builder image ([../Dockerfile](../../Dockerfile), `desktop-linux-build` stage):
```bash
bun run docker:build:linux # deb + rpm -> ./dist
# or, on a host with the Tauri Linux deps installed:
BUNDLES="deb,rpm" scripts/build-desktop-linux.sh
```
Runtime dependency: the app links libmpv (audio) and WebKitGTK (webview + HTML5
transcoded video). The deb/rpm declare these.
> Note: `appimage` is also a valid Tauri target if you want a portable bundle —
> add it to `BUNDLES`.
## Arch Linux: pacman package
**Tauri has no `pacman` bundle target** (as of tauri-cli 2.9.x — valid targets
are deb/rpm/appimage/msi/nsis/app/dmg). So we ship a hand-written PKGBUILD in
[../packaging/arch/PKGBUILD](../../packaging/arch/PKGBUILD) and build it with
`makepkg` on an Arch base image ([../Dockerfile.arch](../../Dockerfile.arch)):
```bash
bun run docker:build:arch # .pkg.tar.zst -> ./dist
```
The PKGBUILD is AUR-ready: swap its `source=()` for a release tarball/VCS URL to
publish. Runtime deps: `webkit2gtk-4.1`, `mpv`, `gtk3`, `libayatana-appindicator`.
`makepkg` refuses to run as root, so the Docker stage builds as a non-root
`builder` user. Because the image `COPY`s the source at build time, the
`arch-build` compose service does **not** bind-mount the repo — rebuild the image
to pick up source changes.
## Windows: NSIS installer cross-compiled from Linux
Produces a working (unsigned) NSIS installer + `.exe` via the official Tauri
cross-compile path — the `x86_64-pc-windows-msvc` target driven by `cargo-xwin`.
Video plays via WebView2 and audio via the webview `<audio>` backend. See
[build-windows.md](build-windows.md) for the full explanation.
```bash
bun run docker:build:windows # NSIS installer + .exe -> ./dist
WIN_BUNDLES=none bun run docker:build:windows # exe only, skip bundling
```
The Docker `windows-cross` stage is a thin layer over the builder, which carries
`cargo-xwin` + `lld` + `llvm` + `nsis` + the `x86_64-pc-windows-msvc` target.
Cross-compilation is Tauri's "last resort" path (less tested than building on
Windows); a `windows-latest` CI job is the fallback if it misbehaves.
+347
View File
@@ -0,0 +1,347 @@
# Build & Release Workflow
This document explains the automated build and release process for JellyTau.
## Overview
The CI/CD pipeline automatically:
1. ✅ Runs all tests (frontend + Rust)
2. ✅ Builds Linux binaries (AppImage + DEB)
3. ✅ Builds Android APK and AAB
4. ✅ Creates releases with artifacts
5. ✅ Tags releases with version numbers
## Workflow Triggers
### Automatic Trigger
When you push a version tag:
```bash
git tag v1.0.0
git push origin v1.0.0
```
The workflow automatically:
1. Runs tests
2. Builds both platforms
3. Creates a GitHub release with artifacts
4. Tags it as release/prerelease based on version
### Manual Trigger
In Gitea Actions UI:
1. Go to **Actions** tab
2. Click **Build & Release** workflow
3. Click **Run workflow**
4. Optionally specify a version
5. Workflow runs without creating a release
## Version Tagging
### Format
Version tags follow semantic versioning: `v{MAJOR}.{MINOR}.{PATCH}`
Examples:
- `v1.0.0` - Release version
- `v1.0.0-rc1` - Release candidate (marked as prerelease)
- `v1.0.0-beta` - Beta version (marked as prerelease)
- `v0.1.0-alpha` - Alpha version (marked as prerelease)
### Creating a Release
```bash
# Create and push a version tag
git tag v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
# Or create from main branch
git tag -a v1.0.0 -m "Release version 1.0.0" main
git push origin v1.0.0
```
### Release Status
Versions containing `rc`, `beta`, or `alpha` are marked as **prerelease**:
```bash
git tag v1.0.0-rc1 # ⚠️ Prerelease
git tag v1.0.0-beta # ⚠️ Prerelease
git tag v1.0.0-alpha # ⚠️ Prerelease
git tag v1.0.0 # ✅ Full release
```
## Workflow Steps
### 1. Test Phase
Runs on all tags and manual triggers:
- Frontend tests (`vitest`)
- Rust tests (`cargo test`)
- TypeScript type checking
**Failure:** Stops workflow, no build/release
### 2. Build Linux Phase
Runs after tests pass:
- Installs system dependencies
- Builds with Tauri
- Generates:
- **AppImage** - Universal Linux binary
- **DEB** - Debian/Ubuntu package
**Output:** `artifacts/linux/`
### 3. Build Android Phase
Runs in parallel with Linux build:
- Installs Android SDK/NDK
- Configures Rust for Android targets
- Builds with Tauri
- Generates:
- **APK** - Android app package (installable)
- **AAB** - Android App Bundle (for Play Store)
**Output:** `artifacts/android/`
### 4. Create Release Phase
Runs after both builds succeed (only on version tags):
- Prepares release notes
- Downloads build artifacts
- Creates GitHub/Gitea release
- Uploads all artifacts
- Tags as prerelease if applicable
## Artifacts
### Linux Artifacts
#### AppImage
- **File:** `jellytau_*.AppImage`
- **Size:** ~100-150 MB
- **Use:** Run directly on any Linux distro
- **Installation:**
```bash
chmod +x jellytau_*.AppImage
./jellytau_*.AppImage
```
#### DEB Package
- **File:** `jellytau_*.deb`
- **Size:** ~80-120 MB
- **Use:** Install on Debian/Ubuntu/similar
- **Installation:**
```bash
sudo dpkg -i jellytau_*.deb
jellytau
```
### Android Artifacts
#### APK
- **File:** `jellytau-release.apk`
- **Size:** ~60-100 MB
- **Use:** Direct installation on Android devices
- **Installation:**
```bash
adb install jellytau-release.apk
# Or sideload via file manager
```
#### AAB (Android App Bundle)
- **File:** `jellytau-release.aab`
- **Size:** ~50-90 MB
- **Use:** Upload to Google Play Console
- **Note:** Cannot be installed directly; for Play Store distribution
## Release Notes
Release notes are automatically generated with:
- Version number
- Download links
- Installation instructions
- System requirements
- Known issues link
- Changelog reference
## Build Matrix
| Platform | OS | Architecture | Format |
|----------|----|----|--------|
| **Linux** | Any | x86_64 | AppImage, DEB |
| **Android** | 8.0+ | arm64, armv7, x86_64 | APK, AAB |
## Troubleshooting
### Build Fails During Test Phase
1. Check test output in Gitea Actions
2. Run tests locally: `bun run test` and `bun run test:rust`
3. Fix failing tests
4. Create new tag with fixed code
### Linux Build Fails
1. Check system dependencies installed
2. Verify Tauri configuration
3. Check cargo dependencies
4. Clear cache: Delete `.cargo` and `target/` directories
### Android Build Fails
1. Check Android SDK/NDK setup
2. Verify Java 17 is installed
3. Check Rust Android targets: `rustup target list`
4. Clear cache and rebuild
### Release Not Created
1. Tag must start with `v` (e.g., `v1.0.0`)
2. Tests must pass
3. Both builds must succeed
4. Check workflow logs for errors
## GitHub Release vs Gitea
The workflow uses GitHub Actions SDK but is designed for Gitea. For Gitea-native releases:
1. Workflow creates artifacts
2. Artifacts are available in Actions artifacts
3. Download and manually create Gitea release, or
4. Set up Gitea API integration to auto-publish
## Customization
### Change Release Notes Template
Edit `.gitea/workflows/build-release.yml`, section `Prepare release notes`:
```yaml
- name: Prepare release notes
id: release_notes
run: |
# Add your custom release notes format here
echo "Custom notes" > release_notes.md
```
### Add New Platforms
To add macOS or Windows builds:
1. Add new `build-{platform}` job
2. Set appropriate `runs-on` runner
3. Add platform-specific dependencies
4. Update artifact upload
5. Include in `needs: [build-linux, build-android, build-{platform}]`
### Change Build Targets
Modify Tauri configuration or add targets:
```yaml
- name: Build for Linux
run: |
# Add target specification
bun run tauri build -- --target x86_64-unknown-linux-gnu
```
## Monitoring
### Check Status
1. Go to **Actions** tab in Gitea
2. View **Build & Release** workflow runs
3. Click specific run to see logs
### Notifications
Set up notifications for:
- Build failures
- Release creation
- Tag pushes
## Performance
### Build Times (Approximate)
- Test phase: 5-10 minutes
- Linux build: 10-15 minutes
- Android build: 15-20 minutes
- Total: 30-45 minutes
### Caching
Workflow caches:
- Rust dependencies (cargo)
- Bun node_modules
- Android SDK components
## Security
### Secrets
The workflow uses:
- `GITHUB_TOKEN` - Built-in, no setup needed
- No credentials needed for Gitea
### Verification
To verify build integrity:
1. Download artifacts
2. Verify signatures (if implemented)
3. Check file hashes
4. Test on target platform
## Best Practices
### Versioning
1. Follow semantic versioning: `v{MAJOR}.{MINOR}.{PATCH}`
2. Tag releases in git
3. Update CHANGELOG.md before tagging
4. Include release notes in tag message
### Testing Before Release
```bash
# Local testing before release
bun run test # Frontend tests
bun run test:rust # Rust tests
bun run check # Type checking
bun run tauri build # Local build test
```
### Documentation
1. Update [CHANGELOG.md](../../CHANGELOG.md) with changes
2. Update [README.md](../../README.md) with new features
3. Document breaking changes
4. Add migration guide if needed
## Example Release Workflow
```bash
# 1. Update version in relevant files (package.json, Cargo.toml, etc.)
vim package.json
vim src-tauri/tauri.conf.json
# 2. Update CHANGELOG
vim CHANGELOG.md
# 3. Commit changes
git add .
git commit -m "Bump version to v1.0.0"
# 4. Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0
Features:
- Feature 1
- Feature 2
Fixes:
- Fix 1
- Fix 2"
# 5. Push tag to trigger workflow
git push origin v1.0.0
# 6. Monitor workflow in Gitea Actions
# Wait for tests → Linux build → Android build → Release
# 7. Download artifacts and test
# Visit release page and verify downloads
```
## References
- [Tauri Documentation](https://tauri.app/)
- [Semantic Versioning](https://semver.org/)
- [GitHub Release Best Practices](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases)
- [Android App Bundle](https://developer.android.com/guide/app-bundle)
- [AppImage Documentation](https://docs.appimage.org/)
---
**Last Updated:** 2026-02-13
+78
View File
@@ -0,0 +1,78 @@
# Windows build
JellyTau targets Linux and Android primarily, but a working Windows build —
including an **NSIS installer cross-compiled from Linux** — is produced by the
Docker tooling. It is not yet a first-class release target (no code signing / CI
job / SMTC lockscreen), but it runs and plays media.
## How playback works on Windows
- **Video** — renders through the webview HTML5 `<video>` element (hls.js) on
*every* platform; on Windows that is WebView2 (Chromium/Edge), which plays HLS +
h264 fine. No Windows-specific code.
- **Audio-only (music)** — the native audio backends are libmpv (Linux) and
ExoPlayer (Android); neither exists on Windows. Instead
`create_player_backend()` in [../src-tauri/src/lib.rs](../../src-tauri/src/lib.rs)
uses `WebviewAudioBackend` on non-Linux/non-Android targets: it hands the stream
URL to a webview `<audio>` element (see
[../src/lib/services/webviewAudio.ts](../../src/lib/services/webviewAudio.ts)),
which reports state back through the same `player_report_*` round-trip the video
path uses. Pure Rust + Tauri events.
## Cross-compiling from Linux (MSVC + cargo-xwin)
We use the [official Tauri cross-compile path](https://v2.tauri.app/distribute/windows-installer/):
the **MSVC** target (`x86_64-pc-windows-msvc`) driven by
[`cargo-xwin`](https://github.com/rust-cross/cargo-xwin), which downloads the MSVC
CRT / Windows SDK headers and links with `lld`. MSVC is the target Tauri
officially supports for Windows (mingw/GNU is not), and — unlike GNU — it lets the
Tauri CLI bundle the **NSIS installer from a Linux host**.
> Why not mingw/GNU? The GNU target *does* link a valid `.exe`, but the Tauri CLI
> gates `--bundles` by the host OS unless it recognizes a real Windows build.
> `--runner cargo-xwin --target x86_64-pc-windows-msvc` is what flips it into
> Windows mode and enables the `nsis`/`msi` bundlers on Linux.
The builder image ([../Dockerfile.builder](../../Dockerfile.builder)) bakes in the
whole toolchain: the `x86_64-pc-windows-msvc` rust target, `cargo-xwin`, `lld`,
`llvm`, and `nsis`.
```bash
bun run docker:build:windows # NSIS installer + .exe -> ./dist
WIN_BUNDLES=none bun run docker:build:windows # exe only, skip bundling
```
Or directly on a host that has the toolchain:
```bash
scripts/build-windows-cross.sh # nsis installer + exe
WIN_BUNDLES=none scripts/build-windows-cross.sh # exe only
```
Under the hood the build runs:
```bash
tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis
```
Outputs:
- `.exe``src-tauri/target/x86_64-pc-windows-msvc/release/jellytau.exe`
- NSIS installer — `.../release/bundle/nsis/*-setup.exe`
(both copied to `./dist` when `OUTPUT_DIR` is set).
## Caveats
- **Cross-compilation is a last resort** per Tauri's own docs — it's less tested
than building on Windows. If it misbehaves, a `windows-latest` CI job or a
Windows VM building natively (`tauri build --bundles nsis`) is the fallback.
- **Code signing is not wired up** — the installer is unsigned, so Windows
SmartScreen will warn on first run.
## Outstanding for a first-class Windows release
1. Gapless/crossfade + SMTC (lockscreen) — currently no-ops in the webview audio
path.
2. Downloaded (`Local` source) file playback needs `convertFileSrc` on the
frontend; streaming works today.
3. Code signing + a Windows packaging CI job.