Skip to content

chore(release): 0.9.0 #13

chore(release): 0.9.0

chore(release): 0.9.0 #13

Workflow file for this run

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 }}
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