diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 570bce868fd..1ed20a09658 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -1,3 +1,12 @@ +# This workflow tests the zip distribution of the SDK. +# There are three ways to configure the source of the zip file for testing: +# 1. To iterate on a PR: Set the `PINNED_RUN_ID` environment variable in this +# file to a successful zip packaging run. This is useful for avoiding +# re-running the packaging jobs on every commit. +# 2. For manual runs: Trigger the workflow via the GitHub UI (`workflow_dispatch`) +# and provide a "Run ID of a previous successful zip workflow" in the input. +# 3. By default (for scheduled and other PR runs): The workflow will build the +# zip from the current commit (HEAD). name: zip # TODO(ncooke3): Add FirebaseAI test. @@ -6,6 +15,11 @@ permissions: actions: read contents: read +env: + # When a run_id is specified, build jobs will be skipped and the specified + # run's artifacts will be used for testing. + PINNED_RUN_ID: '17965877651' + on: pull_request: paths: @@ -39,12 +53,27 @@ concurrency: cancel-in-progress: true jobs: + should_package: + runs-on: ubuntu-latest + outputs: + should_package: ${{ steps.check.outputs.should_package }} + steps: + - name: Check if packaging should be skipped + id: check + run: | + 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 + package-release: + needs: should_package # Don't run on private repo. if: | github.repository == 'firebase/firebase-ios-sdk' && contains(fromJSON('["schedule", "pull_request", "workflow_dispatch"]'), github.event_name) && - github.event.inputs.zip_run_id == '' + needs.should_package.outputs.should_package == 'true' runs-on: macos-14 steps: - uses: actions/checkout@v4 @@ -71,11 +100,12 @@ jobs: path: release_zip_dir build: + needs: should_package # Don't run on private repo unless it is a PR. if: | github.repository == 'firebase/firebase-ios-sdk' && contains(fromJSON('["schedule", "pull_request", "workflow_dispatch"]'), github.event_name) && - github.event.inputs.zip_run_id == '' + needs.should_package.outputs.should_package == 'true' runs-on: macos-14 steps: - uses: actions/checkout@v4 @@ -87,7 +117,8 @@ jobs: swift build -v package-head: - needs: build + needs: [build, should_package] + if: needs.should_package.outputs.should_package == 'true' strategy: matrix: linking_type: [static, dynamic] @@ -110,16 +141,71 @@ jobs: build-head \ ${{ matrix.linking_type }} - uses: actions/upload-artifact@v4 - if: ${{ always() }} + if: always() with: name: ${{ matrix.linking_type == 'static' && 'Firebase-actions-dir' || 'Firebase-actions-dir-dynamic' }} # Zip the entire output directory since the builder adds subdirectories we don't know the # name of. path: zip_output_dir + packaging_done: + runs-on: ubuntu-latest + needs: [package-head] + if: always() + outputs: + run_id: ${{ steps.get_run_id.outputs.run_id }} + steps: + - name: Check packaging result + if: ${{ needs.package-head.result == 'failure' }} + run: | + echo "Packaging failed. Aborting." + exit 1 + - 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 + 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 + + check_framework_firestore_symbols: + needs: packaging_done + if: ${{ !cancelled() }} + env: + FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 + runs-on: macos-14 + steps: + - name: Xcode 16.2 + run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + - uses: actions/checkout@v4 + - name: Get framework dir + uses: actions/download-artifact@v4.1.7 + with: + name: Firebase-actions-dir + run-id: ${{ needs.packaging_done.outputs.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Setup Bundler + run: ./scripts/setup_bundler.sh + - name: Install xcpretty + run: gem install xcpretty + - name: Move frameworks + run: | + mkdir -p "${HOME}"/ios_frameworks/ + find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + + - uses: actions/checkout@v4 + - name: Check linked Firestore.xcframework for unlinked symbols. + run: | + scripts/check_firestore_symbols.sh \ + $(pwd) \ + "${HOME}"/ios_frameworks/Firebase/FirebaseFirestore/FirebaseFirestoreInternal.xcframework + quickstart_framework_abtesting: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "ABTesting" @@ -136,7 +222,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -162,24 +248,30 @@ jobs: - name: Test Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - name: Remove data before upload - if: ${{ failure() }} + if: always() run: scripts/remove_data.sh abtesting # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} + # if: failure() # with: # name: quickstart_artifacts_abtesting - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_abtesting + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_auth: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Authentication" strategy: matrix: os: [macos-15] - artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] + artifact: [Firebase-actions-dir] , Firebase-actions-dir-dynamic] include: - os: macos-15 xcode: Xcode_16.4 @@ -190,7 +282,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -212,18 +304,17 @@ jobs: quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - name: Test Swift Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh authentiation - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_auth - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_auth + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_config: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Config" @@ -240,7 +331,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -262,17 +353,17 @@ jobs: - name: Test Swift Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - name: Remove data before upload - if: ${{ failure() }} + if: always() run: scripts/remove_data.sh config - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_config - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_config + path: quickstart-ios/ quickstart_framework_crashlytics: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Crashlytics" @@ -289,7 +380,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -303,13 +394,18 @@ jobs: - uses: actions/checkout@v4 - name: Setup quickstart run: | - SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ - "${HOME}"/ios_frameworks/Firebase/FirebaseCrashlytics/* \ - "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - cp quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Firebase/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart - cp quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Firebase/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart - chmod +x quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/run - chmod +x quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/upload-symbols + rm -rf "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/FirebaseAnalytics* + rm -rf "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/GoogleAppMeasurement* + rm -rf "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/GoogleAds* + SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ + "${HOME}"/ios_frameworks/Firebase/FirebaseCrashlytics/* \ + "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* + - name: Add frameworks to Crashlytics watchOS target + run: | + cd quickstart-ios/crashlytics + "${GITHUB_WORKSPACE}"/quickstart-ios/scripts/add_framework_script.rb --sdk "Crashlytics" --target "CrashlyticsExample_(watchOS)_Extension" --framework_path Firebase/ + - name: Patch Crashlytics Run Script Path + run: scripts/patch_crashlytics_run_path.rb # TODO(#8057): Restore Swift Quickstart # - name: Setup swift quickstart # env: @@ -327,18 +423,17 @@ jobs: # env: # LEGACY: true # run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}" swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh crashlytics - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_crashlytics - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_crashlytics + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_database: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Database" @@ -354,7 +449,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -379,18 +474,17 @@ jobs: quickstart-ios/database/GoogleService-Info.plist "$plist_secret" - name: Test Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh database - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts database - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_database + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_firestore: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Firestore" @@ -407,7 +501,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -426,7 +520,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Upload build logs on failure - if: ${{ failure() }} + if: failure() uses: actions/upload-artifact@v4 with: name: build_logs_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} @@ -437,49 +531,17 @@ jobs: - name: Test Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - name: Remove data before upload and zip directory to reduce upload size. - if: ${{ failure() }} + if: always() run: scripts/remove_data.sh firestore; zip -r --symlinks quickstart_artifacts_firestore.zip quickstart-ios/ - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} - # path: quickstart_artifacts_firestore.zip - - check_framework_firestore_symbols: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - runs-on: macos-14 - steps: - - name: Xcode 16.2 - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - uses: actions/checkout@v4 - - name: Get framework dir - uses: actions/download-artifact@v4.1.7 - with: - name: Firebase-actions-dir - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup Bundler - run: ./scripts/setup_bundler.sh - - name: Install xcpretty - run: gem install xcpretty - - name: Move frameworks - run: | - mkdir -p "${HOME}"/ios_frameworks/ - find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - - uses: actions/checkout@v4 - - name: Check linked Firestore.xcframework for unlinked symbols. - run: | - scripts/check_firestore_symbols.sh \ - $(pwd) \ - "${HOME}"/ios_frameworks/Firebase/FirebaseFirestore/FirebaseFirestoreInternal.xcframework + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} + path: quickstart_artifacts_firestore.zip quickstart_framework_inappmessaging: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "InAppMessaging" @@ -496,7 +558,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -521,18 +583,17 @@ jobs: run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - name: Test Swift Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}" swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh inappmessaging - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_inappmessaging - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_inappmessaging + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_messaging: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Messaging" @@ -549,7 +610,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -574,18 +635,17 @@ jobs: run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - name: Test Swift Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}" swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh messaging - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_messaging - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_messaging + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist quickstart_framework_storage: - needs: package-head - if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} + needs: packaging_done + if: ${{ !cancelled() }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Storage" @@ -602,7 +662,7 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} - run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + run-id: ${{ needs.packaging_done.outputs.run_id }} github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode @@ -626,13 +686,10 @@ jobs: quickstart-ios/storage/GoogleService-Info.plist "$plist_secret" - name: Test Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") - - name: Test Swift Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}" swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh storage - # - uses: actions/upload-artifact@v4 - # if: ${{ failure() }} - # with: - # name: quickstart_artifacts_storage - # path: quickstart-ios/ + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: quickstart_artifacts_storage + path: | + quickstart-ios/ + !quickstart-ios/**/GoogleService-Info.plist diff --git a/scripts/patch_crashlytics_run_path.rb b/scripts/patch_crashlytics_run_path.rb new file mode 100755 index 00000000000..0af96faed0b --- /dev/null +++ b/scripts/patch_crashlytics_run_path.rb @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'xcodeproj' + +# This script patches the Crashlytics Quickstart's Xcode project to fix the +# path to the `run` script for XCFramework-based builds. +# +# The default project assumes an SPM dependency. This script changes the path +# to point to the location where the `run` script is placed in the zip +# distribution test environment. + +project_path = 'quickstart-ios/crashlytics/CrashlyticsExample.xcodeproj' +project = Xcodeproj::Project.open(project_path) +new_path = '"${SRCROOT}/Firebase/run"' + +project.targets.each do |target| + target.build_phases.each do |phase| + if phase.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && phase.name == 'Run Script' + if phase.shell_script.include?('SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run') + puts "Patching Run Script phase in target '#{target.name}' to: #{new_path}" + phase.shell_script = new_path + end + end + end +end + +project.save diff --git a/scripts/remove_spm_dependencies.rb b/scripts/remove_spm_dependencies.rb new file mode 100755 index 00000000000..d755ad917ea --- /dev/null +++ b/scripts/remove_spm_dependencies.rb @@ -0,0 +1,112 @@ +#!/usr/bin/env ruby + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may +# obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'xcodeproj' +require 'set' + +# This script removes all Swift Package Manager dependencies from an Xcode project. +# It's designed to be used in CI to prepare a project for framework-based testing. + +# --- Argument Parsing --- +unless ARGV.length == 1 + puts "Usage: #{$0} " + exit 1 +end + +project_path = ARGV[0] + +# --- Main Logic --- +begin + project = Xcodeproj::Project.open(project_path) +rescue => e + puts "Error opening project at #{project_path}: #{e.message}" + exit 1 +end + +puts "Opened project: #{project.path}" + +# --- Step 1: Find all SPM product dependencies --- +package_product_dependencies = project.objects.select do |obj| + obj.is_a?(Xcodeproj::Project::Object::XCSwiftPackageProductDependency) +end + +if package_product_dependencies.empty? + puts "No SPM product dependencies found to remove." +else + puts "Found #{package_product_dependencies.count} SPM product dependencies. Removing all references..." + package_product_dep_uuids = package_product_dependencies.map(&:uuid).to_set + + # --- Step 2: Find all BuildFile objects that reference these SPM products --- + build_files_to_remove = project.objects.select do |obj| + obj.is_a?(Xcodeproj::Project::Object::PBXBuildFile) && + obj.product_ref && + package_product_dep_uuids.include?(obj.product_ref.uuid) + end + build_file_uuids_to_remove = build_files_to_remove.map(&:uuid).to_set + + # --- Step 3: Remove references from all targets --- + project.targets.each do |target| + puts "Cleaning target '#{target.name}'..." + + # Remove from target dependencies list + removed_deps = target.dependencies.reject! do |dep| + package_product_dep_uuids.include?(dep.uuid) + end + if removed_deps + puts " - Removed #{removed_deps.count} SPM target dependencies." + end + + # Remove from build phases (e.g., "Link Binary With Libraries") + target.build_phases.each do |phase| + next unless phase.respond_to?(:files) + + original_file_count = phase.files.count + phase.files.reject! do |build_file| + build_file_uuids_to_remove.include?(build_file.uuid) + end + removed_count = original_file_count - phase.files.count + if removed_count > 0 + puts " - Removed #{removed_count} SPM build file references from '#{phase.display_name}'." + end + end + end + + # --- Step 4: Delete the now-orphaned BuildFile and dependency objects --- + puts "Deleting #{build_files_to_remove.count} SPM BuildFile object(s)..." + build_files_to_remove.each(&:remove_from_project) + + puts "Deleting #{package_product_dependencies.count} SPM product dependency object(s)..." + package_product_dependencies.each(&:remove_from_project) +end + +# --- Step 5: Remove package references from the project root --- +unless project.root_object.package_references.empty? + puts "Removing #{project.root_object.package_references.count} package reference(s)..." + project.root_object.package_references.clear + puts "All package references removed from the project." +else + puts "No package references found in the project." +end + +# --- Step 6: Save the modified project --- +begin + project.save + puts "Project saved successfully." +rescue => e + puts "Error saving project: #{e.message}" + exit 1 +end diff --git a/scripts/setup_quickstart_framework.sh b/scripts/setup_quickstart_framework.sh index 51499ab6efa..f79bd0baa18 100755 --- a/scripts/setup_quickstart_framework.sh +++ b/scripts/setup_quickstart_framework.sh @@ -20,6 +20,11 @@ if [ ! -d "quickstart-ios" ]; then fi QS_SCRIPTS="${REPO}"/quickstart-ios/scripts cd quickstart-ios/"${SAMPLE}" +git checkout nc/quickstarts + +# Remove all SPM dependencies from the project. This is necessary to prepare +# the project for framework-based testing. +"${REPO}"/scripts/remove_spm_dependencies.rb "${SAMPLE}Example.xcodeproj" if [[ ! -z "$LEGACY" ]]; then cd "Legacy${SAMPLE}Quickstart" diff --git a/scripts/zip_quickstart_test.sh b/scripts/zip_quickstart_test.sh index 3b531f8e3f9..1476b2b1985 100755 --- a/scripts/zip_quickstart_test.sh +++ b/scripts/zip_quickstart_test.sh @@ -42,10 +42,23 @@ else device_name="iPhone 16" fi +# Define project and scheme names +PROJECT_NAME="${SAMPLE}Example.xcodeproj" +SCHEME_NAME="${SAMPLE}Example${SWIFT_SUFFIX}" + +# Check if the scheme exists before attempting to build. +# The `awk` command prints all lines from "Schemes:" to the end of the output. +if ! xcodebuild -list -project "${PROJECT_NAME}" | awk '/Schemes:/,0' | grep -q "^\s*${SCHEME_NAME}"$; then + echo "Error: Scheme '${SCHEME_NAME}' not found in project '${PROJECT_NAME}'." + echo "Available schemes from '${PROJECT_NAME}':" + xcodebuild -list -project "${PROJECT_NAME}" + exit 65 +fi + ( xcodebuild \ --project ${SAMPLE}Example.xcodeproj \ --scheme ${SAMPLE}Example${SWIFT_SUFFIX} \ +-project ${PROJECT_NAME} \ +-scheme ${SCHEME_NAME} \ -destination "platform=iOS Simulator,name=$device_name" "SWIFT_VERSION=5.3" "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ObjC" "FRAMEWORK_SEARCH_PATHS= \$(PROJECT_DIR)/Firebase/" HEADER_SEARCH_PATHS='$(PROJECT_DIR)/Firebase' \ build \ ) || EXIT_STATUS=$?