name: Desktop Release on: push: tags: - 'v*' permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build-macos: name: Desktop Build (macOS ${{ matrix.arch }}) runs-on: macos-15 env: AGENTSVIEW_TARGET_TRIPLE: ${{ matrix.target_triple }} CARGO_BUILD_TARGET: ${{ matrix.target_triple }} strategy: fail-fast: false matrix: include: - arch: aarch64 target_triple: aarch64-apple-darwin - arch: x86_64 target_triple: x86_64-apple-darwin steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" - name: Install Rust target run: rustup target add "$AGENTSVIEW_TARGET_TRIPLE" - name: Install desktop dependencies run: npm ci working-directory: desktop - name: Prepare sidecar env: AGENTSVIEW_VERSION: ${{ github.ref_name }} run: | export TAURI_ENV_TARGET_TRIPLE="$AGENTSVIEW_TARGET_TRIPLE" npm run prepare-sidecar working-directory: desktop - name: Patch updater config for current repository env: AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: | sed -i.bak \ -e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \ -e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \ desktop/src-tauri/tauri.conf.json rm -f desktop/src-tauri/tauri.conf.json.bak - name: Import signing certificate env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} run: | KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain" KEYCHAIN_PASS="$(openssl rand -base64 32)" security create-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH" security set-keychain-settings -lut 3600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH" CERT_PATH="$RUNNER_TEMP/certificate.p12" echo "$APPLE_CERTIFICATE" | base64 -d > "$CERT_PATH" security import "$CERT_PATH" \ -k "$KEYCHAIN_PATH" \ -P "$APPLE_CERTIFICATE_PASSWORD" \ -T /usr/bin/codesign \ -T /usr/bin/security rm -f "$CERT_PATH" security set-key-partition-list \ -S apple-tool:,apple: \ -k "$KEYCHAIN_PASS" "$KEYCHAIN_PATH" security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain - name: Write API key env: APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }} APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} run: | KEY_DIR="$RUNNER_TEMP/apple-keys" mkdir -p "$KEY_DIR" echo "$APPLE_API_KEY_CONTENT" | base64 -d \ > "$KEY_DIR/AuthKey_${APPLE_API_KEY}.p8" echo "APPLE_API_KEY_PATH=$KEY_DIR/AuthKey_${APPLE_API_KEY}.p8" \ >> "$GITHUB_ENV" - name: Build DMG and updater bundle env: APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: npx tauri build --target "$AGENTSVIEW_TARGET_TRIPLE" working-directory: desktop - name: Collect build artifacts run: | bundle_dir="desktop/src-tauri/target/${AGENTSVIEW_TARGET_TRIPLE}/release/bundle" mkdir -p staging cp "$bundle_dir"/dmg/*.dmg staging/ app_bundle="$(find "$bundle_dir"/macos -maxdepth 1 -name '*.app.tar.gz' -print -quit)" app_sig="$(find "$bundle_dir"/macos -maxdepth 1 -name '*.app.tar.gz.sig' -print -quit)" app_name="$(basename "$app_bundle")" app_sig_name="$(basename "$app_sig")" cp "$app_bundle" "staging/${app_name%.app.tar.gz}_${{ matrix.arch }}.app.tar.gz" cp "$app_sig" "staging/${app_sig_name%.app.tar.gz.sig}_${{ matrix.arch }}.app.tar.gz.sig" ls -la staging/ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: agentsview-desktop-macos-${{ matrix.arch }} path: staging/* if-no-files-found: error - name: Cleanup signing secrets if: always() run: | KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain" security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true rm -rf "$RUNNER_TEMP/apple-keys" 2>/dev/null || true build-windows: name: Desktop Build (Windows) runs-on: windows-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" - name: Setup MinGW id: setup_mingw continue-on-error: true uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2 with: msystem: MINGW64 update: false install: mingw-w64-x86_64-gcc path-type: inherit - name: Setup MinGW (retry on transient failure) if: steps.setup_mingw.outcome == 'failure' uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2 with: msystem: MINGW64 update: false install: mingw-w64-x86_64-gcc path-type: inherit - name: Install desktop dependencies run: npm ci working-directory: desktop - name: Prepare sidecar shell: bash env: AGENTSVIEW_VERSION: ${{ github.ref_name }} run: npm run prepare-sidecar working-directory: desktop - name: Patch updater config for current repository shell: bash env: AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: | sed -i.bak \ -e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \ -e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \ desktop/src-tauri/tauri.conf.json rm -f desktop/src-tauri/tauri.conf.json.bak - name: Build NSIS installer and updater bundle shell: bash env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: npx tauri build --bundles nsis working-directory: desktop - name: Collect build artifacts shell: bash run: | mkdir -p staging cp desktop/src-tauri/target/release/bundle/nsis/*.exe staging/ cp desktop/src-tauri/target/release/bundle/nsis/*.nsis.zip staging/ cp desktop/src-tauri/target/release/bundle/nsis/*.nsis.zip.sig staging/ ls -la staging/ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: agentsview-desktop-windows path: staging/* if-no-files-found: error build-linux: name: Desktop Build (Linux ${{ matrix.arch }}) runs-on: ${{ matrix.os }} env: AGENTSVIEW_TARGET_TRIPLE: ${{ matrix.target_triple }} strategy: fail-fast: false matrix: include: - arch: x86_64 os: ubuntu-22.04 target_triple: "" artifact_name: agentsview-desktop-linux artifact_dir: desktop/src-tauri/target/release/bundle/appimage/ create_updater_artifacts: "true" - arch: arm64 os: ubuntu-22.04-arm target_triple: aarch64-unknown-linux-gnu artifact_name: agentsview-desktop-linux-arm64 artifact_dir: desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/appimage/ create_updater_artifacts: "false" steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" - name: Install Rust target if: env.AGENTSVIEW_TARGET_TRIPLE != '' run: rustup target add "$AGENTSVIEW_TARGET_TRIPLE" - name: Install Linux system dependencies run: | sudo apt-get update -q sudo apt-get install -y \ libwebkit2gtk-4.1-dev libgtk-3-dev \ libappindicator3-dev librsvg2-dev \ patchelf squashfs-tools xdg-utils - name: Install desktop dependencies run: npm ci working-directory: desktop - name: Prepare sidecar env: AGENTSVIEW_VERSION: ${{ github.ref_name }} run: | export TAURI_ENV_TARGET_TRIPLE="$AGENTSVIEW_TARGET_TRIPLE" npm run prepare-sidecar working-directory: desktop - name: Patch updater config for current repository env: AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: | sed -i.bak \ -e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \ -e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \ desktop/src-tauri/tauri.conf.json rm -f desktop/src-tauri/tauri.conf.json.bak - name: Build AppImage and updater bundle env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }} run: | build_cmd=(npx tauri build --bundles appimage) if [ -n "$AGENTSVIEW_TARGET_TRIPLE" ]; then build_cmd+=(--target "$AGENTSVIEW_TARGET_TRIPLE") fi if [ "${{ matrix.create_updater_artifacts }}" = "false" ]; then build_cmd+=(--config '{"bundle":{"createUpdaterArtifacts":false}}') fi "${build_cmd[@]}" bash scripts/repair-appimage-diricon.sh \ "../${{ matrix.artifact_dir }}"/*.AppImage working-directory: desktop - name: Collect build artifacts run: | mkdir -p staging cp "${{ matrix.artifact_dir }}"/*.AppImage staging/ if [ "${{ matrix.create_updater_artifacts }}" = "true" ]; then cp "${{ matrix.artifact_dir }}"/*.AppImage.tar.gz staging/ cp "${{ matrix.artifact_dir }}"/*.AppImage.tar.gz.sig staging/ fi ls -la staging/ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.artifact_name }} path: staging/* if-no-files-found: error release: name: Upload Desktop Installers needs: [build-macos, build-windows, build-linux] runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: artifacts pattern: agentsview-desktop-* merge-multiple: true - name: Generate checksums run: | cd artifacts sha256sum *.dmg *.exe *.AppImage *.tar.gz *.nsis.zip > SHA256SUMS-desktop 2>/dev/null || true cat SHA256SUMS-desktop - name: Generate updater manifest run: | set -euo pipefail VERSION="${GITHUB_REF_NAME#v}" DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" TAG="updater" MACOS_AARCH64_SIG="" MACOS_AARCH64_URL="" MACOS_X86_64_SIG="" MACOS_X86_64_URL="" WINDOWS_SIG="" WINDOWS_URL="" LINUX_SIG="" LINUX_URL="" for f in artifacts/*_aarch64.app.tar.gz.sig; do if [ -f "$f" ]; then MACOS_AARCH64_SIG="$(cat "$f")" MACOS_AARCH64_TARBALL="$(basename "${f%.sig}")" MACOS_AARCH64_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${MACOS_AARCH64_TARBALL}" fi done for f in artifacts/*_x86_64.app.tar.gz.sig; do if [ -f "$f" ]; then MACOS_X86_64_SIG="$(cat "$f")" MACOS_X86_64_TARBALL="$(basename "${f%.sig}")" MACOS_X86_64_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${MACOS_X86_64_TARBALL}" fi done for f in artifacts/*.nsis.zip.sig; do if [ -f "$f" ]; then WINDOWS_SIG="$(cat "$f")" NSIS_ZIP="$(basename "${f%.sig}")" WINDOWS_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${NSIS_ZIP}" fi done for f in artifacts/*.AppImage.tar.gz.sig; do if [ -f "$f" ]; then LINUX_SIG="$(cat "$f")" LINUX_TARBALL="$(basename "${f%.sig}")" LINUX_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${LINUX_TARBALL}" fi done if [ -z "$MACOS_AARCH64_SIG" ] || [ -z "$MACOS_AARCH64_URL" ]; then echo "error: missing macOS aarch64 updater signature or URL" >&2 exit 1 fi if [ -z "$MACOS_X86_64_SIG" ] || [ -z "$MACOS_X86_64_URL" ]; then echo "error: missing macOS x86_64 updater signature or URL" >&2 exit 1 fi if [ -z "$WINDOWS_SIG" ] || [ -z "$WINDOWS_URL" ]; then echo "error: missing Windows updater signature or URL" >&2 exit 1 fi if [ -z "$LINUX_SIG" ] || [ -z "$LINUX_URL" ]; then echo "error: missing Linux updater signature or URL" >&2 exit 1 fi cat > artifacts/latest.json << MANIFEST { "version": "${VERSION}", "pub_date": "${DATE}", "platforms": { "darwin-aarch64": { "url": "${MACOS_AARCH64_URL}", "signature": "${MACOS_AARCH64_SIG}" }, "darwin-x86_64": { "url": "${MACOS_X86_64_URL}", "signature": "${MACOS_X86_64_SIG}" }, "windows-x86_64": { "url": "${WINDOWS_URL}", "signature": "${WINDOWS_SIG}" }, "linux-x86_64": { "url": "${LINUX_URL}", "signature": "${LINUX_SIG}" } } } MANIFEST echo "Generated latest.json:" cat artifacts/latest.json - name: Upload installers to versioned release uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 with: files: | artifacts/*.dmg artifacts/*.exe artifacts/*.AppImage artifacts/SHA256SUMS-desktop - name: Upload updater artifacts env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail # Create or update the permanent 'updater' release if ! gh release view updater --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then gh release create updater \ --repo "$GITHUB_REPOSITORY" \ --title "Auto-Updater Artifacts" \ --notes "Internal release used by the desktop auto-updater. Do not delete." \ --prerelease fi # Overwrite existing assets gh release upload updater \ --repo "$GITHUB_REPOSITORY" \ --clobber \ artifacts/*.app.tar.gz \ artifacts/*.app.tar.gz.sig \ artifacts/*.nsis.zip \ artifacts/*.nsis.zip.sig \ artifacts/*.AppImage.tar.gz \ artifacts/*.AppImage.tar.gz.sig \ artifacts/latest.json