Increments desktop app version to alpha.8 #31
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: Build & Release macOS .dmg | |
on: | |
push: | |
tags: | |
- "v*" # e.g., v1.0.0 | |
workflow_dispatch: | |
permissions: | |
contents: write | |
jobs: | |
build: | |
name: Build Tauri macOS App | |
runs-on: macos-latest | |
environment: Production | |
steps: | |
- name: 📥 Checkout Code | |
uses: actions/checkout@v4 | |
- name: 🦀 Install Rust | |
uses: dtolnay/rust-toolchain@stable | |
with: | |
targets: x86_64-apple-darwin,aarch64-apple-darwin | |
- name: 📦 Install pnpm & dependencies | |
working-directory: desktop | |
run: | | |
corepack enable | |
pnpm install | |
- name: 📝 Verify signing script exists | |
run: | | |
# Check if script exists | |
if [ ! -f "desktop/scripts/sign-externals.sh" ]; then | |
echo "❌ Sign script not found! Make sure you're using a tag that includes the script." | |
echo "Available files in desktop/:" | |
ls -la desktop/ | |
exit 1 | |
fi | |
echo "✅ Sign script found: desktop/scripts/sign-externals.sh" | |
echo "Script will be made executable by beforeBuildCommand" | |
- name: 🪪 Setup Code Signing (Build Phase) | |
run: | | |
# Import certificate for build-time signing | |
echo "$APPLE_CERTIFICATE" | tr -d '\n\r\t ' | base64 -d > certificate.p12 | |
security create-keychain -p "build" build.keychain | |
security default-keychain -s build.keychain | |
security unlock-keychain -p "build" build.keychain | |
security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "build" build.keychain | |
rm certificate.p12 | |
env: | |
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
- name: 🛠️ Build Tauri App with Signed Binaries | |
working-directory: desktop | |
run: | | |
pnpm tauri build --bundles dmg | |
env: | |
HUMAAN_ENV: production | |
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
- name: 🧾 Check if .dmg exists | |
run: ls -al target/release/bundle/dmg/ | |
- name: 🧹 Clean up build keychain | |
run: security delete-keychain build.keychain || true | |
- name: 📤 Upload signed .dmg | |
uses: actions/upload-artifact@v4 | |
with: | |
name: signed-dmg | |
path: target/release/bundle/dmg/*.dmg | |
sign-and-notarize: | |
name: Sign & Notarize | |
needs: build | |
runs-on: macos-latest | |
environment: Production | |
env: | |
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
APPLE_API_PRIVATE_KEY: ${{ secrets.APPLE_API_PRIVATE_KEY }} | |
steps: | |
- name: 📥 Download signed .dmg | |
uses: actions/download-artifact@v4 | |
with: | |
name: signed-dmg | |
path: ./signed-dmg | |
- name: ✅ Check signed .dmg | |
run: ls -al ./signed-dmg/ | |
- name: 📝 Save API Key to File | |
run: | | |
# Validate API key before use | |
if [ -z "$APPLE_API_PRIVATE_KEY" ]; then | |
echo "Error: APPLE_API_PRIVATE_KEY is empty or not set" | |
exit 1 | |
fi | |
echo "$APPLE_API_PRIVATE_KEY" > ./AuthKey.p8 | |
- name: 📩 Notarize with Apple | |
run: | | |
for f in ./signed-dmg/*.dmg; do | |
echo "Submitting $f for notarization..." | |
# Submit and capture the submission ID | |
SUBMISSION_OUTPUT=$(xcrun notarytool submit "$f" \ | |
--key ./AuthKey.p8 \ | |
--key-id "$APPLE_API_KEY" \ | |
--issuer "$APPLE_API_ISSUER" \ | |
--wait) | |
echo "$SUBMISSION_OUTPUT" | |
# Extract submission ID for verification | |
SUBMISSION_ID=$(echo "$SUBMISSION_OUTPUT" | grep "id:" | head -1 | awk '{print $2}') | |
if [ -n "$SUBMISSION_ID" ]; then | |
echo "Submission ID: $SUBMISSION_ID" | |
# Get detailed status | |
echo "=== Detailed Notarization Status ===" | |
xcrun notarytool info "$SUBMISSION_ID" \ | |
--key ./AuthKey.p8 \ | |
--key-id "$APPLE_API_KEY" \ | |
--issuer "$APPLE_API_ISSUER" | |
echo "==================================" | |
# If status is not Accepted, get the detailed log | |
if echo "$SUBMISSION_OUTPUT" | grep -q "status: Invalid\|status: Rejected"; then | |
echo "=== Notarization FAILED - Getting Detailed Log ===" | |
xcrun notarytool log "$SUBMISSION_ID" \ | |
--key ./AuthKey.p8 \ | |
--key-id "$APPLE_API_KEY" \ | |
--issuer "$APPLE_API_ISSUER" | |
echo "==============================================" | |
echo "❌ Notarization failed for $f with detailed errors above" | |
exit 1 | |
fi | |
fi | |
# Check if notarization was successful | |
if echo "$SUBMISSION_OUTPUT" | grep -q "status: Accepted"; then | |
echo "✅ Notarization successful for $f" | |
else | |
echo "❌ Notarization failed for $f" | |
echo "Full output: $SUBMISSION_OUTPUT" | |
exit 1 | |
fi | |
done | |
- name: 📎 Staple Notarization Ticket | |
run: | | |
for f in ./signed-dmg/*.dmg; do | |
echo "Attempting to staple $f..." | |
# Retry stapling with exponential backoff | |
RETRY_COUNT=0 | |
MAX_RETRIES=5 | |
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
if xcrun stapler staple "$f"; then | |
echo "✅ Successfully stapled $f" | |
# Validate the stapled ticket | |
xcrun stapler validate "$f" | |
break | |
else | |
RETRY_COUNT=$((RETRY_COUNT + 1)) | |
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then | |
DELAY=$((2 ** RETRY_COUNT * 10)) # 20s, 40s, 80s, 160s | |
echo "⏳ Stapling failed, retrying in ${DELAY}s (attempt $RETRY_COUNT/$MAX_RETRIES)..." | |
sleep $DELAY | |
else | |
echo "❌ Failed to staple $f after $MAX_RETRIES attempts" | |
echo "⚠️ The DMG is notarized but not stapled. It will still work but may show warnings." | |
# Don't exit - continue with unstapled but notarized DMG | |
fi | |
fi | |
done | |
done | |
- name: 📤 Upload notarized .dmg | |
uses: actions/upload-artifact@v4 | |
with: | |
name: notarized-dmg | |
path: ./signed-dmg/*.dmg | |
- name: 🧹 Clean up API key | |
run: rm -f ./AuthKey.p8 | |
release: | |
name: Upload to GitHub Release | |
needs: sign-and-notarize | |
runs-on: macos-latest | |
if: startsWith(github.ref, 'refs/tags/') | |
steps: | |
- name: 📥 Download notarized .dmg | |
uses: actions/download-artifact@v4 | |
with: | |
name: notarized-dmg | |
path: ./notarized-dmg | |
- name: 🏷️ Get version from tag | |
id: version | |
run: | | |
VERSION=${GITHUB_REF#refs/tags/} | |
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
echo "Version: $VERSION" | |
- name: 📝 Rename DMG with version | |
run: | | |
# Work with files directly instead of cd | |
for f in notarized-dmg/*.dmg; do | |
if [ -f "$f" ]; then | |
# Extract base name without extension | |
BASE_NAME=$(basename "$f" .dmg) | |
# Create new name with version and OS info | |
NEW_NAME="notarized-dmg/humaan-${{ steps.version.outputs.VERSION }}-macos-arm64.dmg" | |
mv "$f" "$NEW_NAME" | |
echo "Renamed $f to $NEW_NAME" | |
else | |
echo "No DMG files found in notarized-dmg/" | |
echo "Available files:" | |
ls -la notarized-dmg/ || echo "Directory does not exist" | |
exit 1 | |
fi | |
done | |
echo "=== Final files ===" | |
ls -la notarized-dmg/ | |
- name: 🚀 Upload .dmg to GitHub Release | |
uses: softprops/action-gh-release@v1 | |
with: | |
files: notarized-dmg/*.dmg | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |