name: Build & Release on: push: tags: - 'v*' workflow_dispatch: permissions: contents: write jobs: build: strategy: fail-fast: false matrix: include: - platform: macos-latest args: '--target aarch64-apple-darwin' rust_target: aarch64-apple-darwin - platform: ubuntu-22.04 args: '' rust_target: '' # GitHub-hosted ARM Linux runner (free for public repos # since 2024). Native build — no cross-compile of webkit2gtk. - platform: ubuntu-22.04-arm args: '' rust_target: '' - platform: windows-latest args: '' rust_target: '' runs-on: ${{ matrix.platform }} env: # GitHub-hosted runners occasionally hit crates.io HTTP/2 stream # resets while downloading large dependency graphs. Cargo retries plus # HTTP/1.1 transport make release builds less flaky across the matrix. CARGO_HTTP_MULTIPLEXING: "false" CARGO_NET_RETRY: "5" CARGO_HTTP_TIMEOUT: "60" steps: - name: Checkout uses: actions/checkout@v4 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.rust_target }} - name: Rust cache uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - name: Install protoc (macOS) if: startsWith(matrix.platform, 'macos-') run: brew install protobuf - name: Install dependencies (Ubuntu) if: startsWith(matrix.platform, 'ubuntu-22.04') run: | sudo apt-get update # xdg-utils provides /usr/bin/xdg-open, which Tauri's # AppImage bundler embeds into the produced AppImage. # Pre-installed on the x86_64 runner image but NOT on # the ARM64 image — list it explicitly so both arches # bundle cleanly regardless of future image drift. sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf protobuf-compiler xdg-utils # The repo ships pre-downloaded PDFium binaries under # src-tauri/pdfium/ for every supported architecture # (libpdfium.so = Linux x86_64, libpdfium-arm64.so = Linux aarch64, # libpdfium.dylib = macOS arm64, pdfium.dll = Windows). # For architectures whose bundled filename must # stay `libpdfium.*`, swap the matching binary into place before cargo # runs. We do NOT pull from bblanchon/pdfium-binaries during CI — that # download has historically failed often enough that committing the # binaries is the maintenance-friendly path. - name: Verify PDFium binary checksums if: matrix.platform != 'windows-latest' run: shasum -a 256 -c src-tauri/pdfium/SHA256SUMS # rust_target is empty for both Ubuntu rows, so platform is the # only stable discriminator for the Linux ARM swap. - name: Use ARM64 pdfium binary (Ubuntu ARM only) if: matrix.platform == 'ubuntu-22.04-arm' run: | cp src-tauri/pdfium/libpdfium-arm64.so src-tauri/pdfium/libpdfium.so file src-tauri/pdfium/libpdfium.so - name: Install protoc (Windows) if: matrix.platform == 'windows-latest' uses: arduino/setup-protoc@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 - name: Install frontend dependencies run: npm install - name: Prepare MCP server resources run: | npm --prefix mcp-server ci npm run mcp:build - name: Build Tauri app uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} with: # Tag-triggered runs publish a real GitHub Release. # Manual (workflow_dispatch) runs leave tagName/releaseName # empty so tauri-action skips the release-upload step and # just produces bundle artifacts — useful for testing a # branch build without polluting the Releases page. tagName: ${{ github.event_name == 'push' && github.ref_name || '' }} releaseName: ${{ github.event_name == 'push' && format('LLM Wiki {0}', github.ref_name) || '' }} releaseBody: 'See the assets below for download links.' releaseDraft: false prerelease: false args: ${{ matrix.args }} - name: Package Windows portable zip if: matrix.platform == 'windows-latest' shell: pwsh run: | $version = node -p "require('./package.json').version" .github/scripts/package-windows-portable.ps1 -Version $version - name: Attach Windows portable zip to release if: github.event_name == 'push' && matrix.platform == 'windows-latest' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} shell: pwsh run: | gh release upload "${{ github.ref_name }}" dist-portable/*.zip --clobber # On workflow_dispatch, no release is created, so the bundles # would otherwise be discarded with the runner. Upload them as # workflow artifacts so the maintainer can `gh run download` # the .msi / .exe / .dmg / .deb to test locally. Skipped on # tag pushes since the release page already has them. - name: Upload bundles as workflow artifacts (manual runs only) if: github.event_name == 'workflow_dispatch' uses: actions/upload-artifact@v4 with: name: bundle-${{ matrix.platform }} # Glob covers both targeted (e.g. # target/aarch64-apple-darwin/release/...) and default # (target/release/...) build paths. path: | src-tauri/target/**/release/bundle/msi/*.msi src-tauri/target/**/release/bundle/nsis/*.exe src-tauri/target/**/release/bundle/dmg/*.dmg src-tauri/target/**/release/bundle/deb/*.deb src-tauri/target/**/release/bundle/appimage/*.AppImage dist-portable/*.zip if-no-files-found: warn retention-days: 14 package-extension: name: Package browser extension needs: build # Browser extension is only published as part of an actual # tagged release; manual builds don't need it. if: github.event_name == 'push' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Sync extension manifest version and zip run: | # Pull version from package.json so we have a single source of # truth. Chrome's manifest requires numeric-only version # (e.g. 0.3.5), which matches the repo's semver convention. APP_VERSION=$(node -p "require('./package.json').version") node -e " const fs = require('fs'); const p = 'extension/manifest.json'; const m = JSON.parse(fs.readFileSync(p, 'utf-8')); m.version = '${APP_VERSION}'; fs.writeFileSync(p, JSON.stringify(m, null, 2) + '\n'); " mkdir -p dist-extension (cd extension && zip -r "../dist-extension/llm-wiki-extension-${APP_VERSION}.zip" . -x "*.DS_Store") ls -la dist-extension - name: Attach extension zip to release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release upload "${{ github.ref_name }}" dist-extension/*.zip --clobber