mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00

Resolves #7591 This moves our CI to build macOS on Sequoia (macOS 15) with Xcode 26, including the new macOS 26 beta SDK. Importantly, this will make our builds on macOS 26 use the new styling. I've added a new job that ensures we can continue to build with Xcode 16 and the macOS 15 SDK, as well, although I think that might come to an end when we switch over to an IconComposer-based icon. I'll verify then. For now, we continue to support both. I've also removed our `hasLiquidGlass` check, since this will now always be true for macOS 26 builds.
352 lines
18 KiB
YAML
352 lines
18 KiB
YAML
on:
|
|
workflow_dispatch: {}
|
|
|
|
name: Release PR
|
|
|
|
jobs:
|
|
sentry-dsym-debug:
|
|
runs-on: namespace-profile-ghostty-sm
|
|
needs: [build-macos-debug]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install sentry-cli
|
|
run: |
|
|
curl -sL https://sentry.io/get-cli/ | bash
|
|
|
|
- name: Download dSYM
|
|
run: |
|
|
GHOSTTY_COMMIT_LONG=$(git rev-parse HEAD)
|
|
curl -L https://pr.files.ghostty.dev/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal-debug-dsym.zip > dsym.zip
|
|
|
|
- name: Upload dSYM to Sentry
|
|
env:
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
run: |
|
|
sentry-cli dif upload --project ghostty --wait dsym.zip
|
|
|
|
sentry-dsym:
|
|
runs-on: namespace-profile-ghostty-sm
|
|
needs: [build-macos]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install sentry-cli
|
|
run: |
|
|
curl -sL https://sentry.io/get-cli/ | bash
|
|
|
|
- name: Download dSYM
|
|
run: |
|
|
GHOSTTY_COMMIT_LONG=$(git rev-parse HEAD)
|
|
curl -L https://pr.files.ghostty.dev/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal-dsym.zip > dsym.zip
|
|
|
|
- name: Upload dSYM to Sentry
|
|
env:
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
run: |
|
|
sentry-cli dif upload --project ghostty --wait dsym.zip
|
|
|
|
build-macos:
|
|
runs-on: namespace-profile-ghostty-macos-sequoia
|
|
timeout-minutes: 90
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
# Important so that build number generation works
|
|
fetch-depth: 0
|
|
|
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
|
- uses: cachix/install-nix-action@v31
|
|
with:
|
|
nix_path: nixpkgs=channel:nixos-unstable
|
|
- uses: cachix/cachix-action@v16
|
|
with:
|
|
name: ghostty
|
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
|
|
|
# Setup Sparkle
|
|
- name: Setup Sparkle
|
|
env:
|
|
SPARKLE_VERSION: 2.6.4
|
|
run: |
|
|
mkdir -p .action/sparkle
|
|
cd .action/sparkle
|
|
curl -L https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-for-Swift-Package-Manager.zip > sparkle.zip
|
|
unzip sparkle.zip
|
|
echo "$(pwd)/bin" >> $GITHUB_PATH
|
|
|
|
# Load Build Number
|
|
- name: Build Number
|
|
run: |
|
|
echo "GHOSTTY_BUILD=$(git rev-list --count head)" >> $GITHUB_ENV
|
|
echo "GHOSTTY_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
|
echo "GHOSTTY_COMMIT_LONG=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
|
|
|
# GhosttyKit is the framework that is built from Zig for our native
|
|
# Mac app to access. Build this in release mode.
|
|
- name: Build GhosttyKit
|
|
run: nix develop -c zig build -Doptimize=ReleaseSafe
|
|
|
|
# The native app is built with native XCode tooling. This also does
|
|
# codesigning. IMPORTANT: this must NOT run in a Nix environment.
|
|
# Nix breaks xcodebuild so this has to be run outside.
|
|
- name: Build Ghostty.app
|
|
run: |
|
|
cd macos
|
|
sudo xcode-select -s /Applications/Xcode_26.0.app
|
|
xcodebuild -target Ghostty -configuration Release
|
|
|
|
# We inject the "build number" as simply the number of commits since HEAD.
|
|
# This will be a monotonically always increasing build number that we use.
|
|
- name: Update Info.plist
|
|
env:
|
|
SPARKLE_KEY_PUB: ${{ secrets.PROD_MACOS_SPARKLE_KEY_PUB }}
|
|
run: |
|
|
# Version Info
|
|
/usr/libexec/PlistBuddy -c "Set :GhosttyCommit $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $GHOSTTY_BUILD" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
|
|
# Updater
|
|
/usr/libexec/PlistBuddy -c "Set :SUPublicEDKey $SPARKLE_KEY_PUB" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Delete :SUEnableAutomaticChecks" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
|
|
- name: Codesign app bundle
|
|
env:
|
|
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
|
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
|
run: |
|
|
# Turn our base64-encoded certificate back to a regular .p12 file
|
|
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
|
|
|
|
# We need to create a new keychain, otherwise using the certificate will prompt
|
|
# with a UI dialog asking for the certificate password, which we can't
|
|
# use in a headless CI environment
|
|
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
security default-keychain -s build.keychain
|
|
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
|
|
# Codesign Sparkle. Some notes here:
|
|
# - The XPC services aren't used since we don't sandbox Ghostty,
|
|
# but since they're part of the build, they still need to be
|
|
# codesigned.
|
|
# - The binaries in the "Versions" folders need to NOT be symlinks.
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Downloader.xpc"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Installer.xpc"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Updater.app"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework"
|
|
|
|
# Codesign the app bundle
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime --entitlements "macos/Ghostty.entitlements" macos/build/Release/Ghostty.app
|
|
|
|
- name: "Notarize app bundle"
|
|
env:
|
|
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
|
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
|
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
|
run: |
|
|
# Store the notarization credentials so that we can prevent a UI password dialog
|
|
# from blocking the CI
|
|
echo "Create keychain profile"
|
|
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
|
|
|
|
# We can't notarize an app bundle directly, but we need to compress it as an archive.
|
|
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
|
# notarization service
|
|
echo "Creating temp notarization archive"
|
|
ditto -c -k --keepParent "macos/build/Release/Ghostty.app" "notarization.zip"
|
|
|
|
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
|
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
|
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
|
|
# you're curious
|
|
echo "Notarize app"
|
|
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
|
|
|
|
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
|
# validated by macOS even when an internet connection is not available.
|
|
echo "Attach staple"
|
|
xcrun stapler staple "macos/build/Release/Ghostty.app"
|
|
|
|
# Zip up the app
|
|
- name: Zip App
|
|
run: |
|
|
cd macos/build/Release
|
|
zip -9 -r --symlinks ../../../ghostty-macos-universal.zip Ghostty.app
|
|
zip -9 -r --symlinks ../../../ghostty-macos-universal-dsym.zip Ghostty.app.dSYM/
|
|
|
|
# Update Blob Storage
|
|
- name: Prep R2 Storage
|
|
run: |
|
|
mkdir blob
|
|
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
|
|
cp ghostty-macos-universal.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal.zip
|
|
cp ghostty-macos-universal-dsym.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal-dsym.zip
|
|
- name: Upload to R2
|
|
uses: ryand56/r2-upload-action@latest
|
|
with:
|
|
r2-account-id: ${{ secrets.CF_R2_PR_ACCOUNT_ID }}
|
|
r2-access-key-id: ${{ secrets.CF_R2_PR_AWS_KEY }}
|
|
r2-secret-access-key: ${{ secrets.CF_R2_PR_SECRET_KEY }}
|
|
r2-bucket: ghostty-pr
|
|
source-dir: blob
|
|
destination-dir: ./
|
|
|
|
build-macos-debug:
|
|
runs-on: namespace-profile-ghostty-macos-sequoia
|
|
timeout-minutes: 90
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
# Important so that build number generation works
|
|
fetch-depth: 0
|
|
|
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
|
- uses: cachix/install-nix-action@v31
|
|
with:
|
|
nix_path: nixpkgs=channel:nixos-unstable
|
|
- uses: cachix/cachix-action@v16
|
|
with:
|
|
name: ghostty
|
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
|
|
|
# Setup Sparkle
|
|
- name: Setup Sparkle
|
|
env:
|
|
SPARKLE_VERSION: 2.5.1
|
|
run: |
|
|
mkdir -p .action/sparkle
|
|
cd .action/sparkle
|
|
curl -L https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-for-Swift-Package-Manager.zip > sparkle.zip
|
|
unzip sparkle.zip
|
|
echo "$(pwd)/bin" >> $GITHUB_PATH
|
|
|
|
# Load Build Number
|
|
- name: Build Number
|
|
run: |
|
|
echo "GHOSTTY_BUILD=$(git rev-list --count head)" >> $GITHUB_ENV
|
|
echo "GHOSTTY_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
|
echo "GHOSTTY_COMMIT_LONG=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
|
|
|
# GhosttyKit is the framework that is built from Zig for our native
|
|
# Mac app to access. Build this in release mode.
|
|
- name: Build GhosttyKit
|
|
run: nix develop -c zig build -Doptimize=Debug
|
|
|
|
# The native app is built with native XCode tooling. This also does
|
|
# codesigning. IMPORTANT: this must NOT run in a Nix environment.
|
|
# Nix breaks xcodebuild so this has to be run outside.
|
|
- name: Build Ghostty.app
|
|
run: |
|
|
cd macos
|
|
sudo xcode-select -s /Applications/Xcode_26.0.app
|
|
xcodebuild -target Ghostty -configuration Release
|
|
|
|
# We inject the "build number" as simply the number of commits since HEAD.
|
|
# This will be a monotonically always increasing build number that we use.
|
|
- name: Update Info.plist
|
|
env:
|
|
SPARKLE_KEY_PUB: ${{ secrets.PROD_MACOS_SPARKLE_KEY_PUB }}
|
|
run: |
|
|
# Version Info
|
|
/usr/libexec/PlistBuddy -c "Set :GhosttyCommit $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $GHOSTTY_BUILD" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
|
|
# Updater
|
|
/usr/libexec/PlistBuddy -c "Set :SUPublicEDKey $SPARKLE_KEY_PUB" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Delete :SUEnableAutomaticChecks" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
|
|
|
- name: Codesign app bundle
|
|
env:
|
|
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
|
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
|
run: |
|
|
# Turn our base64-encoded certificate back to a regular .p12 file
|
|
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
|
|
|
|
# We need to create a new keychain, otherwise using the certificate will prompt
|
|
# with a UI dialog asking for the certificate password, which we can't
|
|
# use in a headless CI environment
|
|
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
security default-keychain -s build.keychain
|
|
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
|
|
# Codesign Sparkle. Some notes here:
|
|
# - The XPC services aren't used since we don't sandbox Ghostty,
|
|
# but since they're part of the build, they still need to be
|
|
# codesigned.
|
|
# - The binaries in the "Versions" folders need to NOT be symlinks.
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Downloader.xpc"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Installer.xpc"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Updater.app"
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework"
|
|
|
|
# Codesign the app bundle
|
|
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime --entitlements "macos/Ghostty.entitlements" macos/build/Release/Ghostty.app
|
|
|
|
- name: "Notarize app bundle"
|
|
env:
|
|
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
|
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
|
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
|
run: |
|
|
# Store the notarization credentials so that we can prevent a UI password dialog
|
|
# from blocking the CI
|
|
echo "Create keychain profile"
|
|
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
|
|
|
|
# We can't notarize an app bundle directly, but we need to compress it as an archive.
|
|
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
|
# notarization service
|
|
echo "Creating temp notarization archive"
|
|
ditto -c -k --keepParent "macos/build/Release/Ghostty.app" "notarization.zip"
|
|
|
|
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
|
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
|
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
|
|
# you're curious
|
|
echo "Notarize app"
|
|
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
|
|
|
|
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
|
# validated by macOS even when an internet connection is not available.
|
|
echo "Attach staple"
|
|
xcrun stapler staple "macos/build/Release/Ghostty.app"
|
|
|
|
# Zip up the app
|
|
- name: Zip App
|
|
run: |
|
|
cd macos/build/Release
|
|
zip -9 -r --symlinks ../../../ghostty-macos-universal-debug.zip Ghostty.app
|
|
zip -9 -r --symlinks ../../../ghostty-macos-universal-debug-dsym.zip Ghostty.app.dSYM/
|
|
|
|
# Update Blob Storage
|
|
- name: Prep R2 Storage
|
|
run: |
|
|
mkdir blob
|
|
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
|
|
cp ghostty-macos-universal-debug.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal-debug.zip
|
|
cp ghostty-macos-universal-debug-dsym.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-macos-universal-debug-dsym.zip
|
|
- name: Upload to R2
|
|
uses: ryand56/r2-upload-action@latest
|
|
with:
|
|
r2-account-id: ${{ secrets.CF_R2_PR_ACCOUNT_ID }}
|
|
r2-access-key-id: ${{ secrets.CF_R2_PR_AWS_KEY }}
|
|
r2-secret-access-key: ${{ secrets.CF_R2_PR_SECRET_KEY }}
|
|
r2-bucket: ghostty-pr
|
|
source-dir: blob
|
|
destination-dir: ./
|