feat: implement dual audio capture for Linux and enhance WASAPI audio… #28
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Two ways to trigger a release: | |
| # 1. workflow_dispatch: Manually trigger with version input (bumps version files, commits, creates release) | |
| # 2. push.tags: Push a version tag manually (e.g., git tag v1.0.0 && git push origin v1.0.0) | |
| # | |
| # Note: The workflow checks if a release already exists before creating one, so it's safe if | |
| # both triggers fire (e.g., when workflow_dispatch creates a tag that triggers push.tags) | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' # Trigger on version tags like v1.0.0 | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., 1.0.0)' | |
| required: true | |
| type: string | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # Job to create or validate version tag | |
| prepare-release: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # Allow creating releases and pushing commits | |
| pull-requests: write # Allow creating PRs | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| tag: ${{ steps.get_version.outputs.tag }} | |
| upload_url: ${{ steps.check_release.outputs.upload_url || steps.create_release.outputs.upload_url }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.PAT_TOKEN }} | |
| - name: Get version from tag or input | |
| id: get_version | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "tag=v${VERSION}" >> $GITHUB_OUTPUT | |
| else | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Update version in all files | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| # Update package.json | |
| cd apps/desktop | |
| npm version $VERSION --no-git-tag-version --allow-same-version | |
| # Update tauri.conf.json | |
| sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json | |
| # Update Cargo.toml | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" src-tauri/Cargo.toml | |
| # Update Cargo.lock | |
| cd src-tauri | |
| cargo update --package meet-scribe --precise $VERSION 2>/dev/null || cargo generate-lockfile | |
| cd ../.. | |
| - name: Commit version bump | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| TAG="${{ steps.get_version.outputs.tag }}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Check if there are any changes to commit | |
| if git diff --quiet apps/desktop/package.json apps/desktop/package-lock.json apps/desktop/src-tauri/tauri.conf.json apps/desktop/src-tauri/Cargo.toml apps/desktop/src-tauri/Cargo.lock; then | |
| echo "No version changes detected, skipping commit" | |
| else | |
| # Commit version changes | |
| git add apps/desktop/package.json apps/desktop/package-lock.json apps/desktop/src-tauri/tauri.conf.json apps/desktop/src-tauri/Cargo.toml apps/desktop/src-tauri/Cargo.lock | |
| git commit -m "chore: bump version to ${VERSION}" | |
| git push origin main | |
| fi | |
| # Create tag locally (DON'T push to prevent double-trigger) | |
| # Tag is only used for creating the GitHub release, not pushed to remote | |
| if git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "Tag $TAG already exists" | |
| else | |
| echo "Creating local tag $TAG for release (not pushing to remote)" | |
| git tag "$TAG" | |
| fi | |
| - name: Check if release already exists | |
| id: check_release | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| TAG="${{ steps.get_version.outputs.tag }}" | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "Release $TAG already exists" | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| # Get the upload URL from existing release | |
| UPLOAD_URL=$(gh api repos/${{ github.repository }}/releases/tags/$TAG --jq '.upload_url') | |
| echo "upload_url=$UPLOAD_URL" >> $GITHUB_OUTPUT | |
| else | |
| echo "Release $TAG does not exist, will create" | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create GitHub Release | |
| id: create_release | |
| if: steps.check_release.outputs.exists != 'true' | |
| uses: actions/create-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| tag_name: ${{ steps.get_version.outputs.tag }} | |
| release_name: Release ${{ steps.get_version.outputs.tag }} | |
| draft: false | |
| prerelease: false | |
| body: | | |
| ## Meet Scribe ${{ steps.get_version.outputs.version }} | |
| ### Downloads | |
| **Windows:** | |
| - x64: `meet-scribe_${{ steps.get_version.outputs.version }}_x64_en-US.msi` | |
| - ARM64: `meet-scribe_${{ steps.get_version.outputs.version }}_arm64_en-US.msi` | |
| **Linux:** | |
| - x64: `meet-scribe_${{ steps.get_version.outputs.version }}_amd64.deb` or `meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage` | |
| - ARM64: `meet-scribe_${{ steps.get_version.outputs.version }}_arm64.deb` | |
| ### Installation | |
| **Windows:** | |
| 1. Download the `.msi` installer (x64 or ARM64) | |
| 2. Double-click to install | |
| 3. Follow the installation wizard | |
| **Linux x64 (Debian/Ubuntu):** | |
| ```bash | |
| # Option 1: Install with dpkg | |
| sudo dpkg -i meet-scribe_${{ steps.get_version.outputs.version }}_amd64.deb | |
| # Option 2: Run AppImage (portable) | |
| chmod +x meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage | |
| ./meet-scribe_${{ steps.get_version.outputs.version }}_amd64.AppImage | |
| ``` | |
| **Linux ARM64 (Debian/Ubuntu):** | |
| ```bash | |
| sudo dpkg -i meet-scribe_${{ steps.get_version.outputs.version }}_arm64.deb | |
| ``` | |
| *Note: ARM64 Linux builds are .deb only (no AppImage available)* | |
| ### Changes | |
| See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details. | |
| # Build for Windows | |
| build-windows: | |
| needs: prepare-release | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare-release.outputs.tag || github.ref }} | |
| - name: Sync version files to match release | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.prepare-release.outputs.version }}" | |
| node -e " | |
| const fs = require('fs'); | |
| const conf = JSON.parse(fs.readFileSync('apps/desktop/src-tauri/tauri.conf.json', 'utf8')); | |
| conf.version = process.argv[1]; | |
| fs.writeFileSync('apps/desktop/src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2) + '\n'); | |
| " "$VERSION" | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" apps/desktop/src-tauri/Cargo.toml | |
| cd apps/desktop && npm version "$VERSION" --no-git-tag-version --allow-same-version | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/desktop/package-lock.json | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-msvc | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| - name: Install dependencies | |
| run: | | |
| cd apps/desktop | |
| npm ci | |
| - name: Build frontend | |
| run: | | |
| cd apps/desktop | |
| npm run build | |
| - name: Check signing environment (Windows) | |
| shell: pwsh | |
| run: | | |
| if ($env:TAURI_SIGNING_PRIVATE_KEY) { | |
| Write-Host "TAURI_SIGNING_PRIVATE_KEY is set (length: $($env:TAURI_SIGNING_PRIVATE_KEY.Length))" | |
| } else { | |
| Write-Host "WARNING: TAURI_SIGNING_PRIVATE_KEY is NOT set" | |
| } | |
| if ($env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD) { | |
| Write-Host "TAURI_SIGNING_PRIVATE_KEY_PASSWORD is set" | |
| } else { | |
| Write-Host "WARNING: TAURI_SIGNING_PRIVATE_KEY_PASSWORD is NOT set" | |
| } | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| - name: Build Tauri app | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| run: | | |
| cd apps/desktop | |
| npm run tauri build | |
| - name: List build artifacts | |
| run: | | |
| Get-ChildItem -Path apps/desktop/src-tauri/target/release/bundle -Recurse | Select-Object FullName | |
| - name: Check if signature was created | |
| id: check_sig | |
| shell: pwsh | |
| run: | | |
| $sigPath = "apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig" | |
| if (Test-Path $sigPath) { | |
| Write-Host "Signature file found: $sigPath" | |
| echo "sig_exists=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "Signature file NOT found: $sigPath" | |
| Write-Host "This is expected if TAURI_SIGNING_PRIVATE_KEY is not configured or signing failed" | |
| echo "sig_exists=false" >> $env:GITHUB_OUTPUT | |
| } | |
| - name: Upload Windows MSI | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi | |
| asset_content_type: application/x-msi | |
| - name: Upload Windows MSI Signature | |
| if: steps.check_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig | |
| asset_content_type: text/plain | |
| - name: Save Windows signature as artifact | |
| if: steps.check_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-sig | |
| path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi.sig | |
| retention-days: 1 | |
| - name: Upload Windows MSI (alternative path) | |
| if: failure() | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_x64_en-US.msi | |
| asset_content_type: application/x-msi | |
| # Build for Windows ARM64 | |
| build-windows-arm64: | |
| needs: prepare-release | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare-release.outputs.tag || github.ref }} | |
| - name: Sync version files to match release | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.prepare-release.outputs.version }}" | |
| node -e " | |
| const fs = require('fs'); | |
| const conf = JSON.parse(fs.readFileSync('apps/desktop/src-tauri/tauri.conf.json', 'utf8')); | |
| conf.version = process.argv[1]; | |
| fs.writeFileSync('apps/desktop/src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2) + '\n'); | |
| " "$VERSION" | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" apps/desktop/src-tauri/Cargo.toml | |
| cd apps/desktop && npm version "$VERSION" --no-git-tag-version --allow-same-version | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/desktop/package-lock.json | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: aarch64-pc-windows-msvc | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| key: arm64 | |
| - name: Install dependencies | |
| run: | | |
| cd apps/desktop | |
| npm ci | |
| - name: Build frontend | |
| run: | | |
| cd apps/desktop | |
| npm run build | |
| - name: Build Tauri app (ARM64) | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| run: | | |
| cd apps/desktop | |
| npm run tauri build -- --target aarch64-pc-windows-msvc | |
| - name: List build artifacts | |
| run: | | |
| Get-ChildItem -Path apps/desktop/src-tauri/target/aarch64-pc-windows-msvc/release/bundle -Recurse | Select-Object FullName | |
| - name: Check if ARM64 signature was created | |
| id: check_arm64_sig | |
| shell: pwsh | |
| run: | | |
| $sigPath = "apps/desktop/src-tauri/target/aarch64-pc-windows-msvc/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi.sig" | |
| if (Test-Path $sigPath) { | |
| Write-Host "ARM64 signature file found: $sigPath" | |
| echo "sig_exists=true" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "ARM64 signature file NOT found: $sigPath" | |
| echo "sig_exists=false" >> $env:GITHUB_OUTPUT | |
| } | |
| - name: Upload Windows ARM64 MSI | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/aarch64-pc-windows-msvc/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi | |
| asset_content_type: application/x-msi | |
| - name: Upload Windows ARM64 MSI Signature | |
| if: steps.check_arm64_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/aarch64-pc-windows-msvc/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi.sig | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi.sig | |
| asset_content_type: text/plain | |
| - name: Save Windows ARM64 signature as artifact | |
| if: steps.check_arm64_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-arm64-sig | |
| path: apps/desktop/src-tauri/target/aarch64-pc-windows-msvc/release/bundle/msi/meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64_en-US.msi.sig | |
| retention-days: 1 | |
| # Build for Linux | |
| build-linux: | |
| needs: prepare-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare-release.outputs.tag || github.ref }} | |
| - name: Sync version files to match release | |
| run: | | |
| VERSION="${{ needs.prepare-release.outputs.version }}" | |
| node -e " | |
| const fs = require('fs'); | |
| const conf = JSON.parse(fs.readFileSync('apps/desktop/src-tauri/tauri.conf.json', 'utf8')); | |
| conf.version = process.argv[1]; | |
| fs.writeFileSync('apps/desktop/src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2) + '\n'); | |
| " "$VERSION" | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" apps/desktop/src-tauri/Cargo.toml | |
| cd apps/desktop && npm version "$VERSION" --no-git-tag-version --allow-same-version | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/desktop/package-lock.json | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| libssl-dev \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev \ | |
| libpulse-dev | |
| - name: Install dependencies | |
| run: | | |
| cd apps/desktop | |
| npm ci | |
| - name: Build frontend | |
| run: | | |
| cd apps/desktop | |
| npm run build | |
| - name: Check signing environment (Linux) | |
| run: | | |
| if [ -n "$TAURI_SIGNING_PRIVATE_KEY" ]; then | |
| echo "TAURI_SIGNING_PRIVATE_KEY is set (length: ${#TAURI_SIGNING_PRIVATE_KEY})" | |
| else | |
| echo "WARNING: TAURI_SIGNING_PRIVATE_KEY is NOT set" | |
| fi | |
| if [ -n "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" ]; then | |
| echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD is set" | |
| else | |
| echo "WARNING: TAURI_SIGNING_PRIVATE_KEY_PASSWORD is NOT set" | |
| fi | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| - name: Build Tauri app | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| run: | | |
| cd apps/desktop | |
| npm run tauri build | |
| - name: List build artifacts | |
| run: | | |
| echo "Checking if bundle directory exists..." | |
| if [ -d "apps/desktop/src-tauri/target/release/bundle" ]; then | |
| echo "Bundle directory found, listing contents:" | |
| cd apps/desktop/src-tauri/target/release/bundle | |
| ls -lR | |
| else | |
| echo "Bundle directory not found! Listing target directory:" | |
| ls -lR apps/desktop/src-tauri/target/ || echo "Target directory doesn't exist" | |
| fi | |
| - name: Upload Linux DEB | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/deb/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.deb | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.deb | |
| asset_content_type: application/vnd.debian.binary-package | |
| - name: Upload Linux AppImage | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage | |
| asset_content_type: application/octet-stream | |
| - name: Check if Linux signature was created | |
| id: check_linux_sig | |
| run: | | |
| SIG_PATH="apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig" | |
| if [ -f "$SIG_PATH" ]; then | |
| echo "Linux signature file found: $SIG_PATH" | |
| echo "sig_exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "Linux signature file NOT found: $SIG_PATH" | |
| echo "sig_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Upload Linux AppImage Signature | |
| if: steps.check_linux_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig | |
| asset_content_type: text/plain | |
| - name: Save Linux signature as artifact | |
| if: steps.check_linux_sig.outputs.sig_exists == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-sig | |
| path: apps/desktop/src-tauri/target/release/bundle/appimage/meet-scribe_${{ needs.prepare-release.outputs.version }}_amd64.AppImage.sig | |
| retention-days: 1 | |
| # Build for Linux ARM64 | |
| build-linux-arm64: | |
| needs: prepare-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare-release.outputs.tag || github.ref }} | |
| - name: Sync version files to match release | |
| run: | | |
| VERSION="${{ needs.prepare-release.outputs.version }}" | |
| node -e " | |
| const fs = require('fs'); | |
| const conf = JSON.parse(fs.readFileSync('apps/desktop/src-tauri/tauri.conf.json', 'utf8')); | |
| conf.version = process.argv[1]; | |
| fs.writeFileSync('apps/desktop/src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2) + '\n'); | |
| " "$VERSION" | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" apps/desktop/src-tauri/Cargo.toml | |
| cd apps/desktop && npm version "$VERSION" --no-git-tag-version --allow-same-version | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/desktop/package-lock.json | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: aarch64-unknown-linux-gnu | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| key: arm64 | |
| - name: Install cross-compilation tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu | |
| - name: Install ARM64 system dependencies | |
| run: | | |
| sudo dpkg --add-architecture arm64 | |
| sudo bash -c 'cat > /etc/apt/sources.list.d/arm64.list <<EOF | |
| deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ $(lsb_release -sc) main restricted universe multiverse | |
| deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ $(lsb_release -sc)-updates main restricted universe multiverse | |
| deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ $(lsb_release -sc)-security main restricted universe multiverse | |
| EOF' | |
| sudo apt-get update || true | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev:arm64 \ | |
| libssl-dev:arm64 \ | |
| libgtk-3-dev:arm64 \ | |
| libayatana-appindicator3-dev:arm64 \ | |
| librsvg2-dev:arm64 \ | |
| libpulse-dev:arm64 || echo "Some ARM64 packages may not be available" | |
| - name: Configure cross-compilation | |
| run: | | |
| mkdir -p ~/.cargo | |
| cat >> ~/.cargo/config.toml <<EOF | |
| [target.aarch64-unknown-linux-gnu] | |
| linker = "aarch64-linux-gnu-gcc" | |
| EOF | |
| - name: Install dependencies | |
| run: | | |
| cd apps/desktop | |
| npm ci | |
| - name: Build frontend | |
| run: | | |
| cd apps/desktop | |
| npm run build | |
| - name: Build Tauri app (ARM64) | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| PKG_CONFIG_SYSROOT_DIR: /usr/aarch64-linux-gnu | |
| PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig | |
| run: | | |
| cd apps/desktop | |
| # Only build .deb for ARM64 - AppImage cross-compilation is problematic due to sysroot path issues | |
| npm run tauri build -- --target aarch64-unknown-linux-gnu --bundles deb | |
| - name: List build artifacts | |
| run: | | |
| echo "Checking ARM64 bundle directory..." | |
| if [ -d "apps/desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle" ]; then | |
| cd apps/desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle | |
| ls -lR | |
| else | |
| echo "ARM64 bundle directory not found!" | |
| ls -lR apps/desktop/src-tauri/target/aarch64-unknown-linux-gnu/ || echo "Target directory doesn't exist" | |
| fi | |
| - name: Upload Linux ARM64 DEB | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| upload_url: ${{ needs.prepare-release.outputs.upload_url }} | |
| asset_path: apps/desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/deb/meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64.deb | |
| asset_name: meet-scribe_${{ needs.prepare-release.outputs.version }}_arm64.deb | |
| asset_content_type: application/vnd.debian.binary-package | |
| # Generate and upload updater manifest | |
| create-updater-manifest: | |
| needs: [prepare-release, build-windows, build-windows-arm64, build-linux, build-linux-arm64] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download Windows signature | |
| uses: actions/download-artifact@v4 | |
| continue-on-error: true | |
| with: | |
| name: windows-sig | |
| path: ./sigs | |
| - name: Download Linux signature | |
| uses: actions/download-artifact@v4 | |
| continue-on-error: true | |
| with: | |
| name: linux-sig | |
| path: ./sigs | |
| - name: Download Windows ARM64 signature | |
| uses: actions/download-artifact@v4 | |
| continue-on-error: true | |
| with: | |
| name: windows-arm64-sig | |
| path: ./sigs | |
| - name: Generate and upload latest.json | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| VERSION="${{ needs.prepare-release.outputs.version }}" | |
| TAG="${{ needs.prepare-release.outputs.tag }}" | |
| REPO="${{ github.repository }}" | |
| # Read signature files if they exist | |
| WINDOWS_SIG="" | |
| LINUX_SIG="" | |
| WINDOWS_ARM64_SIG="" | |
| if [ -f "./sigs/meet-scribe_${VERSION}_x64_en-US.msi.sig" ]; then | |
| WINDOWS_SIG=$(cat "./sigs/meet-scribe_${VERSION}_x64_en-US.msi.sig") | |
| echo "Found Windows x64 signature" | |
| else | |
| echo "No Windows x64 signature found (signing may not be configured)" | |
| fi | |
| if [ -f "./sigs/meet-scribe_${VERSION}_amd64.AppImage.sig" ]; then | |
| LINUX_SIG=$(cat "./sigs/meet-scribe_${VERSION}_amd64.AppImage.sig") | |
| echo "Found Linux x64 signature" | |
| else | |
| echo "No Linux x64 signature found (signing may not be configured)" | |
| fi | |
| if [ -f "./sigs/meet-scribe_${VERSION}_arm64_en-US.msi.sig" ]; then | |
| WINDOWS_ARM64_SIG=$(cat "./sigs/meet-scribe_${VERSION}_arm64_en-US.msi.sig") | |
| echo "Found Windows ARM64 signature" | |
| else | |
| echo "No Windows ARM64 signature found (signing may not be configured)" | |
| fi | |
| # Create the updater manifest JSON | |
| # Note: Linux ARM64 is excluded because .deb files are not supported by Tauri updater | |
| cat > latest.json << EOF | |
| { | |
| "version": "$TAG", | |
| "notes": "See full release notes at https://github.com/$REPO/releases/tag/$TAG", | |
| "pub_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", | |
| "platforms": { | |
| "windows-x86_64": { | |
| "signature": "$WINDOWS_SIG", | |
| "url": "https://github.com/$REPO/releases/download/$TAG/meet-scribe_${VERSION}_x64_en-US.msi" | |
| }, | |
| "linux-x86_64": { | |
| "signature": "$LINUX_SIG", | |
| "url": "https://github.com/$REPO/releases/download/$TAG/meet-scribe_${VERSION}_amd64.AppImage" | |
| }, | |
| "windows-aarch64": { | |
| "signature": "$WINDOWS_ARM64_SIG", | |
| "url": "https://github.com/$REPO/releases/download/$TAG/meet-scribe_${VERSION}_arm64_en-US.msi" | |
| } | |
| } | |
| } | |
| EOF | |
| echo "Generated latest.json:" | |
| cat latest.json | |
| # Upload to release | |
| UPLOAD_URL="${{ needs.prepare-release.outputs.upload_url }}" | |
| UPLOAD_URL="${UPLOAD_URL%\{*}" # Remove the {?name,label} template part | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| --data-binary @latest.json \ | |
| "${UPLOAD_URL}?name=latest.json" |