name: Build App (Preview) # Builds the Tauri app for branches other than main and exposes the bundles as # workflow artifacts. No Gitea release, no GitHub sync — intended for local # smoke-testing of feature branches before they merge. on: push: branches-ignore: [main] paths: - "app/**" - "VERSION" - ".gitea/workflows/build-app-preview.yml" workflow_dispatch: jobs: compute-version: runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.VERSION }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Compute preview version id: version run: | MAJOR_MINOR=$(cat VERSION | tr -d '[:space:]') SHORT_SHA=$(git rev-parse --short HEAD) VERSION="${MAJOR_MINOR}.0-preview.${SHORT_SHA}" echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT echo "Computed preview version: ${VERSION}" build-linux: runs-on: ubuntu-latest needs: [compute-version] steps: - name: Install Node.js 22 run: | NEED_INSTALL=false if command -v node >/dev/null 2>&1; then NODE_MAJOR=$(node --version | sed 's/v\([0-9]*\).*/\1/') OLD_NODE_DIR=$(dirname "$(which node)") echo "Found Node.js $(node --version) at $(which node) (major: ${NODE_MAJOR})" if [ "$NODE_MAJOR" -lt 22 ]; then echo "Node.js ${NODE_MAJOR} is too old, removing before installing 22..." sudo rm -f "${OLD_NODE_DIR}/node" "${OLD_NODE_DIR}/npm" "${OLD_NODE_DIR}/npx" "${OLD_NODE_DIR}/corepack" hash -r NEED_INSTALL=true fi else echo "Node.js not found, installing 22..." NEED_INSTALL=true fi if [ "$NEED_INSTALL" = true ]; then curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs hash -r fi node --version npm --version - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set app version run: | # Tauri / Cargo require a strict semver; strip the preview suffix for # the bundle version but keep it in the artifact filename. BASE_VERSION="$(echo '${{ needs.compute-version.outputs.version }}' | cut -d'-' -f1)" sed -i "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/src-tauri/tauri.conf.json sed -i "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/package.json sed -i "s/^version = \".*\"/version = \"${BASE_VERSION}\"/" app/src-tauri/Cargo.toml echo "Patched version to ${BASE_VERSION}" - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ libgtk-3-dev \ libwebkit2gtk-4.1-dev \ libayatana-appindicator3-dev \ librsvg2-dev \ libsoup-3.0-dev \ libssl-dev \ libxdo-dev \ patchelf \ pkg-config \ build-essential \ curl \ wget \ file \ xdg-utils - name: Install Rust stable run: | if command -v rustup >/dev/null 2>&1; then rustup update stable rustup default stable else curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable fi export PATH="$HOME/.cargo/bin:$PATH" rustc --version cargo --version - name: Install frontend dependencies working-directory: ./app run: | rm -rf node_modules package-lock.json npm install - name: Install Tauri CLI working-directory: ./app run: | export PATH="$HOME/.cargo/bin:$PATH" npx tauri --version || npm install @tauri-apps/cli - name: Build Tauri app working-directory: ./app run: | export PATH="$HOME/.cargo/bin:$PATH" npx tauri build - name: Collect artifacts run: | mkdir -p artifacts cp app/src-tauri/target/release/bundle/appimage/*.AppImage artifacts/ 2>/dev/null || true cp app/src-tauri/target/release/bundle/deb/*.deb artifacts/ 2>/dev/null || true cp app/src-tauri/target/release/bundle/rpm/*.rpm artifacts/ 2>/dev/null || true ls -la artifacts/ - name: Upload Linux artifacts uses: actions/upload-artifact@v4 with: name: triple-c-${{ needs.compute-version.outputs.version }}-linux path: artifacts/ if-no-files-found: error retention-days: 14 build-macos: runs-on: macos-latest needs: [compute-version] steps: - name: Install Node.js 22 run: | NEED_INSTALL=false if command -v node >/dev/null 2>&1; then NODE_MAJOR=$(node --version | sed 's/v\([0-9]*\).*/\1/') if [ "$NODE_MAJOR" -lt 22 ]; then NEED_INSTALL=true fi else NEED_INSTALL=true fi if [ "$NEED_INSTALL" = true ]; then brew install node@22 brew link --overwrite node@22 fi node --version npm --version - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set app version run: | BASE_VERSION="$(echo '${{ needs.compute-version.outputs.version }}' | cut -d'-' -f1)" sed -i '' "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/src-tauri/tauri.conf.json sed -i '' "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/package.json sed -i '' "s/^version = \".*\"/version = \"${BASE_VERSION}\"/" app/src-tauri/Cargo.toml echo "Patched version to ${BASE_VERSION}" - name: Install Rust stable run: | if command -v rustup >/dev/null 2>&1; then rustup update stable rustup default stable else curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable fi export PATH="$HOME/.cargo/bin:$PATH" rustup target add aarch64-apple-darwin x86_64-apple-darwin rustc --version cargo --version - name: Install frontend dependencies working-directory: ./app run: | rm -rf node_modules npm install - name: Install Tauri CLI working-directory: ./app run: | export PATH="$HOME/.cargo/bin:$PATH" npx tauri --version || npm install @tauri-apps/cli - name: Build Tauri app (universal) working-directory: ./app run: | export PATH="$HOME/.cargo/bin:$PATH" npx tauri build --target universal-apple-darwin - name: Collect artifacts run: | mkdir -p artifacts cp app/src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg artifacts/ 2>/dev/null || true cp app/src-tauri/target/universal-apple-darwin/release/bundle/macos/*.app.tar.gz artifacts/ 2>/dev/null || true ls -la artifacts/ - name: Upload macOS artifacts uses: actions/upload-artifact@v4 with: name: triple-c-${{ needs.compute-version.outputs.version }}-macos path: artifacts/ if-no-files-found: error retention-days: 14 build-windows: runs-on: windows-latest needs: [compute-version] defaults: run: shell: cmd steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set app version shell: powershell run: | $raw = "${{ needs.compute-version.outputs.version }}" $version = $raw.Split('-')[0] (Get-Content app/src-tauri/tauri.conf.json) -replace '"version": ".*?"', "`"version`": `"$version`"" | Set-Content app/src-tauri/tauri.conf.json (Get-Content app/package.json) -replace '"version": ".*?"', "`"version`": `"$version`"" | Set-Content app/package.json (Get-Content app/src-tauri/Cargo.toml) -replace '^version = ".*?"', "version = `"$version`"" | Set-Content app/src-tauri/Cargo.toml Write-Host "Patched version to $version" - name: Install Rust stable run: | where rustup >nul 2>&1 && ( rustup update stable rustup default stable ) || ( curl -fSL -o rustup-init.exe https://win.rustup.rs/x86_64 rustup-init.exe -y --default-toolchain stable del rustup-init.exe ) - name: Install Node.js run: | where node >nul 2>&1 && ( node --version ) || ( curl -fSL -o node-install.msi "https://nodejs.org/dist/v22.14.0/node-v22.14.0-x64.msi" msiexec /i node-install.msi /quiet /norestart del node-install.msi ) - name: Verify tools run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" rustc --version cargo --version node --version npm --version - name: Install Tauri CLI via cargo run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" cargo install tauri-cli --version "^2" - name: Fix npm platform detection run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" npm config set os win32 npm config list - name: Install frontend dependencies working-directory: ./app run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" if exist node_modules rmdir /s /q node_modules npm ci - name: Build frontend working-directory: ./app run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" npm run build - name: Build Tauri app working-directory: ./app env: TAURI_CONFIG: "{\"build\":{\"beforeBuildCommand\":\"\"}}" run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" cargo tauri build - name: Collect artifacts run: | set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%" mkdir artifacts copy app\src-tauri\target\release\bundle\msi\*.msi artifacts\ 2>nul copy app\src-tauri\target\release\bundle\nsis\*.exe artifacts\ 2>nul dir artifacts\ - name: Upload Windows artifacts uses: actions/upload-artifact@v4 with: name: triple-c-${{ needs.compute-version.outputs.version }}-windows path: artifacts/ if-no-files-found: error retention-days: 14