name: Release on: push: tags: ["v*"] workflow_dispatch: permissions: contents: write jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - name: Install dependencies run: npm ci - name: Run backend tests working-directory: src-tauri run: cargo test --release - name: Build app run: npm run tauri build - name: Stage release assets if: startsWith(github.ref, 'refs/tags/') shell: pwsh run: | $version = "${env:GITHUB_REF_NAME}".TrimStart("v") New-Item -ItemType Directory -Force staged | Out-Null Copy-Item "src-tauri/target/release/bundle/nsis/Ports Controller_${version}_x64-setup.exe" "staged/PortsController_${version}_x64-setup.exe" Copy-Item "src-tauri/target/release/ports-controller.exe" "staged/PortsController_${version}_portable.exe" - name: Upload to release (only assets that do not exist yet) if: startsWith(github.ref, 'refs/tags/') shell: pwsh env: GH_TOKEN: ${{ github.token }} run: | $tag = "${env:GITHUB_REF_NAME}" gh release view $tag *> $null if ($LASTEXITCODE -ne 0) { gh release create $tag --title "Ports Controller $tag" --generate-notes } $existing = @(gh release view $tag --json assets --jq '.assets[].name') foreach ($file in Get-ChildItem staged) { if ($existing -notcontains $file.Name) { gh release upload $tag $file.FullName } else { Write-Host "Skipping $($file.Name) - already on release" } }