Skip to content

macOS Direct Release #7

macOS Direct Release

macOS Direct Release #7

name: macOS Direct Release
on:
workflow_dispatch:
inputs:
channel:
description: "Update channel for appcast"
type: choice
required: true
default: stable
options:
- stable
- beta
sparkle_version:
description: "Sparkle release version"
required: true
default: "2.7.3"
tag:
description: "Git tag to attach the DMG to (optional)"
required: false
default: ""
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
runs-on: macos-latest
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Preflight
id: preflight
env:
SCHEME: ${{ vars.MACOS_DIRECT_SCHEME }}
XCODE_PATH: ${{ vars.MACOS_XCODE_PATH }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
MACOS_SPARKLE_PUBLIC_KEY: ${{ secrets.MACOS_SPARKLE_PUBLIC_KEY }}
MACOS_SPARKLE_PRIVATE_KEY: ${{ secrets.MACOS_SPARKLE_PRIVATE_KEY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
PUBLIC_RELEASES_R2_ACCESS_KEY_ID: ${{ secrets.PUBLIC_RELEASES_R2_ACCESS_KEY_ID }}
PUBLIC_RELEASES_R2_SECRET_ACCESS_KEY: ${{ secrets.PUBLIC_RELEASES_R2_SECRET_ACCESS_KEY }}
PUBLIC_RELEASES_R2_BUCKET: ${{ secrets.PUBLIC_RELEASES_R2_BUCKET }}
PUBLIC_RELEASES_R2_ENDPOINT: ${{ secrets.PUBLIC_RELEASES_R2_ENDPOINT }}
PUBLIC_RELEASES_R2_PUBLIC_BASE_URL: ${{ secrets.PUBLIC_RELEASES_R2_PUBLIC_BASE_URL }}
PUBLIC_RELEASES_R2_PREFIX: ${{ secrets.PUBLIC_RELEASES_R2_PREFIX }}
run: |
set -euo pipefail
required=(
MACOS_CERTIFICATE
MACOS_CERTIFICATE_PWD
MACOS_CERTIFICATE_NAME
MACOS_CI_KEYCHAIN_PWD
MACOS_SPARKLE_PUBLIC_KEY
MACOS_SPARKLE_PRIVATE_KEY
APPLE_ID
APPLE_PASSWORD
APPLE_TEAM_ID
PUBLIC_RELEASES_R2_ACCESS_KEY_ID
PUBLIC_RELEASES_R2_SECRET_ACCESS_KEY
PUBLIC_RELEASES_R2_BUCKET
PUBLIC_RELEASES_R2_ENDPOINT
PUBLIC_RELEASES_R2_PUBLIC_BASE_URL
)
missing=0
for name in "${required[@]}"; do
if [[ -z "${!name:-}" ]]; then
echo "Missing required secret: ${name}" >&2
missing=1
fi
done
if [[ "${missing}" -ne 0 ]]; then
exit 1
fi
if [[ -z "${PUBLIC_RELEASES_R2_PREFIX:-}" ]]; then
echo "PUBLIC_RELEASES_R2_PREFIX not set; defaulting to 'mac' in script." >&2
fi
if [[ -n "${XCODE_PATH:-}" ]]; then
xcode_path="${XCODE_PATH}"
elif [[ -d "/Applications/Xcode_26.1.app" ]]; then
xcode_path="/Applications/Xcode_26.1.app"
elif [[ -d "/Applications/Xcode_26.0.app" ]]; then
xcode_path="/Applications/Xcode_26.0.app"
elif [[ -d "/Applications/Xcode.app" ]]; then
xcode_path="/Applications/Xcode.app"
else
echo "No suitable Xcode found on runner." >&2
exit 1
fi
echo "Using Xcode path: ${xcode_path}"
echo "xcode_path=${xcode_path}" >> "${GITHUB_OUTPUT}"
- name: Set Xcode version
run: sudo xcode-select -s "${{ steps.preflight.outputs.xcode_path }}"
- name: Xcode Version
run: xcodebuild -version
- name: Verify Scheme
env:
SCHEME: ${{ vars.MACOS_DIRECT_SCHEME }}
run: |
set -euo pipefail
scheme="${SCHEME:-Inline (macOS)}"
echo "Using scheme: ${scheme}"
scheme_list=$(xcodebuild -list -project apple/Inline.xcodeproj)
if ! echo "${scheme_list}" | grep -Fq "${scheme}"; then
echo "Xcode scheme '${scheme}' not found in apple/Inline.xcodeproj." >&2
echo "Set MACOS_DIRECT_SCHEME repository variable to override." >&2
echo "Available schemes:" >&2
echo "${scheme_list}" | awk '/Schemes:/{flag=1;next} flag{print}' >&2
exit 1
fi
- name: Install create-dmg
run: npm install --global create-dmg
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "latest"
- name: Import macOS signing certificate
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
run: |
echo "$MACOS_CERTIFICATE" | base64 --decode > certificate.p12
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
- name: Build Direct DMG
env:
SPARKLE_VERSION: ${{ inputs.sparkle_version }}
CHANNEL: ${{ inputs.channel }}
SCHEME: ${{ vars.MACOS_DIRECT_SCHEME }}
SPARKLE_PUBLIC_KEY: ${{ secrets.MACOS_SPARKLE_PUBLIC_KEY }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: bash scripts/macos/build-direct.sh
- name: Generate Appcast
env:
CHANNEL: ${{ inputs.channel }}
SPARKLE_PRIVATE_KEY: ${{ secrets.MACOS_SPARKLE_PRIVATE_KEY }}
PUBLIC_RELEASES_R2_PUBLIC_BASE_URL: ${{ secrets.PUBLIC_RELEASES_R2_PUBLIC_BASE_URL }}
run: |
BUILD_NUMBER=$(git rev-list --count HEAD)
COMMIT=$(git rev-parse --short HEAD)
COMMIT_LONG=$(git rev-parse HEAD)
APP_PATH="build/InlineMacDirect/Build/Products/Release/Inline.app"
INFO_PLIST="${APP_PATH}/Contents/Info.plist"
VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${INFO_PLIST}")
BASE_URL="${PUBLIC_RELEASES_R2_PUBLIC_BASE_URL%/}"
DMG_URL="${BASE_URL}/mac/${CHANNEL}/${BUILD_NUMBER}/Inline.dmg"
APPCAST_URL="${BASE_URL}/mac/${CHANNEL}/appcast.xml"
SPARKLE_DIR=".action/sparkle"
echo "${SPARKLE_PRIVATE_KEY}" > signing.key
"${SPARKLE_DIR}/bin/sign_update" -f signing.key build/macos-direct/Inline.dmg > sign_update.txt
rm -f signing.key
if ! curl -fsSL "${APPCAST_URL}" -o appcast.xml; then
rm -f appcast.xml
fi
INLINE_BUILD="${BUILD_NUMBER}" \\
INLINE_VERSION="${VERSION}" \\
INLINE_CHANNEL="${CHANNEL}" \\
INLINE_DMG_URL="${DMG_URL}" \\
INLINE_MIN_MACOS="15.0" \\
INLINE_COMMIT="${COMMIT}" \\
INLINE_COMMIT_LONG="${COMMIT_LONG}" \\
python3 scripts/macos/update_appcast.py
- name: Upload to R2
env:
CHANNEL: ${{ inputs.channel }}
DMG_PATH: build/macos-direct/Inline.dmg
APPCAST_PATH: appcast_new.xml
PUBLIC_RELEASES_R2_ACCESS_KEY_ID: ${{ secrets.PUBLIC_RELEASES_R2_ACCESS_KEY_ID }}
PUBLIC_RELEASES_R2_SECRET_ACCESS_KEY: ${{ secrets.PUBLIC_RELEASES_R2_SECRET_ACCESS_KEY }}
PUBLIC_RELEASES_R2_BUCKET: ${{ secrets.PUBLIC_RELEASES_R2_BUCKET }}
PUBLIC_RELEASES_R2_ENDPOINT: ${{ secrets.PUBLIC_RELEASES_R2_ENDPOINT }}
PUBLIC_RELEASES_R2_PUBLIC_BASE_URL: ${{ secrets.PUBLIC_RELEASES_R2_PUBLIC_BASE_URL }}
PUBLIC_RELEASES_R2_PREFIX: mac
run: |
BUILD_NUMBER=$(git rev-list --count HEAD)
export BUILD_NUMBER
bun run scripts/macos/release-direct.ts
- name: Upload DMG to GitHub Release
if: inputs.tag != ''
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag }}
files: build/macos-direct/Inline.dmg
- name: Upload DMG
uses: actions/upload-artifact@v4
with:
name: inline-macos-dmg
path: build/macos-direct/Inline.dmg