name: Publish Release on: workflow_run: workflows: ["Release"] types: [completed] workflow_dispatch: inputs: dry_run: description: 'Build artifacts only, skip uploading to GitHub Release' required: false type: boolean default: true allow_update_published_release: description: 'Allow uploading assets to an already published release' required: false type: boolean default: false jobs: check-release: name: Check for new release runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' permissions: contents: read outputs: tag: ${{ steps.get_tag.outputs.tag }} has_release: ${{ steps.get_tag.outputs.has_release }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Get latest release tag id: get_tag env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then version="$(node -e "process.stdout.write(require('./package.json').version)")" tag="v$version" echo "tag=$tag" >> "$GITHUB_OUTPUT" echo "has_release=true" >> "$GITHUB_OUTPUT" else tag=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // empty') if [ -n "$tag" ]; then echo "tag=$tag" >> "$GITHUB_OUTPUT" echo "has_release=true" >> "$GITHUB_OUTPUT" echo "Found release: $tag" else echo "has_release=false" >> "$GITHUB_OUTPUT" echo "No release found, skipping build." fi fi build: needs: check-release if: needs.check-release.outputs.has_release == 'true' strategy: fail-fast: false matrix: include: - os: windows-latest platform: win32 arch: x64 - os: windows-11-arm platform: win32 arch: arm64 - os: macos-15-intel platform: darwin arch: x64 - os: macos-14 platform: darwin arch: arm64 - os: ubuntu-latest platform: linux arch: x64 - os: ubuntu-24.04-arm platform: linux arch: arm64 runs-on: ${{ matrix.os }} permissions: contents: read steps: - name: Checkout git repo uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v4 with: version: 10 - name: Install Node and NPM uses: actions/setup-node@v4 with: node-version: 20 cache: 'pnpm' - name: Install Linux dependencies if: matrix.platform == 'linux' run: | sudo apt-get update sudo apt-get install -y fakeroot rpm libsecret-1-dev pkg-config - name: Ensure WiX Toolset if: matrix.platform == 'win32' && matrix.arch == 'x64' shell: powershell run: | $installed = choco list --local-only wixtoolset --exact --limit-output if (-not $installed) { choco install wixtoolset --version=3.14.0 -y } elseif ($installed -match '^wixtoolset\|3\.14(\.|$)') { Write-Host "WiX Toolset already compatible: $installed" } else { Write-Host "Incompatible WiX Toolset detected: $installed" choco upgrade wixtoolset --version=3.14.0 --allow-downgrade -y } - name: Install dependencies run: pnpm install --frozen-lockfile - name: Make Artifacts if: matrix.platform != 'darwin' env: NODE_OPTIONS: --max-old-space-size=8192 SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ secrets.SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} run: pnpm run make -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }} # DMG creation may be flaky on GitHub macOS runners, so retry the full darwin make. - name: Make Artifacts (darwin with retry) if: matrix.platform == 'darwin' uses: nick-fields/retry@v3 with: max_attempts: 3 timeout_minutes: 20 retry_wait_seconds: 20 command: pnpm run make -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }} env: NODE_OPTIONS: --max-old-space-size=8192 SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ secrets.SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} - name: Upload Build Artifacts uses: actions/upload-artifact@v4 with: name: make-${{ matrix.platform }}-${{ matrix.arch }} path: | out/make/**/*.exe out/make/**/*.dmg out/make/**/*.zip out/make/**/*.AppImage out/make/**/*.deb out/make/**/*.rpm out/make/**/*.msi out/make/**/*.yml out/make/**/*.txt if-no-files-found: error retention-days: 14 - name: Dry-run summary if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true' run: | echo "Dry run enabled: build artifacts generated and uploaded; release publish step will be skipped." publish: name: Publish Release needs: [check-release, build] runs-on: ubuntu-latest if: needs.build.result == 'success' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true') permissions: contents: write steps: - name: Checkout git repo uses: actions/checkout@v4 - name: Download Build Artifacts uses: actions/download-artifact@v4 with: pattern: make-* merge-multiple: true path: release-assets - name: Resolve release tag id: release_tag run: | tag="${{ needs.check-release.outputs.tag }}" if [ -z "$tag" ]; then version="$(node -e "process.stdout.write(require('./package.json').version)")" tag="v$version" fi echo "tag=$tag" >> "$GITHUB_OUTPUT" echo "Using release tag: $tag" - name: Upload assets to release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ steps.release_tag.outputs.tag }} run: | mapfile -t files < <(find release-assets -type f \( \ -name '*.exe' -o \ -name '*.dmg' -o \ -name '*.zip' -o \ -name '*.AppImage' -o \ -name '*.deb' -o \ -name '*.rpm' -o \ -name '*.msi' -o \ -name '*.yml' -o \ -name '*.txt' \ \) | sort) if [ "${#files[@]}" -eq 0 ]; then echo "::error::No release assets found under release-assets/" exit 1 fi printf 'Uploading %s assets to %s\n' "${#files[@]}" "$RELEASE_TAG" gh release upload "$RELEASE_TAG" "${files[@]}" --clobber