chore(release): 0.9.3 #17
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Triggered when `np` (or manual `git tag`) pushes a semver tag. | |
| # Orchestrates: GitHub Release creation -> Desktop builds -> Mobile builds -> Checksums. | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g. 0.3.2)' | |
| required: true | |
| type: string | |
| # Minimal permissions — only contents:write for release management | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # ── 1. Create the GitHub Release ──────────────────────────────────────── | |
| create-release: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release_id: ${{ steps.create.outputs.id }} | |
| upload_url: ${{ steps.create.outputs.upload_url }} | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| persist-credentials: false | |
| - name: Extract and validate version | |
| id: version | |
| run: | | |
| VERSION="${{ github.event.inputs.version || '' }}" | |
| if [ -z "$VERSION" ]; then | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| fi | |
| # Validate semver format (major.minor.patch with optional pre-release) | |
| if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then | |
| echo "Error: tag does not match semver format: $VERSION" | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| # Clean slate: delete any pre-existing release for this tag so we don't | |
| # end up with duplicate releases (e.g., from a previous failed run that | |
| # left a stale draft, or from a re-trigger). The git tag is preserved. | |
| - name: Delete any pre-existing release for this tag | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| TAG="v${{ steps.version.outputs.version }}" | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "Found existing release $TAG — deleting to start clean" | |
| gh release delete "$TAG" --yes --cleanup-tag=false | |
| else | |
| echo "No existing release for $TAG" | |
| fi | |
| - name: Create GitHub Release | |
| id: create | |
| uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 | |
| with: | |
| draft: true | |
| prerelease: false | |
| generate_release_notes: true | |
| name: v${{ steps.version.outputs.version }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ── 2. Build Desktop (Tauri) ──────────────────────────────────────────── | |
| build-desktop: | |
| needs: create-release | |
| uses: ./.github/workflows/release-desktop.yml | |
| with: | |
| version: ${{ needs.create-release.outputs.version }} | |
| release_id: ${{ needs.create-release.outputs.release_id }} | |
| secrets: inherit | |
| # ── 2b. Build Android APK ────────────────────────────────────────────── | |
| build-android: | |
| needs: create-release | |
| uses: ./.github/workflows/release-mobile.yml | |
| with: | |
| version: ${{ needs.create-release.outputs.version }} | |
| release_id: ${{ needs.create-release.outputs.release_id }} | |
| secrets: inherit | |
| # ── 3. Generate checksums (best-effort) ──────────────────────────────── | |
| checksums: | |
| needs: [create-release, build-desktop, build-android] | |
| if: always() && needs.build-desktop.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: List existing release assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| echo "=== Release v${{ needs.create-release.outputs.version }} assets ===" | |
| gh release view "v${{ needs.create-release.outputs.version }}" \ | |
| --json assets --jq '.assets[].name' || echo "Failed to list assets" | |
| - name: Download release assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| mkdir -p artifacts | |
| # Download all non-checksum files from the release | |
| gh release download "v${{ needs.create-release.outputs.version }}" \ | |
| --dir artifacts \ | |
| --pattern '*.dmg' \ | |
| --pattern '*.app.tar.gz' \ | |
| --pattern '*.app.tar.gz.sig' \ | |
| --pattern '*.msi' \ | |
| --pattern '*.msi.zip' \ | |
| --pattern '*.msi.zip.sig' \ | |
| --pattern '*.nsis.zip' \ | |
| --pattern '*.nsis.zip.sig' \ | |
| --pattern '*.exe' \ | |
| --pattern '*.deb' \ | |
| --pattern '*.rpm' \ | |
| --pattern '*.AppImage' \ | |
| --pattern '*.AppImage.tar.gz' \ | |
| --pattern '*.AppImage.tar.gz.sig' \ | |
| --pattern '*.apk' \ | |
| --pattern '*.aab' \ | |
| --pattern '*.ipa' || true | |
| echo "=== Downloaded files ===" | |
| ls -la artifacts/ || true | |
| - name: Generate SHA-256 checksums | |
| id: sums | |
| run: | | |
| cd artifacts | |
| shopt -s nullglob | |
| files=( * ) | |
| if [ ${#files[@]} -gt 0 ]; then | |
| sha256sum -- "${files[@]}" | LC_ALL=C sort > SHA256SUMS.txt | |
| echo "=== SHA256SUMS.txt ===" | |
| cat SHA256SUMS.txt | |
| echo "=== File count: $(wc -l < SHA256SUMS.txt) ===" | |
| echo "generated=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No artifacts found to checksum — skipping (release will publish without SHA256SUMS.txt)" | |
| echo "generated=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Upload checksums to release | |
| if: steps.sums.outputs.generated == 'true' | |
| uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 | |
| with: | |
| tag_name: v${{ needs.create-release.outputs.version }} | |
| files: artifacts/SHA256SUMS.txt | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ── 4. Publish the release ───────────────────────────────────────────── | |
| # Publish as long as the desktop build succeeded — checksums are best-effort | |
| # and shouldn't block publishing the actual binaries. | |
| publish: | |
| needs: [create-release, build-desktop, build-android, checksums] | |
| if: always() && needs.build-desktop.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Publish release (remove draft status) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| gh release edit "v${{ needs.create-release.outputs.version }}" --draft=false |