Skip to content

Merge pull request #20 from beautyfree/release-please--branches--main… #22

Merge pull request #20 from beautyfree/release-please--branches--main…

Merge pull request #20 from beautyfree/release-please--branches--main… #22

Workflow file for this run

name: Release
# Two triggers that cover the two ways a release lands here:
#
# 1. `release: [created]` — fires when release-please creates the draft
# release after its PR is merged. This is the normal path. Draft
# releases don't create a git tag until they're published, so tag
# push alone wouldn't fire (see commit 4032f11 for the draft switch).
#
# 2. `push: tags: v*` — fallback for when a maintainer hand-creates a
# tag locally (e.g. to rebuild a release whose assets got corrupted).
# Also covers anyone using a PAT-based release-please flow where the
# tag push genuinely does trigger workflows.
#
# Both paths resolve the tag/release via TAG_NAME below so the downstream
# softprops/gh-release steps don't care which trigger fired.
on:
release:
types: [created]
push:
tags:
- "v*"
permissions:
contents: write
concurrency:
# Deduplicate by tag so the `release: created` + late `push: tags` never
# run simultaneously for the same version.
group: ${{ github.workflow }}-${{ github.event.release.tag_name || github.ref }}
cancel-in-progress: false
jobs:
build-desktop:
name: Build ${{ matrix.label }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- label: macos
runner: macos-14
script: dist:mac
- label: windows-x64
runner: windows-latest
script: dist:win
- label: linux-x64
runner: ubuntu-latest
script: dist:linux
steps:
- uses: actions/checkout@v5
with:
# On `release: created` for a draft, there's no git tag yet — use
# the release's target commit sha. On tag push, github.ref resolves
# to the tag itself (checkout picks that up by default).
ref: ${{ github.event.release.target_commitish || github.ref }}
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# create-dmg builds the styled drag-to-Applications DMG that
# scripts/repack-dmg.sh wraps around electron-builder's signed .app.
- name: Install create-dmg (macOS)
if: runner.os == 'macOS'
run: brew install create-dmg
# Native module build toolchain for better-sqlite3 under Electron's ABI.
- name: Install Linux deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential pkg-config python3 \
libxss1 libnss3 libasound2t64 \
fakeroot dpkg
- run: bun install --frozen-lockfile
# Rebuild native modules (better-sqlite3) against the Electron ABI
# bundled by electron-builder. Runs on every OS — electron-builder
# handles the platform-specific node-gyp invocation.
- name: Rebuild native modules
run: bunx electron-builder install-app-deps
# Import the Developer ID signing cert into a temporary keychain.
# Without this, electron-builder's codesign step fails with
# "The specified item could not be found in the keychain."
- name: Import Developer ID certificate (macOS)
if: runner.os == 'macOS'
env:
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_P12_PASSWORD: ${{ secrets.MACOS_CERT_P12_PASSWORD }}
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/skiller-build.keychain-db"
CERT_PATH="$RUNNER_TEMP/cert.p12"
echo "$MACOS_CERT_P12" | base64 --decode > "$CERT_PATH"
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERT_PATH" \
-P "$MACOS_CERT_P12_PASSWORD" \
-A -t cert -f pkcs12 \
-k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple:,codesign: \
-s -k "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain
rm -f "$CERT_PATH"
# notarytool / @electron/notarize needs the .p8 file on disk. Secret
# should be the raw contents of AuthKey_XXXX.p8 (multiline).
- name: Write notarization API key (macOS)
if: runner.os == 'macOS' && env.APPLE_API_KEY_P8 != ''
env:
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
run: |
KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
printf '%s' "$APPLE_API_KEY_P8" > "$KEY_PATH"
chmod 600 "$KEY_PATH"
echo "APPLE_API_KEY=$KEY_PATH" >> "$GITHUB_ENV"
- name: Build app
env:
# electron-builder reads GH_TOKEN for its publish step; we publish
# via softprops below instead but the var being set also unlocks
# electron-builder's release-draft verification.
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# macOS signing + notarization. Env-var names follow electron-builder's
# conventions (NB: `APPLE_API_ISSUER`, not `APPLE_API_KEY_ISSUER` —
# electron-builder rejects the "_KEY_" variant).
CSC_NAME: ${{ secrets.CSC_NAME }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: bun run ${{ matrix.script }}
# Upload every artifact (including latest-*.yml and .blockmap files —
# electron-updater needs them alongside the binaries).
# The release itself (with CHANGELOG body) was already created by
# release-please when the Release PR merged — we only attach assets.
- name: Upload build outputs to Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.release.tag_name || github.ref_name }}
# release-please creates the Release as a draft (see config). We
# keep it a draft here too so softprops doesn't accidentally flip
# it to published — the final publish-release job does that after
# all three OS builds finish.
draft: true
# GitHub Releases shows assets in reverse upload order (newest on
# top). Upload the auto-updater plumbing (yml, blockmap, zip) FIRST
# and the human-facing installers LAST so the download list leads
# with .dmg / .exe / .AppImage instead of the .zip that
# electron-updater needs but end users should ignore.
files: |
artifacts/*.yml
artifacts/*.blockmap
artifacts/*.zip
artifacts/*.tar.xz
artifacts/*.deb
artifacts/*.AppImage
artifacts/*.exe
artifacts/*.dmg
fail_on_unmatched_files: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Flip the release from draft to published ONLY after every matrix build
# succeeded and uploaded its artifacts. This avoids the awkward window where
# a user lands on the Releases page with only the Linux installer visible
# because mac/win builds are still running.
publish-release:
needs: build-desktop
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Publish draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release edit "${{ github.event.release.tag_name || github.ref_name }}" \
--repo "${{ github.repository }}" \
--draft=false