name: Release on: push: tags: - 'v*' workflow_dispatch: jobs: create-release: permissions: contents: write runs-on: ubuntu-latest outputs: release_id: ${{ steps.create-release.outputs.result }} package_version: ${{ steps.get-version.outputs.version }} steps: - uses: actions/checkout@v5 - name: setup node uses: actions/setup-node@v5 with: node-version: lts/* - name: cache npm uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} restore-keys: ${{ runner.os }}-npm- - name: get version id: get-version run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT - name: extract changelog id: changelog run: | VERSION="${{ steps.get-version.outputs.version }}" # Extract the block between ## [VERSION] and the next ## heading BODY=$(awk "/^## \[$VERSION\]/{found=1; next} found && /^## \[/{exit} found{print}" CHANGELOG.md) # Store multiline output EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) echo "body<<$EOF" >> $GITHUB_OUTPUT echo "$BODY" >> $GITHUB_OUTPUT echo "$EOF" >> $GITHUB_OUTPUT - name: create release id: create-release uses: actions/github-script@v7 env: PACKAGE_VERSION: ${{ steps.get-version.outputs.version }} CHANGELOG_BODY: ${{ steps.changelog.outputs.body }} with: script: | const tag = `app-v${process.env.PACKAGE_VERSION}`; const body = process.env.CHANGELOG_BODY || 'See the assets to download this version and install.'; try { const { data } = await github.rest.repos.getReleaseByTag({ owner: context.repo.owner, repo: context.repo.repo, tag, }); await github.rest.repos.updateRelease({ owner: context.repo.owner, repo: context.repo.repo, release_id: data.id, body, }); return data.id; } catch (e) { if (e.status !== 404) throw e; } const { data } = await github.rest.repos.createRelease({ owner: context.repo.owner, repo: context.repo.repo, tag_name: tag, name: `Psysonic v${process.env.PACKAGE_VERSION}`, body, draft: true, prerelease: false }); return data.id; build-macos-windows: needs: create-release permissions: contents: write env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} strategy: fail-fast: false matrix: settings: - platform: 'macos-latest' args: '--target aarch64-apple-darwin' - platform: 'macos-latest' args: '--target x86_64-apple-darwin' - platform: 'windows-latest' args: '--bundles nsis' runs-on: ${{ matrix.settings.platform }} steps: - uses: actions/checkout@v5 - name: setup node uses: actions/setup-node@v5 with: node-version: lts/* - name: cache npm uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} restore-keys: ${{ runner.os }}-npm- - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.settings.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - name: cache cargo uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - name: install npm dependencies run: npm install - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} with: releaseId: ${{ needs.create-release.outputs.release_id }} args: ${{ matrix.settings.args }} # Prevent tauri-action from auto-uploading a latest.json that uses # the PUBLIC KEY as the signature value. Our generate-update-manifest.js # builds the correct manifest with real .sig file contents. updaterJsonKeepUniversal: false - name: sign and upload Windows NSIS updater bundle if: matrix.settings.platform == 'windows-latest' shell: pwsh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ needs.create-release.outputs.package_version }} run: | $dir = "src-tauri/target/release/bundle/nsis" $exe = (Get-ChildItem $dir -Filter "*.exe")[0].FullName $zip = $exe -replace '\.exe$', '.nsis.zip' Compress-Archive -Path $exe -DestinationPath $zip -Force npx tauri signer sign --private-key "$env:TAURI_SIGNING_PRIVATE_KEY" --password "$env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD" $zip gh release upload "app-v$env:VERSION" $zip "$zip.sig" --clobber - name: sign and upload macOS bundle signature if: matrix.settings.platform == 'macos-latest' shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ needs.create-release.outputs.package_version }} run: | if [[ "${{ matrix.settings.args }}" == *"aarch64"* ]]; then BUNDLE="src-tauri/target/aarch64-apple-darwin/release/bundle/macos/Psysonic.app.tar.gz" SIG_NAME="Psysonic_aarch64.app.tar.gz.sig" else BUNDLE="src-tauri/target/x86_64-apple-darwin/release/bundle/macos/Psysonic.app.tar.gz" SIG_NAME="Psysonic_x64.app.tar.gz.sig" fi npx tauri signer sign --private-key "$TAURI_SIGNING_PRIVATE_KEY" --password "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" "$BUNDLE" cp "${BUNDLE}.sig" "$SIG_NAME" gh release upload "app-v${VERSION}" "$SIG_NAME" --clobber build-linux: needs: create-release permissions: contents: write runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v5 - name: install dependencies run: | sudo apt-get update sudo apt-get install -y \ libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf \ libasound2-dev - name: setup node uses: actions/setup-node@v5 with: node-version: lts/* - name: cache npm uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} restore-keys: ${{ runner.os }}-npm- - name: install Rust stable uses: dtolnay/rust-toolchain@stable - name: cache cargo uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - name: install npm dependencies run: npm install - name: build env: VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} run: npm run tauri:build -- --bundles deb,rpm - name: upload Linux artifacts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | VERSION=${{ needs.create-release.outputs.package_version }} find src-tauri/target/release/bundle \ \( -name "*.deb" -o -name "*.rpm" \) \ | xargs gh release upload "app-v${VERSION}" --clobber generate-manifest: needs: [create-release, build-macos-windows] permissions: contents: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: setup node uses: actions/setup-node@v5 with: node-version: lts/* - name: cache npm uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} restore-keys: ${{ runner.os }}-npm- - name: generate latest.json env: VERSION: ${{ needs.create-release.outputs.package_version }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node scripts/generate-update-manifest.js - name: upload latest.json env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | VERSION=${{ needs.create-release.outputs.package_version }} gh release upload "app-v${VERSION}" latest.json --clobber