diff --git a/.github/actions/notices_generation/action.yml b/.github/actions/notices_generation/action.yml index b47920ffe6e..53993ebe677 100644 --- a/.github/actions/notices_generation/action.yml +++ b/.github/actions/notices_generation/action.yml @@ -34,11 +34,16 @@ runs: cd "${{ github.action_path }}" bundle install if ${{ inputs.search-local-pod-version == 'true' }} ; then - ruby app.rb --pods ${{ inputs.pods }} --sources ${{ inputs.sources }} --min_ios_version ${{ inputs.min-ios-version }} --search_local_pod_version --notices_path ${{ inputs.notices-path }} + ruby app.rb --pods ${INPUTS_PODS} --sources ${INPUTS_SOURCES} --min_ios_version ${INPUTS_MIN_IOS_VERSION} --search_local_pod_version --notices_path ${INPUTS_NOTICES_PATH} else - ruby app.rb --pods ${{ inputs.pods }} --sources ${{ inputs.sources }} --min_ios_version ${{ inputs.min-ios-version }} --notices_path ${{ inputs.notices-path }} + ruby app.rb --pods ${INPUTS_PODS} --sources ${INPUTS_SOURCES} --min_ios_version ${INPUTS_MIN_IOS_VERSION} --notices_path ${INPUTS_NOTICES_PATH} fi shell: bash + env: + INPUTS_PODS: ${{ inputs.pods }} + INPUTS_SOURCES: ${{ inputs.sources }} + INPUTS_MIN_IOS_VERSION: ${{ inputs.min-ios-version }} + INPUTS_NOTICES_PATH: ${{ inputs.notices-path }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/api_diff_report.yml b/.github/workflows/api_diff_report.yml index 3ffdcd09eee..468f20120e9 100644 --- a/.github/workflows/api_diff_report.yml +++ b/.github/workflows/api_diff_report.yml @@ -53,8 +53,10 @@ jobs: - name: Generate API files for PR branch run: | python ~/api_diff_report/api_info.py \ - --file_list ${{ steps.get_changed_files.outputs.file_list }} \ + --file_list ${STEPS_GET_CHANGED_FILES_OUTPUTS_FILE_LIST} \ --output_dir ${{ env.PR_API_OUTPUT }} + env: + STEPS_GET_CHANGED_FILES_OUTPUTS_FILE_LIST: ${{ steps.get_changed_files.outputs.file_list }} - name: Checkout Base branch run: git checkout HEAD^ @@ -62,8 +64,10 @@ jobs: - name: Generate API files for Base branch run: | python ~/api_diff_report/api_info.py \ - --file_list ${{ steps.get_changed_files.outputs.file_list }} \ + --file_list ${STEPS_GET_CHANGED_FILES_OUTPUTS_FILE_LIST} \ --output_dir ${{ env.BASE_API_OUTPUT }} + env: + STEPS_GET_CHANGED_FILES_OUTPUTS_FILE_LIST: ${{ steps.get_changed_files.outputs.file_list }} - name: Generate API Diff Report run: | diff --git a/.github/workflows/common_quickstart.yml b/.github/workflows/common_quickstart.yml index 3ced9e62959..9b30a50673d 100644 --- a/.github/workflows/common_quickstart.yml +++ b/.github/workflows/common_quickstart.yml @@ -80,13 +80,18 @@ jobs: - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Run setup command. - run: ${{ inputs.setup_command }} + run: ${INPUTS_SETUP_COMMAND} + env: + INPUTS_SETUP_COMMAND: ${{ inputs.setup_command }} - name: Install Secret GoogleService-Info.plist run: | scripts/decrypt_gha_secret.sh \ - ${{ inputs.plist_src_path }} \ - ${{ inputs.plist_dst_path }} \ + ${INPUTS_PLIST_SRC_PATH} \ + ${INPUTS_PLIST_DST_PATH} \ "$plist_secret" + env: + INPUTS_PLIST_SRC_PATH: ${{ inputs.plist_src_path }} + INPUTS_PLIST_DST_PATH: ${{ inputs.plist_dst_path }} - name: Build ${{ inputs.product }} Quickstart (${{ inputs.quickstart_type }} / ${{ inputs.is_legacy && 'Legacy' || 'Non-Legacy' }}) uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: @@ -102,11 +107,15 @@ jobs: - id: lowercase_product if: failure() run: | - lowercase_product=$(echo "${{ inputs.product }}" | tr '[:upper:]' '[:lower:]') + lowercase_product=$(echo "${INPUTS_PRODUCT}" | tr '[:upper:]' '[:lower:]') echo "lowercase_product=$lowercase_product" >> $GITHUB_OUTPUT + env: + INPUTS_PRODUCT: ${{ inputs.product }} - name: Remove data before upload. if: failure() - run: scripts/remove_data.sh ${{ steps.lowercase_product.outputs.lowercase_product }} + run: scripts/remove_data.sh ${STEPS_LOWERCASE_PRODUCT_OUTPUTS_LOWERCASE_PRODUCT} + env: + STEPS_LOWERCASE_PRODUCT_OUTPUTS_LOWERCASE_PRODUCT: ${{ steps.lowercase_product.outputs.lowercase_product }} - uses: actions/upload-artifact@v4 if: failure() with: diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index eab6b595610..f04ca06e169 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -48,7 +48,7 @@ jobs: target: iOS xcode: Xcode_26.0 runs-on: ${{ matrix.os }} - needs: spm + # needs: spm env: TEST_RUNNER_FIRAAppCheckDebugToken: ${{ secrets.VERTEXAI_INTEGRATION_FAC_DEBUG_TOKEN }} TEST_RUNNER_VTXIntegrationImagen: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} @@ -56,10 +56,10 @@ jobs: secrets_passphrase: ${{ secrets.GHASecretsGPGPassphrase1 }} steps: - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: .build - key: ${{ needs.spm.outputs.cache_key }} + # - uses: actions/cache/restore@v4 + # with: + # path: .build + # key: ${{ needs.spm.outputs.cache_key }} - name: Run integration tests run: scripts/repo.sh tests run --secrets ./scripts/secrets/AI.json --platforms ${{ matrix.target }} --xcode ${{ matrix.xcode }} AI - name: Upload xcodebuild logs diff --git a/.github/workflows/health-metrics-presubmit.yml b/.github/workflows/health-metrics-presubmit.yml index b9bd1a00edc..19ccf68cfe4 100644 --- a/.github/workflows/health-metrics-presubmit.yml +++ b/.github/workflows/health-metrics-presubmit.yml @@ -53,7 +53,7 @@ jobs: env: pr_branch: ${{ github.event.pull_request.head.ref }} run: | - if [ ! -z "${{ env.METRICS_SERVICE_SECRET }}" ]; then + if [ ! -z "${METRICS_SERVICE_SECRET}" ]; then ./scripts/health_metrics/get_updated_files.sh fi @@ -312,7 +312,7 @@ jobs: # Activate the service account for Metrics Service. scripts/decrypt_gha_secret.sh scripts/gha-encrypted/metrics_service_access.json.gpg \ - metrics-access.json "${{ env.METRICS_SERVICE_SECRET }}" + metrics-access.json "${METRICS_SERVICE_SECRET}" gcloud auth activate-service-account --key-file metrics-access.json - uses: actions/download-artifact@v4.1.7 id: download @@ -322,9 +322,10 @@ jobs: if: github.event.pull_request.merged != true && github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.base.ref == 'main' env: base_commit: ${{ needs.check.outputs.target_branch_head }} + STEPS_DOWNLOAD_OUTPUTS_DOWNLOAD_PATH: ${{steps.download.outputs.download-path}} run: | # Get Head commit of the branch, instead of a merge commit created by actions/checkout. - if [ -d "${{steps.download.outputs.download-path}}" ]; then + if [ -d "${STEPS_DOWNLOAD_OUTPUTS_DOWNLOAD_PATH}" ]; then cd scripts/health_metrics/generate_code_coverage_report swift run CoverageReportGenerator --presubmit "firebase/firebase-ios-sdk" --head-commit "${GITHUB_SHA}" --token $(gcloud auth print-identity-token) --xcresult-dir "/Users/runner/test/codecoverage" --log-link "https://github.com/firebase/firebase-ios-sdk/actions/runs/${GITHUB_RUN_ID}" --pull-request-num ${{github.event.pull_request.number}} --base-commit "$base_commit" fi @@ -357,7 +358,9 @@ jobs: - name: Update New Coverage Data if: github.event.pull_request.merged && github.event.pull_request.head.repo.full_name == github.repository run: | - if [ -d "${{steps.download.outputs.download-path}}" ]; then + if [ -d "${STEPS_DOWNLOAD_OUTPUTS_DOWNLOAD_PATH}" ]; then cd scripts/health_metrics/generate_code_coverage_report - swift run CoverageReportGenerator --merge "firebase/firebase-ios-sdk" --head-commit "${GITHUB_SHA}" --token $(gcloud auth print-identity-token) --xcresult-dir "/Users/runner/test/codecoverage" --log-link "https://github.com/firebase/firebase-ios-sdk/actions/runs/${GITHUB_RUN_ID}" --source-branch "${{ github.base_ref }}" + swift run CoverageReportGenerator --merge "firebase/firebase-ios-sdk" --head-commit "${GITHUB_SHA}" --token $(gcloud auth print-identity-token) --xcresult-dir "/Users/runner/test/codecoverage" --log-link "https://github.com/firebase/firebase-ios-sdk/actions/runs/${GITHUB_RUN_ID}" --source-branch "${GITHUB_BASE_REF}" fi + env: + STEPS_DOWNLOAD_OUTPUTS_DOWNLOAD_PATH: ${{steps.download.outputs.download-path}} diff --git a/.github/workflows/prerelease_cocoapods.yml b/.github/workflows/prerelease_cocoapods.yml index f74adfb6e7d..be0c42741a4 100644 --- a/.github/workflows/prerelease_cocoapods.yml +++ b/.github/workflows/prerelease_cocoapods.yml @@ -152,7 +152,7 @@ jobs: git config --global user.name "google-oss-bot" - name: Update SpecsTesting repo run: | - [[ ${{ matrix.allowwarnings }} == true ]] && ALLOWWARNINGS=true + [[ ${MATRIX_ALLOWWARNINGS} == true ]] && ALLOWWARNINGS=true cd scripts/create_spec_repo/ swift build pod repo add --silent "${local_repo}" https://"$botaccess"@github.com/Firebase/SpecsTesting.git @@ -166,6 +166,8 @@ jobs: --pod-sources 'https://${BOT_TOKEN}@github.com/Firebase/SpecsTesting' "https://github.com/firebase/SpecsDev.git" "https://github.com/firebase/SpecsStaging.git" "https://github.com/CocoaPods/Specs.git" \ --include-pods "${targeted_pod}" \ --keep-repo ${ALLOWWARNINGS:+--allow-warnings} + env: + MATRIX_ALLOWWARNINGS: ${{ matrix.allowwarnings }} - name: Clean Artifacts if: ${{ always() }} run: pod repo remove "${local_repo}" diff --git a/.github/workflows/release_cocoapods.yml b/.github/workflows/release_cocoapods.yml index 4ec26a41272..e66c819060a 100644 --- a/.github/workflows/release_cocoapods.yml +++ b/.github/workflows/release_cocoapods.yml @@ -137,7 +137,7 @@ jobs: git config --global user.name "google-oss-bot" - name: Update SpecsReleasing repo run: | - [[ ${{ matrix.allowwarnings }} == true ]] && ALLOWWARNINGS=true + [[ ${MATRIX_ALLOWWARNINGS} == true ]] && ALLOWWARNINGS=true cd scripts/create_spec_repo/ swift build pod repo add --silent "${local_repo}" https://"$botaccess"@github.com/Firebase/SpecsReleasing.git @@ -149,6 +149,8 @@ jobs: --pod-sources 'https://github.com/Firebase/SpecsReleasing' "https://github.com/firebase/SpecsStaging.git" "https://github.com/CocoaPods/Specs.git" \ --include-pods "${targeted_pod}" \ --keep-repo ${ALLOWWARNINGS:+--allow-warnings} + env: + MATRIX_ALLOWWARNINGS: ${{ matrix.allowwarnings }} - name: Clean Artifacts if: ${{ always() }} run: pod repo remove "${local_repo}" diff --git a/.github/workflows/update-cpp-sdk-on-release.yml b/.github/workflows/update-cpp-sdk-on-release.yml index b806de8da81..7f761a7f7e2 100644 --- a/.github/workflows/update-cpp-sdk-on-release.yml +++ b/.github/workflows/update-cpp-sdk-on-release.yml @@ -82,4 +82,6 @@ jobs: - name: Trigger firebase-cpp-sdk update run: | pip install -r scripts/gha/python_requirements.txt - python scripts/gha/trigger_workflow.py -t ${{ steps.generate-token.outputs.token }} -w update-dependencies.yml -p updateAndroid 0 -p updateiOS 1 -p comment "[Triggered]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) by [firebase-ios-sdk $GITHUB_REF release]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/tag/$GITHUB_REF)." -s 10 -A + python scripts/gha/trigger_workflow.py -t ${STEPS_GENERATE_TOKEN_OUTPUTS_TOKEN} -w update-dependencies.yml -p updateAndroid 0 -p updateiOS 1 -p comment "[Triggered]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) by [firebase-ios-sdk $GITHUB_REF release]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/tag/$GITHUB_REF)." -s 10 -A + env: + STEPS_GENERATE_TOKEN_OUTPUTS_TOKEN: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index d698a01a20a..8735449bb81 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -59,11 +59,13 @@ jobs: - name: Check if packaging should be skipped id: check run: | - if [[ -n "${{ env.PINNED_RUN_ID }}" || -n "${{ github.event.inputs.zip_run_id }}" ]]; then + if [[ -n "${{ env.PINNED_RUN_ID }}" || -n "${GITHUB_EVENT_INPUTS_ZIP_RUN_ID}" ]]; then echo "should_package=false" >> $GITHUB_OUTPUT else echo "should_package=true" >> $GITHUB_OUTPUT fi + env: + GITHUB_EVENT_INPUTS_ZIP_RUN_ID: ${{ github.event.inputs.zip_run_id }} package-release: needs: should_package @@ -161,13 +163,15 @@ jobs: - name: Get Run ID id: get_run_id run: | - if [[ -n "${{ github.event.inputs.zip_run_id }}" ]]; then - echo "run_id=${{ github.event.inputs.zip_run_id }}" >> $GITHUB_OUTPUT + if [[ -n "${GITHUB_EVENT_INPUTS_ZIP_RUN_ID}" ]]; then + echo "run_id=${GITHUB_EVENT_INPUTS_ZIP_RUN_ID}" >> $GITHUB_OUTPUT elif [[ -n "${{ env.PINNED_RUN_ID }}" ]]; then echo "run_id=${{ env.PINNED_RUN_ID }}" >> $GITHUB_OUTPUT else echo "run_id=${{ github.run_id }}" >> $GITHUB_OUTPUT fi + env: + GITHUB_EVENT_INPUTS_ZIP_RUN_ID: ${{ github.event.inputs.zip_run_id }} check_framework_firestore_symbols: needs: packaging_done @@ -739,4 +743,4 @@ jobs: name: quickstart_artifacts_storage_${{ matrix.artifact }} path: | quickstart-ios/ - !quickstart-ios/**/GoogleService-Info.plist \ No newline at end of file + !quickstart-ios/**/GoogleService-Info.plist diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index 9bfc47a0e5a..4f88a39448b 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -23,10 +23,9 @@ public enum FirebaseAppNames { public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" - public static let gemini2FlashPreviewImageGeneration = "gemini-2.0-flash-preview-image-generation" public static let gemini2FlashLive = "gemini-2.0-flash-live-001" public static let gemini2FlashLivePreview = "gemini-2.0-flash-live-preview-04-09" - public static let gemini2_5_FlashImagePreview = "gemini-2.5-flash-image-preview" + public static let gemini2_5_FlashImage = "gemini-2.5-flash-image" public static let gemini2_5_Flash = "gemini-2.5-flash" public static let gemini2_5_FlashLite = "gemini-2.5-flash-lite" public static let gemini2_5_FlashLivePreview = "gemini-live-2.5-flash-preview" diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index d83a6b4a18d..046d49ff4c0 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -322,18 +322,11 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImagePreview), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImagePreview), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashImage), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImage), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImage), // Note: The following configs are commented out for easy one-off manual testing. - // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashPreviewImageGeneration) - // (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashPreviewImageGeneration), - // ( - // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, - // ModelNames.gemini2FlashPreviewImageGeneration - // ), + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2_5_FlashImage) ]) func generateImage(_ config: InstanceConfig, modelName: String) async throws { let generationConfig = GenerationConfig( @@ -354,17 +347,8 @@ struct GenerateContentIntegrationTests { ) let prompt = "Generate an image of a cute cartoon kitten playing with a ball of yarn." - var response: GenerateContentResponse? - try await withKnownIssue( - "Backend may fail with a 503 - Service Unavailable error when overloaded", - isIntermittent: true - ) { - response = try await model.generateContent(prompt) - } matching: { issue in - (issue.error as? BackendError).map { $0.httpResponseCode == 503 } ?? false - } + let response = try await model.generateContent(prompt) - guard let response else { return } let candidate = try #require(response.candidates.first) let inlineDataPart = try #require(candidate.content.parts .first { $0 is InlineDataPart } as? InlineDataPart) @@ -372,16 +356,12 @@ struct GenerateContentIntegrationTests { #expect(inlineDataPartsViaAccessor.count == 1) let inlineDataPartViaAccessor = try #require(inlineDataPartsViaAccessor.first) #expect(inlineDataPart == inlineDataPartViaAccessor) - #expect(inlineDataPart.mimeType == "image/png") + #expect(inlineDataPart.mimeType.starts(with: "image/")) #expect(inlineDataPart.data.count > 0) #if canImport(UIKit) let uiImage = try #require(UIImage(data: inlineDataPart.data)) - // Gemini 2.0 Flash Experimental returns images sized to fit within a 1024x1024 pixel box but - // dimensions may vary depending on the aspect ratio. - #expect(uiImage.size.width <= 1024) - #expect(uiImage.size.width >= 500) - #expect(uiImage.size.height <= 1024) - #expect(uiImage.size.height >= 500) + #expect(uiImage.size.width > 0) + #expect(uiImage.size.height > 0) #endif // canImport(UIKit) } @@ -552,18 +532,11 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImagePreview), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImagePreview), + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_FlashImage), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImage), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImage), // Note: The following configs are commented out for easy one-off manual testing. - // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashPreviewImageGeneration) - // (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashPreviewImageGeneration), - // ( - // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, - // ModelNames.gemini2FlashPreviewImageGeneration - // ), + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2_5_FlashImage) ]) func generateImageStreaming(_ config: InstanceConfig, modelName: String) async throws { let generationConfig = GenerationConfig( @@ -572,11 +545,6 @@ struct GenerateContentIntegrationTests { topK: 1, responseModalities: [.text, .image] ) - let safetySettings = safetySettings.filter { - // HARM_CATEGORY_CIVIC_INTEGRITY is deprecated in Vertex AI but only rejected when using the - // 'gemini-2.0-flash-preview-image-generation' model. - $0.harmCategory != .civicIntegrity - } let model = FirebaseAI.componentInstance(config).generativeModel( modelName: modelName, generationConfig: generationConfig, @@ -605,16 +573,12 @@ struct GenerateContentIntegrationTests { #expect(inlineDataParts.count == 1) let inlineDataPart = try #require(inlineDataParts.first) - #expect(inlineDataPart.mimeType == "image/png") + #expect(inlineDataPart.mimeType.starts(with: "image/")) #expect(inlineDataPart.data.count > 0) #if canImport(UIKit) let uiImage = try #require(UIImage(data: inlineDataPart.data)) - // Gemini 2.0 Flash Experimental returns images sized to fit within a 1024x1024 pixel box but - // dimensions may vary depending on the aspect ratio. - #expect(uiImage.size.width <= 1024) - #expect(uiImage.size.width >= 500) - #expect(uiImage.size.height <= 1024) - #expect(uiImage.size.height >= 500) + #expect(uiImage.size.width > 0) + #expect(uiImage.size.height > 0) #endif // canImport(UIKit) } diff --git a/scripts/build.sh b/scripts/build.sh index f9a79ef0960..68f61b94019 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -113,7 +113,7 @@ function RunXcodebuild() { local buildaction="${xcodebuild_args[$# - 1]}" # buildaction is the last arg local log_filename="xcodebuild-${buildaction}.log" - local xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging) + local xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging --is-ci --preserve-unbeautified) local result=0 NSUnbufferedIO=YES xcodebuild "$@" 2>&1 | tee "$log_filename" | \