🐛 fix(ci): add GhosttyKit stub to release-ios workflow #4
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: Release iOS | |
| on: | |
| push: | |
| tags: | |
| - "ios-v*" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version (e.g. 0.1.0)" | |
| required: true | |
| build_number: | |
| description: "Build number" | |
| required: true | |
| default: "1" | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: release-ios-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| release-ios: | |
| runs-on: macos-15 | |
| timeout-minutes: 30 | |
| env: | |
| DERIVED_DATA: .derived-data-ios | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Resolve version | |
| id: version | |
| run: | | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| BUILD_NUMBER="${{ github.event.inputs.build_number }}" | |
| else | |
| VERSION="${GITHUB_REF_NAME#ios-v}" | |
| BUILD_NUMBER="${GITHUB_RUN_NUMBER}" | |
| fi | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "build_number=${BUILD_NUMBER}" >> "$GITHUB_OUTPUT" | |
| echo "📦 Version: ${VERSION} (${BUILD_NUMBER})" | |
| - name: Install tools | |
| run: | | |
| brew install xcodegen xcbeautify | |
| - name: Cache SPM packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.DERIVED_DATA }}/SourcePackages | |
| key: spm-ios-${{ hashFiles('MoriRemote/MoriRemote.xcodeproj/project.pbxproj', '**/Package.resolved') }} | |
| restore-keys: spm-ios- | |
| - name: Generate Xcode project | |
| run: cd MoriRemote && xcodegen generate | |
| - name: Stub GhosttyKit for SPM resolution | |
| run: | | |
| mkdir -p Frameworks/GhosttyKit.xcframework/macos-arm64_x86_64/GhosttyKit.framework/Headers | |
| touch Frameworks/GhosttyKit.xcframework/macos-arm64_x86_64/GhosttyKit.framework/GhosttyKit | |
| cat > Frameworks/GhosttyKit.xcframework/Info.plist << 'PLIST' | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <dict> | |
| <key>AvailableLibraries</key> | |
| <array> | |
| <dict> | |
| <key>LibraryIdentifier</key> | |
| <string>macos-arm64_x86_64</string> | |
| <key>LibraryPath</key> | |
| <string>GhosttyKit.framework</string> | |
| <key>SupportedArchitectures</key> | |
| <array><string>arm64</string><string>x86_64</string></array> | |
| <key>SupportedPlatform</key> | |
| <string>macos</string> | |
| </dict> | |
| </array> | |
| <key>CFBundlePackageType</key> | |
| <string>XFWK</string> | |
| <key>XCFrameworkFormatVersion</key> | |
| <string>1.0</string> | |
| </dict> | |
| </plist> | |
| PLIST | |
| - name: Import signing certificate | |
| env: | |
| APPLE_CERTIFICATE_P12: ${{ secrets.IOS_CERTIFICATE_P12 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }} | |
| run: | | |
| KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" | |
| KEYCHAIN_PASSWORD="$(openssl rand -base64 32)" | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| CERT_PATH="$RUNNER_TEMP/certificate.p12" | |
| echo "$APPLE_CERTIFICATE_P12" | base64 --decode > "$CERT_PATH" | |
| security import "$CERT_PATH" \ | |
| -k "$KEYCHAIN_PATH" \ | |
| -P "$APPLE_CERTIFICATE_PASSWORD" \ | |
| -T /usr/bin/codesign \ | |
| -T /usr/bin/security | |
| rm -f "$CERT_PATH" | |
| security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db | |
| - name: Archive | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| BUILD_NUMBER: ${{ steps.version.outputs.build_number }} | |
| DEVELOPMENT_TEAM: ${{ secrets.APPLE_TEAM_ID }} | |
| run: | | |
| set -euo pipefail | |
| xcodebuild archive \ | |
| -project MoriRemote/MoriRemote.xcodeproj \ | |
| -scheme MoriRemote \ | |
| -destination 'generic/platform=iOS' \ | |
| -archivePath "$DERIVED_DATA/MoriRemote.xcarchive" \ | |
| -derivedDataPath "$DERIVED_DATA" \ | |
| -allowProvisioningUpdates \ | |
| MARKETING_VERSION="$VERSION" \ | |
| CURRENT_PROJECT_VERSION="$BUILD_NUMBER" \ | |
| 2>&1 | xcbeautify | |
| echo "✅ Archive created" | |
| - name: Export IPA | |
| run: | | |
| set -euo pipefail | |
| xcodebuild -exportArchive \ | |
| -archivePath "$DERIVED_DATA/MoriRemote.xcarchive" \ | |
| -exportOptionsPlist MoriRemote/ExportOptions.plist \ | |
| -exportPath "$DERIVED_DATA/export" \ | |
| -allowProvisioningUpdates \ | |
| 2>&1 | xcbeautify | |
| echo "✅ IPA exported" | |
| - name: Upload to TestFlight | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| IPA_PATH=$(find "$DERIVED_DATA/export" -name "*.ipa" | head -1) | |
| if [ -z "$IPA_PATH" ]; then | |
| echo "❌ No IPA found" | |
| exit 1 | |
| fi | |
| xcrun altool --upload-app \ | |
| --type ios \ | |
| --file "$IPA_PATH" \ | |
| --username "$APPLE_ID" \ | |
| --password "$APPLE_APP_PASSWORD" | |
| echo "✅ Uploaded to TestFlight" | |
| - name: Upload IPA artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: MoriRemote-${{ steps.version.outputs.version }}.ipa | |
| path: ${{ env.DERIVED_DATA }}/export/*.ipa | |
| retention-days: 90 | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" | |
| security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true |