# PSG Launcher — Release workflow # # Triggers on version tags: git tag v1.2.3 && git push --tags # # Required Gitea repository secrets: # TAURI_SIGNING_PRIVATE_KEY — from: npm run tauri signer generate # TAURI_SIGNING_PRIVATE_KEY_PASSWORD — (empty string is fine if no passphrase) # MANIFEST_SIGNING_KEY — PEM content of manifest-private.pem # GITEA_TOKEN — a personal access token with repo write scope # # The workflow: # 1. Builds the Tauri Windows installer (signed with Tauri's ed25519 key) # 2. Signs apps.json with the manifest key # 3. Creates a Gitea release with the installer attached # 4. Pushes updated latest.json and apps.json.sig to the `releases` branch name: Release on: push: tags: - "v*" jobs: build-windows: runs-on: windows-latest permissions: contents: write steps: # ── Checkout ─────────────────────────────────────────────────────────── - name: Checkout uses: actions/checkout@v4 # ── Toolchains ───────────────────────────────────────────────────────── - name: Set up Node.js 20 uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - name: Set up Rust (stable) uses: dtolnay/rust-toolchain@stable with: targets: x86_64-pc-windows-msvc - name: Cache Rust build uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git src-tauri/target key: ${{ runner.os }}-cargo-${{ hashFiles('src-tauri/Cargo.lock') }} restore-keys: ${{ runner.os }}-cargo- # ── Install dependencies ─────────────────────────────────────────────── - name: Install npm dependencies run: npm ci # ── Build Tauri release ──────────────────────────────────────────────── - name: Build Tauri app (Windows) run: npm run tauri build -- --target x86_64-pc-windows-msvc env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} # ── Collect artefacts ────────────────────────────────────────────────── - name: Locate installer and signature id: artefacts shell: pwsh run: | $installer = Get-ChildItem src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis ` -Filter "*-setup.exe" -Recurse | Select-Object -First 1 $sig = Get-Item "$($installer.FullName).sig" echo "installer=$($installer.FullName)" >> $env:GITHUB_OUTPUT echo "sig=$($sig.FullName)" >> $env:GITHUB_OUTPUT echo "version=${GITHUB_REF_NAME#v}" >> $env:GITHUB_OUTPUT $sigContent = Get-Content $sig.FullName -Raw echo "tauri_sig=$sigContent" >> $env:GITHUB_OUTPUT # ── Update latest.json ───────────────────────────────────────────────── - name: Write latest.json shell: pwsh run: | $version = "${{ steps.artefacts.outputs.version }}" $tauriSig = "${{ steps.artefacts.outputs.tauri_sig }}" $baseUrl = "${{ gitea.server_url }}/${{ gitea.repository }}/releases/download/v$version" $filename = Split-Path "${{ steps.artefacts.outputs.installer }}" -Leaf $latest = @{ version = $version notes = "Release $version" pub_date = (Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ") platforms = @{ "windows-x86_64" = @{ signature = $tauriSig.Trim() url = "$baseUrl/$filename" } } } $latest | ConvertTo-Json -Depth 5 | Set-Content manifests/latest.json Write-Host "latest.json written" # ── Sign apps.json ───────────────────────────────────────────────────── - name: Sign apps manifest shell: pwsh env: MANIFEST_SIGNING_KEY: ${{ secrets.MANIFEST_SIGNING_KEY }} run: .\scripts\sign-manifest.ps1 # ── Create Gitea release ─────────────────────────────────────────────── - name: Create release and upload installer shell: pwsh env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | $tag = "${{ github.ref_name }}" $version = "${{ steps.artefacts.outputs.version }}" $installer= "${{ steps.artefacts.outputs.installer }}" $sig = "${{ steps.artefacts.outputs.sig }}" $apiBase = "${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}" $headers = @{ Authorization = "token $env:GITEA_TOKEN"; "Content-Type" = "application/json" } # Create release $body = @{ tag_name = $tag; name = "PSG Launcher $tag"; draft = $false; prerelease = $false } | ConvertTo-Json $release = Invoke-RestMethod -Uri "$apiBase/releases" -Method Post -Headers $headers -Body $body $uploadUrl = "$apiBase/releases/$($release.id)/assets" # Upload installer $uploadHeaders = @{ Authorization = "token $env:GITEA_TOKEN" } Invoke-RestMethod -Uri "$uploadUrl`?name=$(Split-Path $installer -Leaf)" ` -Method Post -Headers $uploadHeaders ` -InFile $installer -ContentType "application/octet-stream" # Upload .sig file Invoke-RestMethod -Uri "$uploadUrl`?name=$(Split-Path $sig -Leaf)" ` -Method Post -Headers $uploadHeaders ` -InFile $sig -ContentType "text/plain" Write-Host "Release $tag created ✓" # ── Push manifests to releases branch ───────────────────────────────── - name: Push manifests to releases branch shell: pwsh env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | git config user.name "Gitea Actions" git config user.email "actions@gitea" $remote = "${{ gitea.server_url }}/${{ gitea.repository }}.git" $authedRemote = $remote -replace "://", "://actions:$env:GITEA_TOKEN@" # Fetch or create the releases branch git fetch origin releases 2>$null git checkout -B releases origin/releases 2>$null || git checkout --orphan releases # Copy only the manifest files git checkout ${{ github.sha }} -- manifests/ git add manifests/apps.json manifests/apps.json.sig manifests/latest.json git commit -m "chore: update manifests for ${{ github.ref_name }}" --allow-empty git push $authedRemote releases Write-Host "Manifests pushed to releases branch ✓"