Skip to content

chore(main): release 0.12.0 (#188) #147

chore(main): release 0.12.0 (#188)

chore(main): release 0.12.0 (#188) #147

name: Release Please
on:
push:
branches:
- main
permissions:
contents: write
pull-requests: write
jobs:
release-please:
name: Open or update release PR
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
pr: ${{ steps.release.outputs.pr }}
steps:
- uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
sync-cargo-lock:
name: Sync Cargo.lock into release PR
needs: release-please
# Runs when release-please opened/updated a PR but has not yet created a release
if: ${{ !needs.release-please.outputs.release_created && needs.release-please.outputs.pr }}
runs-on: ubuntu-latest
steps:
- name: Checkout release PR branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ fromJSON(needs.release-please.outputs.pr).headBranchName }}
- name: Install stable Rust toolchain
run: rustup toolchain install stable --no-self-update
- name: Update Cargo.lock for thuki package
working-directory: src-tauri
run: cargo update --package thuki
- name: Commit Cargo.lock if it changed
run: |
if ! git diff --quiet src-tauri/Cargo.lock; then
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add src-tauri/Cargo.lock
git commit -m "chore: sync Cargo.lock to version bump"
git push
else
echo "Cargo.lock already in sync, nothing to commit"
fi
build-and-release:
name: Build and publish macOS app
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.11
- name: Install stable Rust toolchain
run: rustup toolchain install stable --no-self-update
- name: Install nightly Rust toolchain
run: rustup toolchain install nightly-2026-03-30 --component llvm-tools --no-self-update
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@213ccc1a076163c093f914550b94feb90fab916d # v2.79.2
with:
tool: cargo-llvm-cov
- name: Install frontend dependencies
run: bun install --frozen-lockfile
- name: Lint and format check
run: bun run lint && bun run format:check
- name: Typecheck
run: bun run typecheck
- name: Run all tests with coverage enforcement
run: bun run test:all:coverage
- name: Build frontend
run: bun run build:frontend
- name: Build Tauri app
run: bun run build:backend
- name: Ad-hoc sign the app
run: |
codesign --deep --force --sign - src-tauri/target/release/bundle/macos/Thuki.app
codesign --verify --verbose src-tauri/target/release/bundle/macos/Thuki.app
- name: Pack and sign updater payload
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
TAG: ${{ needs.release-please.outputs.tag_name }}
working-directory: src-tauri/target/release/bundle/macos
run: |
VERSION="${TAG#v}"
PAYLOAD="Thuki_${VERSION}_aarch64.app.tar.gz"
tar czf "$PAYLOAD" Thuki.app
# Sign the payload with the project ed25519 key. The CLI reads the
# key + password from TAURI_SIGNING_PRIVATE_KEY[_PASSWORD] env vars.
bunx --bun @tauri-apps/cli signer sign "$PAYLOAD"
- name: Generate updater manifest
env:
TAG: ${{ needs.release-please.outputs.tag_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
working-directory: src-tauri/target/release/bundle/macos
run: |
VERSION="${TAG#v}"
PAYLOAD="Thuki_${VERSION}_aarch64.app.tar.gz"
SIG="$(cat "${PAYLOAD}.sig")"
PUB_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
DOWNLOAD_URL="https://github.com/quiet-node/thuki/releases/download/${TAG}/${PAYLOAD}"
# Embed the full release-please changelog (the GitHub Release body
# for this tag) so the in-app updater shows the real notes instead
# of a bare link. release-please always creates this release with a
# non-empty body before this job runs, so an empty body means
# something upstream broke: fail loudly rather than ship a manifest
# whose notes are blank.
gh release view "$TAG" --json body --jq .body > release-notes.md
if [ ! -s release-notes.md ]; then
echo "::error::GitHub Release body for ${TAG} is empty; refusing to publish a manifest with no notes." >&2
exit 1
fi
# jq --rawfile keeps newlines, quotes, backticks and $ in the
# changelog JSON-safe (the old heredoc interpolation could not).
jq -n \
--arg version "$VERSION" \
--rawfile notes release-notes.md \
--arg pub_date "$PUB_DATE" \
--arg sig "$SIG" \
--arg url "$DOWNLOAD_URL" \
'{version: $version, notes: $notes, pub_date: $pub_date, platforms: {"darwin-aarch64": {signature: $sig, url: $url}}}' \
> latest.json
rm -f release-notes.md
- name: Install create-dmg
run: brew install create-dmg
- name: Create DMG installer
run: |
# Stage only the .app — exclude any leftover build artifacts
# (e.g. Thuki.app.tar.gz) from the bundle directory.
mkdir -p /tmp/thuki-dmg-src
cp -r src-tauri/target/release/bundle/macos/Thuki.app /tmp/thuki-dmg-src/
mkdir -p src-tauri/target/release/bundle/dmg
create-dmg \
--volname "Thuki" \
--background "src-tauri/assets/dmg-background.png" \
--window-pos 200 120 \
--window-size 600 380 \
--icon-size 128 \
--icon "Thuki.app" 170 170 \
--hide-extension "Thuki.app" \
--app-drop-link 430 170 \
"src-tauri/target/release/bundle/dmg/Thuki.dmg" \
"/tmp/thuki-dmg-src"
rm -rf /tmp/thuki-dmg-src
- name: Upload release assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.release-please.outputs.tag_name }}
working-directory: src-tauri/target/release/bundle
run: |
VERSION="${TAG#v}"
PAYLOAD="Thuki_${VERSION}_aarch64.app.tar.gz"
gh release upload "$TAG" \
"dmg/Thuki.dmg" \
"macos/${PAYLOAD}" \
"macos/${PAYLOAD}.sig" \
"macos/latest.json"