Files
jellytau/build/build-release.html
T

581 lines
32 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="navy" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Build &amp; Release - JellyTau Documentation</title>
<!-- Custom HTML head -->
<meta name="description" content="Requirements, traceability, and architecture for the JellyTau Jellyfin client.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "navy";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('navy')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../index.html">Introduction</a></li><li class="chapter-item expanded affix "><li class="part-title">Requirements & Traceability</li><li class="chapter-item expanded "><a href="../requirements.html"><strong aria-hidden="true">1.</strong> Requirements Specification</a></li><li class="chapter-item expanded "><a href="../traceability.html"><strong aria-hidden="true">2.</strong> Traceability Matrix</a></li><li class="chapter-item expanded "><a href="../traceability-ci.html"><strong aria-hidden="true">3.</strong> Traceability CI</a></li><li class="chapter-item expanded "><a href="../traces-quick-ref.html"><strong aria-hidden="true">4.</strong> Traces Quick Reference</a></li><li class="chapter-item expanded affix "><li class="part-title">Architecture</li><li class="chapter-item expanded "><a href="../architecture/index.html"><strong aria-hidden="true">5.</strong> Overview</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../architecture/01-rust-backend.html"><strong aria-hidden="true">5.1.</strong> Rust Backend</a></li><li class="chapter-item "><a href="../architecture/02-svelte-frontend.html"><strong aria-hidden="true">5.2.</strong> Svelte Frontend</a></li><li class="chapter-item "><a href="../architecture/03-data-flow.html"><strong aria-hidden="true">5.3.</strong> Data Flow</a></li><li class="chapter-item "><a href="../architecture/04-type-sync-and-threading.html"><strong aria-hidden="true">5.4.</strong> Type Sync & Threading</a></li><li class="chapter-item "><a href="../architecture/05-platform-backends.html"><strong aria-hidden="true">5.5.</strong> Platform Backends</a></li><li class="chapter-item "><a href="../architecture/06-downloads-and-offline.html"><strong aria-hidden="true">5.6.</strong> Downloads & Offline</a></li><li class="chapter-item "><a href="../architecture/07-connectivity.html"><strong aria-hidden="true">5.7.</strong> Connectivity</a></li><li class="chapter-item "><a href="../architecture/08-database-design.html"><strong aria-hidden="true">5.8.</strong> Database Design</a></li><li class="chapter-item "><a href="../architecture/09-security.html"><strong aria-hidden="true">5.9.</strong> Security</a></li></ol></li><li class="chapter-item expanded "><li class="part-title">UX</li><li class="chapter-item expanded "><a href="../ux-flows.html"><strong aria-hidden="true">6.</strong> UX Flows</a></li><li class="chapter-item expanded affix "><li class="part-title">Specs — Pending Work</li><li class="chapter-item expanded "><a href="../specs/index.html"><strong aria-hidden="true">7.</strong> Specs Index</a></li><li class="chapter-item expanded "><a href="../specs/SPEC-TEMPLATE.html"><strong aria-hidden="true">8.</strong> Spec Template</a></li><li class="chapter-item expanded "><a href="../specs/SPEC-REVIEW-CHECKLIST.html"><strong aria-hidden="true">9.</strong> Spec Review Checklist</a></li><li class="chapter-item expanded "><a href="../specs/playback-backend-unification.html"><strong aria-hidden="true">10.</strong> Playback Backend Unification</a></li><li class="chapter-item expanded "><a href="../specs/linux-native-video-spike.html"><strong aria-hidden="true">11.</strong> Linux Native Video Spike</a></li><li class="chapter-item expanded "><a href="../specs/backend-owned-stream-selection.html"><strong aria-hidden="true">12.</strong> Backend-Owned Stream Selection</a></li><li class="chapter-item expanded "><a href="../specs/player-facade-enforcement.html"><strong aria-hidden="true">13.</strong> Player Facade Enforcement</a></li><li class="chapter-item expanded "><a href="../specs/windows-native-audio-backend.html"><strong aria-hidden="true">14.</strong> Windows Native Audio Backend</a></li><li class="chapter-item expanded "><a href="../specs/libmpv2-migration.html"><strong aria-hidden="true">15.</strong> libmpv2 Migration</a></li><li class="chapter-item expanded "><a href="../specs/read-through-media-cache.html"><strong aria-hidden="true">16.</strong> Read-Through Media Cache</a></li><li class="chapter-item expanded "><a href="../specs/scoped-search.html"><strong aria-hidden="true">17.</strong> Scoped Search</a></li><li class="chapter-item expanded "><a href="../specs/scoped-search-boundary.html"><strong aria-hidden="true">18.</strong> Scoped Search Boundary</a></li><li class="chapter-item expanded "><a href="../specs/scoped-search-boundary-implementation.html"><strong aria-hidden="true">19.</strong> Scoped Search Boundary — Implementation</a></li><li class="chapter-item expanded "><a href="../specs/frontend-domain-model.html"><strong aria-hidden="true">20.</strong> Frontend Domain Model</a></li><li class="chapter-item expanded "><a href="../specs/desktop-native-video.html"><strong aria-hidden="true">21.</strong> Desktop Native Video</a></li><li class="chapter-item expanded "><a href="../specs/build-provenance.html"><strong aria-hidden="true">22.</strong> Build Provenance</a></li><li class="chapter-item expanded affix "><li class="part-title">Build & Release</li><li class="chapter-item expanded "><a href="../build/build-release.html" class="active"><strong aria-hidden="true">23.</strong> Build & Release</a></li><li class="chapter-item expanded "><a href="../release-checklist.html"><strong aria-hidden="true">24.</strong> Release Checklist</a></li><li class="chapter-item expanded "><a href="../native-player-verification.html"><strong aria-hidden="true">25.</strong> Native Player Verification</a></li><li class="chapter-item expanded "><a href="../build/build-desktop-packages.html"><strong aria-hidden="true">26.</strong> Desktop Packaging</a></li><li class="chapter-item expanded "><a href="../build/build-windows.html"><strong aria-hidden="true">27.</strong> Windows Build</a></li><li class="chapter-item expanded "><a href="../defect-windows.html"><strong aria-hidden="true">28.</strong> Defect Windows</a></li><li class="chapter-item expanded "><a href="../build/docker.html"><strong aria-hidden="true">29.</strong> Docker</a></li><li class="chapter-item expanded "><a href="../build/build-builder-image.html"><strong aria-hidden="true">30.</strong> Builder Image</a></li><li class="chapter-item expanded affix "><li class="spacer"></li><li class="chapter-item expanded affix "><a href="../api-redirect.html">Rust API Reference (rustdoc)</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">JellyTau Documentation</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://gitea.tourolle.paris/dtourolle/jellytau" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://gitea.tourolle.paris/dtourolle/jellytau/_edit/master/docs/../docs/build/build-release.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="build--release-workflow"><a class="header" href="#build--release-workflow">Build &amp; Release Workflow</a></h1>
<p>This document explains the automated build and release process for JellyTau.</p>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>The CI/CD pipeline automatically:</p>
<ol>
<li>✅ Runs all tests (frontend + Rust)</li>
<li>✅ Builds Linux binaries (AppImage + DEB)</li>
<li>✅ Builds Android APK and AAB</li>
<li>✅ Creates releases with artifacts</li>
<li>✅ Tags releases with version numbers</li>
</ol>
<h2 id="workflow-triggers"><a class="header" href="#workflow-triggers">Workflow Triggers</a></h2>
<h3 id="automatic-trigger"><a class="header" href="#automatic-trigger">Automatic Trigger</a></h3>
<p>When you push a version tag:</p>
<pre><code class="language-bash">git tag v1.0.0
git push origin v1.0.0
</code></pre>
<p>The workflow automatically:</p>
<ol>
<li>Runs tests</li>
<li>Builds both platforms</li>
<li>Creates a GitHub release with artifacts</li>
<li>Tags it as release/prerelease based on version</li>
</ol>
<h3 id="manual-trigger"><a class="header" href="#manual-trigger">Manual Trigger</a></h3>
<p>In Gitea Actions UI:</p>
<ol>
<li>Go to <strong>Actions</strong> tab</li>
<li>Click <strong>Build &amp; Release</strong> workflow</li>
<li>Click <strong>Run workflow</strong></li>
<li>Optionally specify a version</li>
<li>Workflow runs without creating a release</li>
</ol>
<h2 id="version-tagging"><a class="header" href="#version-tagging">Version Tagging</a></h2>
<h3 id="format"><a class="header" href="#format">Format</a></h3>
<p>Version tags follow semantic versioning: <code>v{MAJOR}.{MINOR}.{PATCH}</code></p>
<p>Examples:</p>
<ul>
<li><code>v1.0.0</code> - Release version</li>
<li><code>v1.0.0-rc1</code> - Release candidate (marked as prerelease)</li>
<li><code>v1.0.0-beta</code> - Beta version (marked as prerelease)</li>
<li><code>v0.1.0-alpha</code> - Alpha version (marked as prerelease)</li>
</ul>
<h3 id="creating-a-release"><a class="header" href="#creating-a-release">Creating a Release</a></h3>
<pre><code class="language-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
</code></pre>
<h3 id="release-status"><a class="header" href="#release-status">Release Status</a></h3>
<p>Versions containing <code>rc</code>, <code>beta</code>, or <code>alpha</code> are marked as <strong>prerelease</strong>:</p>
<pre><code class="language-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
</code></pre>
<h2 id="workflow-steps"><a class="header" href="#workflow-steps">Workflow Steps</a></h2>
<h3 id="1-test-phase"><a class="header" href="#1-test-phase">1. Test Phase</a></h3>
<p>Runs on all tags and manual triggers:</p>
<ul>
<li>Frontend tests (<code>vitest</code>)</li>
<li>Rust tests (<code>cargo test</code>)</li>
<li>TypeScript type checking</li>
</ul>
<p><strong>Failure:</strong> Stops workflow, no build/release</p>
<h3 id="2-build-linux-phase"><a class="header" href="#2-build-linux-phase">2. Build Linux Phase</a></h3>
<p>Runs after tests pass:</p>
<ul>
<li>Installs system dependencies</li>
<li>Builds with Tauri</li>
<li>Generates:
<ul>
<li><strong>AppImage</strong> - Universal Linux binary</li>
<li><strong>DEB</strong> - Debian/Ubuntu package</li>
</ul>
</li>
</ul>
<p><strong>Output:</strong> <code>artifacts/linux/</code></p>
<h3 id="3-build-android-phase"><a class="header" href="#3-build-android-phase">3. Build Android Phase</a></h3>
<p>Runs in parallel with Linux build:</p>
<ul>
<li>Installs Android SDK/NDK</li>
<li>Configures Rust for Android targets</li>
<li>Builds with Tauri</li>
<li>Generates:
<ul>
<li><strong>APK</strong> - Android app package (installable)</li>
<li><strong>AAB</strong> - Android App Bundle (for Play Store)</li>
</ul>
</li>
</ul>
<p><strong>Output:</strong> <code>artifacts/android/</code></p>
<h3 id="4-create-release-phase"><a class="header" href="#4-create-release-phase">4. Create Release Phase</a></h3>
<p>Runs after both builds succeed (only on version tags):</p>
<ul>
<li>Prepares release notes</li>
<li>Downloads build artifacts</li>
<li>Creates GitHub/Gitea release</li>
<li>Uploads all artifacts</li>
<li>Tags as prerelease if applicable</li>
</ul>
<h2 id="artifacts"><a class="header" href="#artifacts">Artifacts</a></h2>
<h3 id="linux-artifacts"><a class="header" href="#linux-artifacts">Linux Artifacts</a></h3>
<h4 id="appimage"><a class="header" href="#appimage">AppImage</a></h4>
<ul>
<li><strong>File:</strong> <code>jellytau_*.AppImage</code></li>
<li><strong>Size:</strong> ~100-150 MB</li>
<li><strong>Use:</strong> Run directly on any Linux distro</li>
<li><strong>Installation:</strong>
<pre><code class="language-bash">chmod +x JellyTau_*.AppImage
./JellyTau_*.AppImage
</code></pre>
</li>
</ul>
<h4 id="deb-package"><a class="header" href="#deb-package">DEB Package</a></h4>
<ul>
<li><strong>File:</strong> <code>JellyTau_*.deb</code></li>
<li><strong>Size:</strong> ~80-120 MB</li>
<li><strong>Use:</strong> Install on Debian/Ubuntu/similar</li>
<li><strong>Installation:</strong>
<pre><code class="language-bash">sudo dpkg -i JellyTau_*.deb
jellytau
</code></pre>
</li>
<li><strong>Note:</strong> the Debian package is named <code>jelly-tau</code> (Tauri kebab-cases
<code>productName</code>), while the command stays <code>jellytau</code>. The package declares
<code>Replaces</code>/<code>Conflicts</code>/<code>Provides: jellytau</code>, so upgrading from a release built
before the rename replaces it rather than installing a second copy.</li>
</ul>
<h4 id="rpm-package"><a class="header" href="#rpm-package">RPM Package</a></h4>
<ul>
<li><strong>File:</strong> <code>JellyTau-*.rpm</code></li>
<li><strong>Use:</strong> Install on Fedora/openSUSE/similar</li>
<li><strong>Installation:</strong>
<pre><code class="language-bash">sudo rpm -i JellyTau-*.rpm
jellytau
</code></pre>
</li>
</ul>
<h3 id="android-artifacts"><a class="header" href="#android-artifacts">Android Artifacts</a></h3>
<h4 id="apk"><a class="header" href="#apk">APK</a></h4>
<ul>
<li><strong>File:</strong> <code>jellytau-release.apk</code></li>
<li><strong>Size:</strong> ~60-100 MB</li>
<li><strong>Use:</strong> Direct installation on Android devices</li>
<li><strong>Installation:</strong>
<pre><code class="language-bash">adb install jellytau-release.apk
# Or sideload via file manager
</code></pre>
</li>
</ul>
<h4 id="aab-android-app-bundle"><a class="header" href="#aab-android-app-bundle">AAB (Android App Bundle)</a></h4>
<ul>
<li><strong>File:</strong> <code>jellytau-release.aab</code></li>
<li><strong>Size:</strong> ~50-90 MB</li>
<li><strong>Use:</strong> Upload to Google Play Console</li>
<li><strong>Note:</strong> Cannot be installed directly; for Play Store distribution</li>
</ul>
<h2 id="release-notes"><a class="header" href="#release-notes">Release Notes</a></h2>
<p>Release notes are automatically generated with:</p>
<ul>
<li>Version number</li>
<li>Download links</li>
<li>Installation instructions</li>
<li>System requirements</li>
<li>Known issues link</li>
<li>Changelog reference</li>
</ul>
<h2 id="build-matrix"><a class="header" href="#build-matrix">Build Matrix</a></h2>
<div class="table-wrapper"><table><thead><tr><th>Platform</th><th>OS</th><th>Architecture</th><th>Format</th></tr></thead><tbody>
<tr><td><strong>Linux</strong></td><td>Any</td><td>x86_64</td><td>AppImage, DEB</td></tr>
<tr><td><strong>Android</strong></td><td>8.0+</td><td>arm64, armv7, x86_64</td><td>APK, AAB</td></tr>
</tbody></table>
</div>
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
<h3 id="build-fails-during-test-phase"><a class="header" href="#build-fails-during-test-phase">Build Fails During Test Phase</a></h3>
<ol>
<li>Check test output in Gitea Actions</li>
<li>Run tests locally: <code>bun run test</code> and <code>bun run test:rust</code></li>
<li>Fix failing tests</li>
<li>Create new tag with fixed code</li>
</ol>
<h3 id="linux-build-fails"><a class="header" href="#linux-build-fails">Linux Build Fails</a></h3>
<ol>
<li>Check system dependencies installed</li>
<li>Verify Tauri configuration</li>
<li>Check cargo dependencies</li>
<li>Clear cache: Delete <code>.cargo</code> and <code>target/</code> directories</li>
</ol>
<h3 id="android-build-fails"><a class="header" href="#android-build-fails">Android Build Fails</a></h3>
<ol>
<li>Check Android SDK/NDK setup</li>
<li>Verify Java 17 is installed</li>
<li>Check Rust Android targets: <code>rustup target list</code></li>
<li>Clear cache and rebuild</li>
</ol>
<h3 id="release-not-created"><a class="header" href="#release-not-created">Release Not Created</a></h3>
<ol>
<li>Tag must start with <code>v</code> (e.g., <code>v1.0.0</code>)</li>
<li>Tests must pass</li>
<li>Both builds must succeed</li>
<li>Check workflow logs for errors</li>
</ol>
<h2 id="github-release-vs-gitea"><a class="header" href="#github-release-vs-gitea">GitHub Release vs Gitea</a></h2>
<p>The workflow uses GitHub Actions SDK but is designed for Gitea. For Gitea-native releases:</p>
<ol>
<li>Workflow creates artifacts</li>
<li>Artifacts are available in Actions artifacts</li>
<li>Download and manually create Gitea release, or</li>
<li>Set up Gitea API integration to auto-publish</li>
</ol>
<h2 id="customization"><a class="header" href="#customization">Customization</a></h2>
<h3 id="change-release-notes-template"><a class="header" href="#change-release-notes-template">Change Release Notes Template</a></h3>
<p>Edit <code>.gitea/workflows/build-release.yml</code>, section <code>Prepare release notes</code>:</p>
<pre><code class="language-yaml">- name: Prepare release notes
id: release_notes
run: |
# Add your custom release notes format here
echo "Custom notes" &gt; release_notes.md
</code></pre>
<h3 id="add-new-platforms"><a class="header" href="#add-new-platforms">Add New Platforms</a></h3>
<p>To add macOS or Windows builds:</p>
<ol>
<li>Add new <code>build-{platform}</code> job</li>
<li>Set appropriate <code>runs-on</code> runner</li>
<li>Add platform-specific dependencies</li>
<li>Update artifact upload</li>
<li>Include in <code>needs: [build-linux, build-android, build-{platform}]</code></li>
</ol>
<h3 id="change-build-targets"><a class="header" href="#change-build-targets">Change Build Targets</a></h3>
<p>Modify Tauri configuration or add targets:</p>
<pre><code class="language-yaml">- name: Build for Linux
run: |
# Add target specification
bun run tauri build -- --target x86_64-unknown-linux-gnu
</code></pre>
<h2 id="monitoring"><a class="header" href="#monitoring">Monitoring</a></h2>
<h3 id="check-status"><a class="header" href="#check-status">Check Status</a></h3>
<ol>
<li>Go to <strong>Actions</strong> tab in Gitea</li>
<li>View <strong>Build &amp; Release</strong> workflow runs</li>
<li>Click specific run to see logs</li>
</ol>
<h3 id="notifications"><a class="header" href="#notifications">Notifications</a></h3>
<p>Set up notifications for:</p>
<ul>
<li>Build failures</li>
<li>Release creation</li>
<li>Tag pushes</li>
</ul>
<h2 id="performance"><a class="header" href="#performance">Performance</a></h2>
<h3 id="build-times-approximate"><a class="header" href="#build-times-approximate">Build Times (Approximate)</a></h3>
<ul>
<li>Test phase: 5-10 minutes</li>
<li>Linux build: 10-15 minutes</li>
<li>Android build: 15-20 minutes</li>
<li>Total: 30-45 minutes</li>
</ul>
<h3 id="caching"><a class="header" href="#caching">Caching</a></h3>
<p>Workflow caches:</p>
<ul>
<li>Rust dependencies (cargo)</li>
<li>Bun node_modules</li>
<li>Android SDK components</li>
</ul>
<h2 id="security"><a class="header" href="#security">Security</a></h2>
<h3 id="secrets"><a class="header" href="#secrets">Secrets</a></h3>
<p>The workflow uses:</p>
<ul>
<li><code>GITHUB_TOKEN</code> - Built-in, no setup needed</li>
<li>No credentials needed for Gitea</li>
</ul>
<h3 id="verification"><a class="header" href="#verification">Verification</a></h3>
<p>To verify build integrity:</p>
<ol>
<li>Download artifacts</li>
<li>Verify signatures (if implemented)</li>
<li>Check file hashes</li>
<li>Test on target platform</li>
</ol>
<h2 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h2>
<h3 id="versioning"><a class="header" href="#versioning">Versioning</a></h3>
<ol>
<li>Follow semantic versioning: <code>v{MAJOR}.{MINOR}.{PATCH}</code></li>
<li>Tag releases in git</li>
<li>Update CHANGELOG.md before tagging</li>
<li>Include release notes in tag message</li>
</ol>
<h3 id="testing-before-release"><a class="header" href="#testing-before-release">Testing Before Release</a></h3>
<pre><code class="language-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
</code></pre>
<h3 id="documentation"><a class="header" href="#documentation">Documentation</a></h3>
<ol>
<li>Update <a href="../../CHANGELOG.html">CHANGELOG.md</a> with changes</li>
<li>Update <a href="../../README.html">README.md</a> with new features</li>
<li>Document breaking changes</li>
<li>Add migration guide if needed</li>
</ol>
<h2 id="example-release-workflow"><a class="header" href="#example-release-workflow">Example Release Workflow</a></h2>
<pre><code class="language-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
</code></pre>
<h2 id="references"><a class="header" href="#references">References</a></h2>
<ul>
<li><a href="https://tauri.app/">Tauri Documentation</a></li>
<li><a href="https://semver.org/">Semantic Versioning</a></li>
<li><a href="https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases">GitHub Release Best Practices</a></li>
<li><a href="https://developer.android.com/guide/app-bundle">Android App Bundle</a></li>
<li><a href="https://docs.appimage.org/">AppImage Documentation</a></li>
</ul>
<hr />
<p><strong>Last Updated:</strong> 2026-02-13</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../specs/build-provenance.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release-checklist.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../specs/build-provenance.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release-checklist.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>