Files
gart/code/Hex-main/docs/release-process.md
T

4.0 KiB
Executable File

Hex Release Process

Overview

Releases are triggered by pushing git tags. The system automatically:

  • Builds & signs the app
  • Notarizes with Apple
  • Creates DMG + ZIP artifacts
  • Uploads to S3 for Sparkle updates
  • Creates GitHub release

Quick Start

# Create and push a tag
git tag v0.2.12
git push origin v0.2.12

# GitHub Actions will automatically:
# 1. Build Hex v0.2.12
# 2. Notarize with Apple
# 3. Upload to S3 (Sparkle)
# 4. Create GitHub release with DMG + ZIP

Architecture

Tag-based versioning:

  • Tag v0.2.12 → builds version 0.2.12
  • Updates Info.plist and project.pbxproj
  • Auto-increments build number

Effect Config system:

// Reads from environment variables
BUCKET=hex-updates              // Default
VERSION=v0.2.12                  // From git tag
APPLE_ID=your@email.com         // CI only
APPLE_ID_PASSWORD=xxxx-xxxx     // CI only
AWS_ACCESS_KEY_ID=...           // Required
AWS_SECRET_ACCESS_KEY=...       // Required

Local vs CI:

  • Local: Uses keychain profile AC_PASSWORD
  • CI: Uses APPLE_ID / APPLE_ID_PASSWORD env vars

Local Testing

# Setup keychain profile (one-time)
xcrun notarytool store-credentials "AC_PASSWORD"

# Test release locally (doesn't upload)
cd tools
VERSION=v0.2.12-test \
  AWS_ACCESS_KEY_ID=... \
  AWS_SECRET_ACCESS_KEY=... \
  bun run release.ts

Required Secrets

Set via: gh secret set SECRET_NAME

Apple (Notarization)

APPLE_ID                    # your@email.com
APPLE_ID_PASSWORD          # App-specific password from appleid.apple.com
TEAM_ID                     # QC99C9JE59

Code Signing

MACOS_CERTIFICATE          # base64 -i cert.p12 | pbcopy
MACOS_CERTIFICATE_PWD      # Certificate password

AWS (S3 / Sparkle)

AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY

Artifacts

Each release creates:

  • Hex-{version}.dmg - Signed, notarized DMG
  • Hex-{version}.zip - For Homebrew cask
  • hex-latest.dmg - Always points to latest
  • appcast.xml - Sparkle update feed

Homebrew Cask

After first release, update hex.rb:

# Get SHA256
curl -L https://github.com/kitlangton/Hex/releases/download/v0.2.12/Hex-v0.2.12.zip -o Hex.zip
shasum -a 256 Hex.zip

# Update hex.rb with version and SHA

Submit to:

  • Personal tap: homebrew-hex (easier)
  • Official cask: PR to homebrew/homebrew-cask

Critical Constraints

CFBundleVersion Requirements

NEVER manually edit CFBundleVersion or reuse build numbers. The release pipeline automatically increments CFBundleVersion with each release to ensure Sparkle can properly generate the appcast feed.

  • updates/ directory must only contain DMGs with strictly increasing CFBundleVersion values
  • Duplicate build numbers will block appcast generation and break updates for existing users
  • The release script preserves the last 3 DMGs in updates/ for delta generation
  • Older versions are automatically moved to updates/old_updates/

If you accidentally create a release with a duplicate CFBundleVersion:

  1. Delete the problematic DMG from updates/
  2. Move any other old DMGs to updates/old_updates/
  3. Regenerate appcast: ./bin/generate_appcast --maximum-deltas 3 updates
  4. Re-upload cleaned artifacts to S3

Troubleshooting

Notarization fails

  • Check Apple ID credentials
  • Verify app-specific password
  • Ensure TEAM_ID is correct

S3 upload fails

  • Verify AWS credentials
  • Check bucket permissions
  • Ensure bucket exists

Build fails

  • Check Xcode version (16.2)
  • Verify code signing setup
  • Check certificate validity

Sparkle updates not appearing

  • Verify appcast.xml lists versions in descending CFBundleVersion order
  • Check that CFBundleVersion values are unique and strictly increasing
  • Ensure no duplicate build numbers exist in updates/
  • Test feed URL: https://hex-updates.s3.amazonaws.com/appcast.xml

Files

  • tools/release.ts - Main release script (Effect)
  • .github/workflows/release.yml - CI workflow
  • bin/generate_appcast - Sparkle appcast generator
  • hex.rb - Homebrew cask formula