From bf6fb471d9f1ecdb374061e181ae8edcc1c32c6c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 21 Mar 2026 06:01:15 -0700 Subject: [PATCH] Merge sidecar and app builds into single jobs per platform Removes the artifact upload/download overhead between sidecar and app build steps. Each platform now runs as a single job: build sidecar, copy it into src-tauri/binaries, build Tauri app, upload to release. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/build-linux.yml | 74 ++++++------------------------ .gitea/workflows/build-macos.yml | 61 ++++++------------------ .gitea/workflows/build-windows.yml | 62 ++++++------------------- 3 files changed, 40 insertions(+), 157 deletions(-) diff --git a/.gitea/workflows/build-linux.yml b/.gitea/workflows/build-linux.yml index 3d2a0ba..d01de12 100644 --- a/.gitea/workflows/build-linux.yml +++ b/.gitea/workflows/build-linux.yml @@ -13,12 +13,13 @@ env: TARGET: x86_64-unknown-linux-gnu jobs: - build-sidecar: - name: Build sidecar (Linux) + build: + name: Build (Linux) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + # ── Python sidecar ── - name: Install uv run: | if command -v uv &> /dev/null; then @@ -38,20 +39,13 @@ jobs: working-directory: python run: uv run --python ${{ env.PYTHON_VERSION }} python build_sidecar.py --cpu-only - - name: Upload sidecar artifact - uses: actions/upload-artifact@v3 - with: - name: sidecar-linux - path: python/dist/voice-to-notes-sidecar/ - retention-days: 7 - - build-app: - name: Build app (Linux) - needs: build-sidecar - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + - name: Place sidecar for Tauri + run: | + mkdir -p src-tauri/binaries + cp -r python/dist/voice-to-notes-sidecar/* src-tauri/binaries/ + chmod +x src-tauri/binaries/voice-to-notes-sidecar-${{ env.TARGET }} + # ── Tauri app ── - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -64,18 +58,8 @@ jobs: - name: Install system dependencies run: | - sudo apt-get update sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils - - name: Download sidecar artifact - uses: actions/download-artifact@v3 - with: - name: sidecar-linux - path: src-tauri/binaries/ - - - name: Make sidecar executable - run: chmod +x src-tauri/binaries/voice-to-notes-sidecar-${{ env.TARGET }} - - name: Install npm dependencies run: npm ci @@ -84,43 +68,20 @@ jobs: env: TAURI_CONFIG: '{"bundle":{"externalBin":["binaries/voice-to-notes-sidecar"]}}' - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: app-linux - path: | - src-tauri/target/release/bundle/deb/*.deb - src-tauri/target/release/bundle/appimage/*.AppImage - retention-days: 30 - - release: - name: Release (Linux) - needs: build-app - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - steps: - - name: Install tools - run: sudo apt-get update && sudo apt-get install -y jq curl - - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: app-linux - path: artifacts/ - - - name: Create or update release + # ── Release ── + - name: Upload to release + if: github.ref == 'refs/heads/main' env: BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }} run: | + sudo apt-get install -y jq TAG="latest" REPO_API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" - # Check if release exists RELEASE_ID=$(curl -s -H "Authorization: token ${BUILD_TOKEN}" \ "${REPO_API}/releases/tags/${TAG}" | jq -r '.id // empty') if [ -z "${RELEASE_ID}" ]; then - # Create new release RELEASE_ID=$(curl -s -X POST \ -H "Authorization: token ${BUILD_TOKEN}" \ -H "Content-Type: application/json" \ @@ -134,14 +95,11 @@ jobs: exit 1 fi - # Upload artifacts (delete existing ones with same name first) - find artifacts/ -type f \( -name "*.deb" -o -name "*.AppImage" \) | while IFS= read -r file; do + find src-tauri/target/release/bundle -type f \( -name "*.deb" -o -name "*.AppImage" \) | while IFS= read -r file; do filename=$(basename "$file") - # URL-encode spaces in filename for the API encoded_name=$(echo "$filename" | sed 's/ /%20/g') echo "Uploading ${filename} ($(du -h "$file" | cut -f1))..." - # Delete existing asset with same name ASSET_ID=$(curl -s -H "Authorization: token ${BUILD_TOKEN}" \ "${REPO_API}/releases/${RELEASE_ID}/assets" | jq -r ".[] | select(.name == \"${filename}\") | .id // empty") if [ -n "${ASSET_ID}" ]; then @@ -149,14 +107,10 @@ jobs: "${REPO_API}/releases/${RELEASE_ID}/assets/${ASSET_ID}" fi - # Upload using -T for streaming (avoids loading entire file into memory) HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ -H "Authorization: token ${BUILD_TOKEN}" \ -H "Content-Type: application/octet-stream" \ -T "$file" \ "${REPO_API}/releases/${RELEASE_ID}/assets?name=${encoded_name}") echo "Upload response: HTTP ${HTTP_CODE}" - if [ "$HTTP_CODE" -ge 400 ]; then - echo "WARNING: Upload failed for ${filename}" - fi done diff --git a/.gitea/workflows/build-macos.yml b/.gitea/workflows/build-macos.yml index d1b0d8e..58f558d 100644 --- a/.gitea/workflows/build-macos.yml +++ b/.gitea/workflows/build-macos.yml @@ -13,12 +13,13 @@ env: TARGET: aarch64-apple-darwin jobs: - build-sidecar: - name: Build sidecar (macOS) + build: + name: Build (macOS) runs-on: macos-latest steps: - uses: actions/checkout@v4 + # ── Python sidecar ── - name: Install uv run: | if command -v uv &> /dev/null; then @@ -38,20 +39,13 @@ jobs: working-directory: python run: uv run --python ${{ env.PYTHON_VERSION }} python build_sidecar.py --cpu-only - - name: Upload sidecar artifact - uses: actions/upload-artifact@v3 - with: - name: sidecar-macos - path: python/dist/voice-to-notes-sidecar/ - retention-days: 7 - - build-app: - name: Build app (macOS) - needs: build-sidecar - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 + - name: Place sidecar for Tauri + run: | + mkdir -p src-tauri/binaries + cp -r python/dist/voice-to-notes-sidecar/* src-tauri/binaries/ + chmod +x src-tauri/binaries/voice-to-notes-sidecar-${{ env.TARGET }} + # ── Tauri app ── - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -65,15 +59,6 @@ jobs: - name: Install system dependencies run: brew install --quiet create-dmg || true - - name: Download sidecar artifact - uses: actions/download-artifact@v3 - with: - name: sidecar-macos - path: src-tauri/binaries/ - - - name: Make sidecar executable - run: chmod +x src-tauri/binaries/voice-to-notes-sidecar-${{ env.TARGET }} - - name: Install npm dependencies run: npm ci @@ -82,35 +67,15 @@ jobs: env: TAURI_CONFIG: '{"bundle":{"externalBin":["binaries/voice-to-notes-sidecar"]}}' - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: app-macos - path: | - src-tauri/target/release/bundle/dmg/*.dmg - src-tauri/target/release/bundle/macos/*.app - retention-days: 30 - - release: - name: Release (macOS) - needs: build-app - if: github.ref == 'refs/heads/main' - runs-on: macos-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: app-macos - path: artifacts/ - - - name: Create or update release + # ── Release ── + - name: Upload to release + if: github.ref == 'refs/heads/main' env: BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }} run: | TAG="latest" REPO_API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" - # Check if release exists RELEASE_ID=$(curl -s -H "Authorization: token ${BUILD_TOKEN}" \ "${REPO_API}/releases/tags/${TAG}" | jq -r '.id // empty') @@ -128,7 +93,7 @@ jobs: exit 1 fi - find artifacts/ -type f -name "*.dmg" | while IFS= read -r file; do + find src-tauri/target/release/bundle -type f -name "*.dmg" | while IFS= read -r file; do filename=$(basename "$file") encoded_name=$(echo "$filename" | sed 's/ /%20/g') echo "Uploading ${filename} ($(du -h "$file" | cut -f1))..." diff --git a/.gitea/workflows/build-windows.yml b/.gitea/workflows/build-windows.yml index 2cafd4f..a07b969 100644 --- a/.gitea/workflows/build-windows.yml +++ b/.gitea/workflows/build-windows.yml @@ -13,12 +13,13 @@ env: TARGET: x86_64-pc-windows-msvc jobs: - build-sidecar: - name: Build sidecar (Windows) + build: + name: Build (Windows) runs-on: windows-latest steps: - uses: actions/checkout@v4 + # ── Python sidecar ── - name: Install uv shell: powershell run: | @@ -42,20 +43,13 @@ jobs: working-directory: python run: uv run --python ${{ env.PYTHON_VERSION }} python build_sidecar.py --cpu-only - - name: Upload sidecar artifact - uses: actions/upload-artifact@v3 - with: - name: sidecar-windows - path: python/dist/voice-to-notes-sidecar/ - retention-days: 7 - - build-app: - name: Build app (Windows) - needs: build-sidecar - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 + - name: Place sidecar for Tauri + shell: powershell + run: | + New-Item -ItemType Directory -Force -Path src-tauri\binaries + Copy-Item -Path python\dist\voice-to-notes-sidecar\* -Destination src-tauri\binaries\ -Recurse -Force + # ── Tauri app ── - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -72,12 +66,6 @@ jobs: echo "$env:USERPROFILE\.cargo\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append } - - name: Download sidecar artifact - uses: actions/download-artifact@v3 - with: - name: sidecar-windows - path: src-tauri/binaries/ - - name: Install npm dependencies shell: powershell run: npm ci @@ -88,28 +76,9 @@ jobs: env: TAURI_CONFIG: '{"bundle":{"externalBin":["binaries/voice-to-notes-sidecar"]}}' - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: app-windows - path: | - src-tauri/target/release/bundle/msi/*.msi - src-tauri/target/release/bundle/nsis/*.exe - retention-days: 30 - - release: - name: Release (Windows) - needs: build-app - if: github.ref == 'refs/heads/main' - runs-on: windows-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: app-windows - path: artifacts/ - - - name: Create or update release + # ── Release ── + - name: Upload to release + if: github.ref == 'refs/heads/main' shell: powershell env: BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }} @@ -118,12 +87,10 @@ jobs: $REPO_API = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}" $Headers = @{ "Authorization" = "token $env:BUILD_TOKEN" } - # Check if release exists try { $release = Invoke-RestMethod -Uri "${REPO_API}/releases/tags/${TAG}" -Headers $Headers -ErrorAction Stop $RELEASE_ID = $release.id } catch { - # Create new release $body = @{ tag_name = $TAG name = "Voice to Notes (Latest Build)" @@ -137,14 +104,12 @@ jobs: Write-Host "Release ID: ${RELEASE_ID}" - # Upload artifacts - Get-ChildItem -Path artifacts -Recurse -Include *.msi,*.exe | ForEach-Object { + Get-ChildItem -Path src-tauri\target\release\bundle -Recurse -Include *.msi,*.exe | ForEach-Object { $filename = $_.Name $encodedName = [System.Uri]::EscapeDataString($filename) $size = [math]::Round($_.Length / 1MB, 1) Write-Host "Uploading ${filename} (${size} MB)..." - # Delete existing asset with same name try { $assets = Invoke-RestMethod -Uri "${REPO_API}/releases/${RELEASE_ID}/assets" -Headers $Headers $existing = $assets | Where-Object { $_.name -eq $filename } @@ -153,7 +118,6 @@ jobs: } } catch {} - # Upload try { Invoke-RestMethod -Uri "${REPO_API}/releases/${RELEASE_ID}/assets?name=${encodedName}" ` -Method Post -Headers $Headers -ContentType "application/octet-stream" `