From 0464f884565fa4e15da0a23d88bd1c4576c1da25 Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Thu, 23 Jan 2025 14:13:47 -0800 Subject: [PATCH] Update GitHub Action Signed-off-by: Paul Schmiedmayer --- .github/workflows/xcodebuild-or-fastlane.yml | 556 ++++++++++--------- 1 file changed, 298 insertions(+), 258 deletions(-) diff --git a/.github/workflows/xcodebuild-or-fastlane.yml b/.github/workflows/xcodebuild-or-fastlane.yml index 24895cb..fc729b4 100644 --- a/.github/workflows/xcodebuild-or-fastlane.yml +++ b/.github/workflows/xcodebuild-or-fastlane.yml @@ -12,127 +12,204 @@ on: workflow_call: inputs: path: - description: 'The path where the project is located. Defaults to $GITHUB_WORKSPACE' + description: | + The path where the project is located. Defaults to $GITHUB_WORKSPACE. required: false type: string default: '.' runsonlabels: - description: 'JSON-based collection of labels indicating which type of github runner should be chosen' + description: | + JSON-based collection of labels indicating which type of github runner should be chosen. required: false type: string - default: '["macos-14"]' + default: '["macos-15"]' xcodeversion: - description: 'The Xcode version used for the build' + description: | + The Xcode version used for the build. required: false type: string default: 'latest-stable' scheme: - description: 'The scheme in the Xcode project. Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`' + description: | + The scheme in the Xcode project. + Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`. required: false type: string default: '' buildConfig: - description: 'The build configuration parameter that should be passed to xcodebuild. Either use `Debug` or `Release` to build in the respective modes. If not defined, the `Debug` configuration is used.' + description: | + The build configuration parameter that should be passed to xcodebuild. + Either use `Debug` or `Release` to build in the respective modes. + If not defined, the `Debug` configuration is used. required: false type: string default: 'Debug' destination: - description: 'The destination parameter that should be passed to xcodebuild. Defaults to the iOS simulator using an iPhone 15 Pro' + description: | + The destination parameter that should be passed to xcodebuild. + Defaults to the iOS simulator using an iPhone 16 Pro. required: false type: string - default: 'platform=iOS Simulator,name=iPhone 15 Pro' + default: 'platform=iOS Simulator,name=iPhone 16 Pro' setupSimulators: - description: 'Flag indicating if all iOS simulators matching the `destination` input shoud be setup (e.g. password autofill functionality should be disabled).' + description: | + Flag indicating if all iOS simulators matching the `destination` input shoud be setup. + Includes, e.g., password autofill functionality should be disabled [Deprecated]. required: false type: boolean default: false resultBundle: - description: 'The name of the Xcode result bundle that is passed to xcodebuild. If not defined, the name of the scheme + .xcresult is used.' + description: | + The name of the Xcode result bundle that is passed to xcodebuild. + If not defined, the name of the scheme + .xcresult is used. + required: false + type: string + default: '' + swiftVersion: + description: | + Specify the Swift language version when using xcodebuild. required: false type: string default: '' test: - description: 'A flag indicating if the tests of the Xcode project scheme should run' + description: | + A flag indicating if the tests of the Xcode project scheme should run when using xcodebuild. required: false type: boolean default: true fastlanelane: - description: 'The lane of the fastlane command. Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`' + description: | + The lane of the fastlane command. + Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`. required: false type: string default: '' customcommand: - description: 'A custom command that should be run after the setup. Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`' + description: | + A custom command that should be run after the setup. + Either use `scheme` to use xcodebuild, `fastlanelane` to use fastlane, or a custom command using `customcommand`. required: false type: string default: '' artifactname: - description: 'The name & path of the artifact that should be uploaded at the end of the build.' + description: | + The name & path of the artifact that should be uploaded at the end of the build. + required: false + type: string + default: '' + environment: + description: | + GitHub deployment environment to optionally adjust access to variables and secrets with additional protection rules. + https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment required: false type: string default: '' setupsigning: - description: 'Setup the keychain to include Apple certificate and provisioning profile' + description: | + Setup the keychain to include Apple certificate and provisioning profile. required: false type: boolean default: false cacheDerivedData: - description: 'Cache the derived data folder for a build using xcodebuild' + description: | + Cache the derived data folder for a build using xcodebuild [Deprecated]. required: false type: boolean default: false setupfirebaseemulator: - description: 'Setup the Firebase Emulator' + description: | + Setup the Firebase Emulator & automatically use it for the automated fastlane commands. required: false type: boolean default: false + firebaseemulatorimport: + description: | + Firebase import directory that contains Authentication, Cloud Firestore, Realtime Database and Cloud Storage data for Firebase emulators. + Can be used to inject a shareable, common baseline data set. + required: false + type: string + default: '' + firebasejsonpath: + description: | + Path to the firebase.json file that is used to boot up the firebase emulator. + Defaults to the root of the project. + required: false + type: string + default: './firebase.json' googleserviceinfoplistpath: - description: 'Path to the GoogleService-Info.plist file that is replaced using the content found in the secret GOOGLE_SERVICE_INFO_PLIST' + description: | + Path to the GoogleService-Info.plist file that is replaced using the content found in the secret GOOGLE_SERVICE_INFO_PLIST. required: false type: string default: '' codeql: - description: 'Use CodeQL code scanning' + description: | + Use CodeQL code scanning. required: false type: boolean default: false checkout_submodules: - description: "Flag indicating if submodules should be automatically checked out." + description: | + Flag indicating if submodules should be automatically checked out. + required: false + type: boolean + checkout_lfs: + description: | + Flag indicating if git lfs should be used when running the check out step. required: false type: boolean + default: false secrets: BUILD_CERTIFICATE_BASE64: - description: 'The Base64 version of the Apple signing certificate to build your iOS application.' + description: | + The Base64 version of the Apple signing certificate to build your iOS application. required: false P12_PASSWORD: - description: 'The password for the Apple signing certificate.' + description: | + The password for the Apple signing certificate. required: false BUILD_PROVISION_PROFILE_BASE64: - description: 'The Base64 version of the Apple provisioning profile to build your main application (e.g. iOS app).' + description: | + The Base64 version of the Apple provisioning profile to build your main application (e.g. iOS app). required: false BUILD_SECONDARY_PROVISION_PROFILE_BASE64: - description: 'The Base64 version of the Apple provisioning profile to build your an accompanying application (e.g. watchOS app).' + description: | + The Base64 version of the Apple provisioning profile to build your an accompanying application (e.g. watchOS app). required: false KEYCHAIN_PASSWORD: - description: 'A password for the keychain that will be created on the runner instance.' + description: | + A password for the keychain that will be created on the runner instance. required: false APP_STORE_CONNECT_API_KEY_ID: - description: 'The key ID of the API key created in the App Store Connect API keys section.' + description: | + The key ID of the API key created in the App Store Connect API keys section. required: false APP_STORE_CONNECT_ISSUER_ID: - description: 'The issuer ID of the App Store Connect API is displayed in the App Store Connect API keys section.' + description: | + The issuer ID of the App Store Connect API is displayed in the App Store Connect API keys section. required: false APP_STORE_CONNECT_API_KEY_BASE64: - description: 'The content of the key created in App Store Connect condensed into a Base64 representation, e.g., using base64 -i AuthKey_ABCDEFGHIJ.p8 | pbcopy.' + description: | + The content of the key created in App Store Connect condensed into a Base64 representation. + Can be generated using, e.g., `$ base64 -i AuthKey_ABCDEFGHIJ.p8 | pbcopy`. required: false APPLE_ID: - description: 'The Apple ID you use to access the App Store Connect API.' + description: | + The Apple ID you use to access the App Store Connect API. required: false CHECKOUT_TOKEN: - description: 'The Personal access token (PAT) to use with the checkout action' + description: | + The Personal access token (PAT) to use with the checkout action. required: false GOOGLE_SERVICE_INFO_PLIST_BASE64: - description: 'The Base64 version of the GoogleService-Info.plist file that is used to replace the file found at googleserviceinfoplistpath if the arguemnt is set.' + description: | + The Base64 version of the GoogleService-Info.plist file that is used. + Replace the file found at googleserviceinfoplistpath if the arguemnt is set. + required: false + GOOGLE_APPLICATION_CREDENTIALS_BASE64: + description: | + The Base64 version of the private key JSON file to boot up the firebase emulator. + Only needed if cloud functions are used to fully support the execution of cloud functions in the emulator. required: false jobs: @@ -142,246 +219,209 @@ jobs: defaults: run: working-directory: ${{ inputs.path }} + environment: ${{ inputs.environment }} steps: - - uses: actions/checkout@v4 - with: - # This is GitHubs way of implementing ternary expressions (see https://docs.github.com/en/actions/learn-github-actions/expressions) - token: ${{ secrets.CHECKOUT_TOKEN != '' && secrets.CHECKOUT_TOKEN || github.token }} - submodules: ${{ inputs.checkout_submodules }} - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ${{ inputs.xcodeversion }} - - name: Check environment - run: | - xcodebuild -version - swift --version - echo "env.selfhosted: ${{ env.selfhosted }}" - - name: Install xcpretty - if: ${{ !env.selfhosted && inputs.scheme != '' }} - run: gem install xcpretty - - name: Cache .derivedData folder - if: ${{ inputs.cacheDerivedData }} - uses: actions/cache@v4 - with: - path: .derivedData - key: ${{ runner.os }}-${{ runner.arch }}-derivedData-${{ hashFiles('**/Package.swift', '**/*.pbxproj') }} - restore-keys: | - ${{ runner.os }}-${{ runner.arch }}-derivedData- - - name: Cache Firebase Emulators - if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} - uses: actions/cache@v4 - with: - path: ~/.cache/firebase/emulators - key: ${{ runner.os }}-${{ runner.arch }}-firebase-emulators-${{ hashFiles('~/.cache/firebase/emulators/**') }} - - name: Setup NodeJS - if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} - uses: actions/setup-node@v4 - - name: Setup Java - if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} - uses: actions/setup-java@v4 - with: - distribution: 'microsoft' - java-version: '17' - - name: Install Firebase CLI Tools - if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} - run: npm install -g firebase-tools - - name: Install the Apple certificate and provisioning profile - if: ${{ inputs.setupsigning }} - env: - BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} - P12_PASSWORD: ${{ secrets.P12_PASSWORD }} - BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} - BUILD_SECONDARY_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_SECONDARY_PROVISION_PROFILE_BASE64 }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - run: | - # Create Variables - CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 - PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision - KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + - uses: actions/checkout@v4 + with: + # This is GitHubs way of implementing ternary expressions (see https://docs.github.com/en/actions/learn-github-actions/expressions) + token: ${{ secrets.CHECKOUT_TOKEN != '' && secrets.CHECKOUT_TOKEN || github.token }} + submodules: ${{ inputs.checkout_submodules }} + lfs: ${{ inputs.checkout_lfs }} + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ inputs.xcodeversion }} + - name: Check environment + run: | + xcodebuild -version + swift --version + echo "env.selfhosted: ${{ env.selfhosted }}" + echo "environment: ${{ inputs.environment }}" + - name: Install xcbeautify + if: ${{ !env.selfhosted && inputs.scheme != '' }} + run: brew install xcbeautify + - name: Cache .derivedData folder (Deprecated) + if: ${{ inputs.cacheDerivedData }} + run: | + echo "::warning::Caching of the .derivedData folder was removed and is deprecated. Plase stop using this option." + - name: Cache Firebase Emulators + if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} + uses: actions/cache@v4 + with: + path: ~/.cache/firebase/emulators + key: ${{ runner.os }}-${{ runner.arch }}-firebase-emulators-${{ hashFiles('~/.cache/firebase/emulators/**') }} + - name: Setup NodeJS + if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} + uses: actions/setup-node@v4 + - name: Setup Java + if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} + uses: actions/setup-java@v4 + with: + distribution: 'microsoft' + java-version: '17' + - name: Install Firebase CLI Tools + if: ${{ !env.selfhosted && inputs.setupfirebaseemulator }} + run: npm install -g firebase-tools + - name: Install the Apple certificate and provisioning profile + if: ${{ inputs.setupsigning }} + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} + BUILD_SECONDARY_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_SECONDARY_PROVISION_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + # Create Variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - # Import Certificate and Provisioning Profile from Secrets - echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH - echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH - - # Create a Temporary Keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - security set-keychain-settings -lut 21600 $KEYCHAIN_PATH - security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - - # Import Certificate to the Keychain - security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH - security list-keychain -d user -s $KEYCHAIN_PATH - - # Apply Provisioning Profile - mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - UUID=`grep UUID -A1 -a $PP_PATH | grep -io "[-A-F0-9]\{36\}"` - cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision - - # Secondary Provisioning Profile - if [ -n "$BUILD_SECONDARY_PROVISION_PROFILE_BASE64" ]; then - PP_SECONDARY_PATH=$RUNNER_TEMP/build_pp_secondary.mobileprovision - echo -n "$BUILD_SECONDARY_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_SECONDARY_PATH - SECONDARY_UUID=`grep UUID -A1 -a $PP_SECONDARY_PATH | grep -io "[-A-F0-9]\{36\}"` - cp $PP_SECONDARY_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$SECONDARY_UUID.mobileprovision - fi - - name: Setup Google Services File - if: ${{ inputs.googleserviceinfoplistpath != '' }} - run: | - echo -n "${{ secrets.GOOGLE_SERVICE_INFO_PLIST_BASE64 }}" | base64 --decode -o "${{ inputs.googleserviceinfoplistpath }}" - - name: Initialize CodeQL - if: ${{ !env.selfhosted && inputs.codeql }} - uses: github/codeql-action/init@v2 - with: - languages: swift - db-location: '${{ inputs.path }}/.codeql' - - name: Disable Password Autofill in the iOS Simulator - if: ${{ inputs.setupSimulators && inputs.destination != '' }} - run: | - # Function to parse the device name from input string - parse_device_name() { - local input_str=$1 - local IFS=',' # Set Internal Field Separator to comma for splitting - - for kv in $input_str; do - key="${kv%%=*}" # Extract key (everything before '=') - value="${kv#*=}" # Extract value (everything after '=') - - if [ "$key" = "name" ]; then - echo "$value" - return - fi - done - } + # Import Certificate and Provisioning Profile from Secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH - # Extract device name from the input - DEVICE_NAME=$(parse_device_name "${{ inputs.destination }}") + # Create a Temporary Keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - echo "Device name: $DEVICE_NAME" - - # Retrieve the iOS simulator IDs for the specified device - REGEX_PATTERN="$DEVICE_NAME( Simulator)? \(.*\)" - SIMULATOR_IDS=$(xctrace list devices | grep -E "$REGEX_PATTERN" | awk '{print $NF}' | tr -d '()') + # Import Certificate to the Keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH - # Check if SIMULATOR_IDS is empty - if [ -z "$SIMULATOR_IDS" ]; then - echo "No simulators found for the specified device." - exit 1 - fi + # Apply Provisioning Profile + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + UUID=`grep UUID -A1 -a $PP_PATH | grep -io "[-A-F0-9]\{36\}"` + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision - # Loop through each Simulator ID - for SIMULATOR_ID in $SIMULATOR_IDS; do - echo "Processing Simulator ID: $SIMULATOR_ID" - - PLIST1="$HOME/Library/Developer/CoreSimulator/Devices/$SIMULATOR_ID/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles/Library/ConfigurationProfiles/UserSettings.plist" - PLIST2="$HOME/Library/Developer/CoreSimulator/Devices/$SIMULATOR_ID/data/Library/UserConfigurationProfiles/EffectiveUserSettings.plist" - PLIST3="$HOME/Library/Developer/CoreSimulator/Devices/$SIMULATOR_ID/data/Library/UserConfigurationProfiles/PublicInfo/PublicEffectiveUserSettings.plist" - - if [ ! -f "$PLIST1" ] || [ ! -f "$PLIST2" ] || [ ! -f "$PLIST3" ]; then - echo "Simulator $SIMULATOR_ID booting ..." - xcrun simctl boot "$SIMULATOR_ID" + # Secondary Provisioning Profile + if [ -n "$BUILD_SECONDARY_PROVISION_PROFILE_BASE64" ]; then + PP_SECONDARY_PATH=$RUNNER_TEMP/build_pp_secondary.mobileprovision + echo -n "$BUILD_SECONDARY_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_SECONDARY_PATH + SECONDARY_UUID=`grep UUID -A1 -a $PP_SECONDARY_PATH | grep -io "[-A-F0-9]\{36\}"` + cp $PP_SECONDARY_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$SECONDARY_UUID.mobileprovision + fi + - name: Setup Google Services File + if: ${{ inputs.googleserviceinfoplistpath != '' }} + run: | + echo -n "${{ secrets.GOOGLE_SERVICE_INFO_PLIST_BASE64 }}" | base64 --decode -o "${{ inputs.googleserviceinfoplistpath }}" + - name: Initialize CodeQL + if: ${{ !env.selfhosted && inputs.codeql }} + uses: github/codeql-action/init@v3 + with: + languages: swift + db-location: '${{ inputs.path }}/.codeql' + - name: Mechanism to resolve CodeQL issue https://github.com/github/codeql-action/issues/2506#issuecomment-2594033147 + if: ${{ !env.selfhosted && inputs.codeql }} + run: | + XCODE_PATH=$(xcode-select -p) + mkdir -p $XCODE_PATH/Toolchains/XcodeDefault.xctoolchain/usr/lib + cp $XCODE_PATH/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/*.dylib $XCODE_PATH/Toolchains/XcodeDefault.xctoolchain/usr/lib + sudo mkdir -p /usr/local/lib + sudo cp $XCODE_PATH/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/*.dylib /usr/local/lib + - name: Disable Password Autofill in the iOS Simulator (Deprecated) + if: ${{ inputs.setupSimulators && inputs.destination != '' }} + run: | + echo "::warning::Script-based simulator setup to disable Password Autofill was removed and is deprecated. Please stop using this option." + - name: Run custom command + if: ${{ inputs.customcommand != '' }} + run: ${{ inputs.customcommand }} + env: + APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} + APPLE_ID: ${{ secrets.APPLE_ID }} + - name: Resolve dependencies (xcodebuild) + if: ${{ inputs.scheme != '' }} + run: | + xcodebuild \ + -scheme ${{ inputs.scheme }} \ + -resolvePackageDependencies \ + -derivedDataPath ".derivedData" \ + | xcbeautify \ + || true + - name: Build and test (xcodebuild) + if: ${{ inputs.scheme != '' }} + run: | + if ${{ inputs.test }}; then + XCODECOMMAND="test" + CODECOVERAGEFLAG="-enableCodeCoverage YES" + else + XCODECOMMAND="build" fi - # Loop for a maximum of 30 seconds - for (( i=0; i<30; i++ )); do - if [ -f "$PLIST1" ] && [ -f "$PLIST2" ] && [ -f "$PLIST3" ]; then - echo "All files found." - break - fi - sleep 1 - done - - # Check if the loop exited because all files were found or because of timeout - if [ ! -f "$PLIST1" ] || [ ! -f "$PLIST2" ] || [ ! -f "$PLIST3" ]; then - echo "Error: Not all files were found within the 30-second timeout." - exit 1 + if [ -z "${{ inputs.resultBundle }}" ]; then + RESULTBUNDLE=${{ inputs.scheme }}.xcresult + else + RESULTBUNDLE=${{ inputs.resultBundle }} fi - sleep 5 - - # Disable AutoFillPasswords - plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO $PLIST1 - plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO $PLIST2 - plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO $PLIST3 - /usr/libexec/PlistBuddy -c "Add :KeyboardContinuousPathEnabled bool false" /Users/githubaction/Library/Developer/CoreSimulator/Devices/$SIMULATOR_ID/data/Library/Preferences/com.apple.keyboard.ContinuousPath.plist - - sleep 1 + if [ "${{ inputs.buildConfig }}" = "Release" ]; then + ENABLE_TESTING_FLAG="-enable-testing" + else + ENABLE_TESTING_FLAG="" + fi - # Restart (shutdown if needed and boot) the iOS simulator for the changes to take effect - if xcrun simctl shutdown "$SIMULATOR_ID"; then - echo "Simulator $SIMULATOR_ID shutdown successfully." + if [ -n "${{ inputs.swiftVersion }}" ]; then + SWIFT_VERSION_FLAG="-swift-version ${{ inputs.swiftVersion }}" else - echo "Unable to shutdown simulator $SIMULATOR_ID as it is already shutdown." + SWIFT_VERSION_FLAG="" fi - done - - name: Run custom command - if: ${{ inputs.customcommand != '' }} - run: ${{ inputs.customcommand }} - env: - APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} - APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} - APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} - APPLE_ID: ${{ secrets.APPLE_ID }} - - name: Resolve dependencies (xcodebuild) - if: ${{ inputs.scheme != '' }} - run: | - xcodebuild \ - -scheme ${{ inputs.scheme }} \ - -resolvePackageDependencies \ - -derivedDataPath ".derivedData" \ - || true - - name: Build and test (xcodebuild) - if: ${{ inputs.scheme != '' }} - run: | - if ${{ inputs.test }}; then - XCODECOMMAND="test" - CODECOVERAGEFLAG="-enableCodeCoverage YES" - else - XCODECOMMAND="build" - fi - if [ -z "${{ inputs.resultBundle }}" ]; then - RESULTBUNDLE=${{ inputs.scheme }}.xcresult - else - RESULTBUNDLE=${{ inputs.resultBundle }} - fi + set -o pipefail \ + && xcodebuild $XCODECOMMAND \ + -scheme "${{ inputs.scheme }}" \ + -configuration "${{ inputs.buildConfig }}" \ + -destination "${{ inputs.destination }}" \ + $CODECOVERAGEFLAG \ + -derivedDataPath ".derivedData" \ + -resultBundlePath "$RESULTBUNDLE" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGN_IDENTITY="" \ + OTHER_SWIFT_FLAGS="\$(inherited) $ENABLE_TESTING_FLAG $SWIFT_VERSION_FLAG" \ + -skipPackagePluginValidation \ + -skipMacroValidation \ + | xcbeautify + - name: Fastlane + if: ${{ inputs.fastlanelane != '' }} + run: | + if ${{ inputs.setupfirebaseemulator }}; then + # We try to do an npm install in the functions directory. + npm --prefix ./functions install || true - if [ "${{ inputs.buildConfig }}" = "Release" ]; then - ENABLE_TESTING_FLAG="-enable-testing" - else - ENABLE_TESTING_FLAG="" - fi + echo -n "${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }}" | base64 -d > "$RUNNER_TEMP/google-application-credentials.json" + export GOOGLE_APPLICATION_CREDENTIALS="$RUNNER_TEMP/google-application-credentials.json" + echo "Stored the Google application credentials at $GOOGLE_APPLICATION_CREDENTIALS" - set -o pipefail \ - && xcodebuild $XCODECOMMAND \ - -scheme "${{ inputs.scheme }}" \ - -configuration "${{ inputs.buildConfig }}" \ - -destination "${{ inputs.destination }}" \ - $CODECOVERAGEFLAG \ - -derivedDataPath ".derivedData" \ - -resultBundlePath "$RESULTBUNDLE" \ - CODE_SIGNING_REQUIRED=NO \ - CODE_SIGN_IDENTITY="" \ - OTHER_SWIFT_FLAGS="\$(inherited) $ENABLE_TESTING_FLAG" \ - | xcpretty - - name: Fastlane - if: ${{ inputs.fastlanelane != '' }} - run: fastlane ${{ inputs.fastlanelane }} - env: - APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} - APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} - APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} - APPLE_ID: ${{ secrets.APPLE_ID }} - - name: Perform CodeQL Analysis - if: ${{ !env.selfhosted && inputs.codeql }} - uses: github/codeql-action/analyze@v2 - - name: Upload artifact - if: ${{ (success() || failure()) && inputs.artifactname != '' && inputs.buildConfig != 'Release' }} - uses: actions/upload-artifact@v4 - with: - name: ${{ inputs.artifactname }} - path: ${{ inputs.path }}/${{ inputs.artifactname }} - - name: Clean up keychain and provisioning profile - if: ${{ (inputs.setupsigning && env.selfhosted) || failure() }} - run: | - security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true - rm -rf ~/Library/MobileDevice/Provisioning\ Profiles || true + if [ -n "${{ inputs.firebaseemulatorimport }}" ]; then + echo "Importing firebase emulator data from ${{ inputs.firebaseemulatorimport }}" + firebase emulators:exec -c ${{ inputs.firebasejsonpath }} --import=${{ inputs.firebaseemulatorimport }} 'fastlane ${{ inputs.fastlanelane }}' + else + firebase emulators:exec -c ${{ inputs.firebasejsonpath }} 'fastlane ${{ inputs.fastlanelane }}' + fi + else + fastlane ${{ inputs.fastlanelane }} + fi + env: + APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} + APPLE_ID: ${{ secrets.APPLE_ID }} + GOOGLE_APPLICATION_CREDENTIALS_BASE64: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }} + - name: Perform CodeQL Analysis + if: ${{ !env.selfhosted && inputs.codeql }} + uses: github/codeql-action/analyze@v3 + - name: Upload artifact + if: ${{ (success() || failure()) && inputs.artifactname != '' && inputs.buildConfig != 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifactname }} + path: ${{ inputs.path }}/${{ inputs.artifactname }} + - name: Clean up keychain and provisioning profile + if: ${{ (inputs.setupsigning && env.selfhosted) || failure() }} + run: | + security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true + rm -rf ~/Library/MobileDevice/Provisioning\ Profiles || true + - name: Clean up Google application credentials + if: ${{ inputs.fastlanelane != '' || failure() }} + run: | + rm -rf $RUNNER_TEMP/google-application-credentials.json || true