Skip to content

Release

Release #17

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
version:
description: "Marketing version and tag (for example: 0.3.0)"
required: true
type: string
permissions:
contents: write
concurrency:
group: release
cancel-in-progress: false
jobs:
release:
runs-on: macos-26
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
with:
ref: main
fetch-depth: 0
- name: Validate version
env:
VERSION: ${{ inputs.version }}
run: |
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Version must use the x.y.z format."
exit 1
fi
if git rev-parse --verify --quiet "refs/tags/$VERSION"; then
echo "::error::Tag $VERSION already exists."
exit 1
fi
- name: Update marketing version
env:
VERSION: ${{ inputs.version }}
run: |
ruby <<'RUBY'
path = "TrackpadAir.xcodeproj/project.pbxproj"
project = File.read(path)
version = ENV.fetch("VERSION")
updated_configurations = 0
updated_project = project.gsub(
/(\w+ \/\* (?:Debug|Release) \*\/ = \{\n\s+isa = XCBuildConfiguration;.*?\n\s+\};)/m
) do |configuration|
unless configuration.include?("PRODUCT_BUNDLE_IDENTIFIER = com.TrackpadAir;")
next configuration
end
updated_configuration = configuration.sub(
/MARKETING_VERSION = [^;]+;/,
"MARKETING_VERSION = #{version};"
)
if updated_configuration == configuration
abort "MARKETING_VERSION was not found in an app build configuration"
end
updated_configurations += 1
updated_configuration
end
unless updated_configurations == 2
abort "Expected to update 2 app build configurations, updated #{updated_configurations}"
end
File.write(path, updated_project)
RUBY
- name: Push version and tag
env:
VERSION: ${{ inputs.version }}
run: |
if git diff --quiet -- TrackpadAir.xcodeproj/project.pbxproj; then
echo "::error::Marketing version is already $VERSION."
exit 1
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add TrackpadAir.xcodeproj/project.pbxproj
git commit -m "Bump version to $VERSION"
git push origin HEAD:main
git tag "$VERSION"
git push origin "$VERSION"
- name: Import signing certificate
env:
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
CERTIFICATE_P12: ${{ secrets.CERTIFICATE_P12 }}
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
CERTIFICATE_PATH="$RUNNER_TEMP/certificate.p12"
printf '%s' "$CERTIFICATE_P12" | base64 --decode > "$CERTIFICATE_PATH"
security create-keychain -p runner "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p runner "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" \
-k "$KEYCHAIN_PATH" \
-P "$CERTIFICATE_PASSWORD" \
-T /usr/bin/codesign
security set-key-partition-list \
-S apple-tool:,apple: \
-s \
-k runner \
"$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH"
- name: Run tests
run: |
xcodebuild test \
-project TrackpadAir.xcodeproj \
-scheme TrackpadAir \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO
- name: Archive app
run: |
xcodebuild archive \
-project TrackpadAir.xcodeproj \
-scheme TrackpadAir \
-archivePath "$RUNNER_TEMP/TrackpadAir.xcarchive"
- name: Notarize app
env:
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
run: |
APP_PATH="$RUNNER_TEMP/TrackpadAir.xcarchive/Products/Applications/TrackpadAir.app"
NOTARIZATION_ZIP="$RUNNER_TEMP/TrackpadAir-notarization.zip"
API_KEY_PATH="$RUNNER_TEMP/AuthKey_$APP_STORE_CONNECT_API_KEY_ID.p8"
printf '%s' "$APP_STORE_CONNECT_API_KEY" > "$API_KEY_PATH"
ditto -c -k --keepParent "$APP_PATH" "$NOTARIZATION_ZIP"
xcrun notarytool submit "$NOTARIZATION_ZIP" \
--key "$API_KEY_PATH" \
--key-id "$APP_STORE_CONNECT_API_KEY_ID" \
--issuer "$APP_STORE_CONNECT_API_ISSUER_ID" \
--wait
xcrun stapler staple "$APP_PATH"
xcrun stapler validate "$APP_PATH"
spctl --assess --type execute --verbose=4 "$APP_PATH"
- name: Package app
run: |
ditto -c -k --keepParent \
"$RUNNER_TEMP/TrackpadAir.xcarchive/Products/Applications/TrackpadAir.app" \
TrackpadAir.app.zip
- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ inputs.version }}
run: |
gh release create "$VERSION" \
TrackpadAir.app.zip \
--generate-notes \
--verify-tag
- name: Clean up keychain
if: always()
run: security delete-keychain "$RUNNER_TEMP/build.keychain-db" || true