diff --git a/.gitea/workflows/build-app-preview.yml b/.gitea/workflows/build-app-preview.yml new file mode 100644 index 0000000..c519204 --- /dev/null +++ b/.gitea/workflows/build-app-preview.yml @@ -0,0 +1,323 @@ +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