Преглед изворни кода

[Infra] Common cocoapods pod lib lint job (#14876)

Nick Cooke пре 10 месеци
родитељ
комит
588c02370e

+ 10 - 38
.github/workflows/abtesting.yml

@@ -1,5 +1,8 @@
 name: abtesting
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseABTesting**'
     - 'Interop/Analytics/Public/*.h'
     - '.github/workflows/abtesting.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 1am(PST) - cron uses UTC times
@@ -28,43 +33,10 @@ jobs:
       product: FirebaseABTesting
       target: FirebaseABTesting-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-            target: ios
-          - os: macos-15
-            xcode: Xcode_16.2
-            target: ios
-          - os: macos-15
-            xcode: Xcode_16.2
-            target: tvos
-          - os: macos-15
-            xcode: Xcode_16.2
-            target: macos
-          - os: macos-15
-            xcode: Xcode_16.2
-            target: watchos
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/pod_lib_lint.rb FirebaseABTesting.podspec --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseABTesting
 
   quickstart:
     # Don't run on private repo unless it is a PR.
@@ -136,7 +108,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 11 - 24
.github/workflows/appdistribution.yml

@@ -1,11 +1,16 @@
 name: appdistribution
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
     paths:
     - 'FirebaseAppDistribution**'
     - '.github/workflows/appdistribution.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 1am (PST) - cron uses UTC times
@@ -28,29 +33,11 @@ jobs:
       product: FirebaseAppDistribution
       target: FirebaseAppDistribution-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.3
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: |
-       scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAppDistribution.podspec \
-         --platforms=ios
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseAppDistribution
+      platforms: iOS # App Distro only supports iOS.
 
   appdistribution-cron-only:
     if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk'
@@ -62,7 +49,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 12 - 26
.github/workflows/auth.yml

@@ -1,5 +1,8 @@
 name: auth
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseAuth**'
     - 'FirebaseAuth/Interop/*.h'
     - '.github/workflows/auth.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'scripts/gha-encrypted/AuthSample/SwiftApplication.plist.gpg'
     - 'Gemfile*'
   schedule:
@@ -34,33 +39,14 @@ jobs:
       target: FirebaseAuth-Unit-unit
       buildonly: true
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
+  pod_lib_lint:
     strategy:
       matrix:
-        podspec: [FirebaseAuthInterop.podspec, FirebaseAuth.podspec]
-        target: [ios, tvos, macos --skip-tests, watchos]
-        os: [macos-15]
-        xcode: [Xcode_16.3]
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Configure test keychain
-      run: scripts/configure_test_keychain.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} ${{ matrix.tests }}
+        product: [FirebaseAuthInterop, FirebaseAuth]
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: ${{  matrix.product }}
+      buildonly_platforms: macOS
 
   spm-package-resolved:
     env:
@@ -190,7 +176,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 20 - 2
.github/workflows/common.yml

@@ -41,6 +41,22 @@ on:
        required: false
        default: ""
 
+      # A command to execute before testing.
+      #
+      # This is useful for additional set up, like starting an emulator or
+      # downloading test data.
+      #
+      # Example: `FirebaseFunctions/Backend/start.sh synchronous`
+      setup_command:
+        type: string
+        required: false
+        default: ""
+
+    outputs:
+      cache_key:
+        description: "The cache key for the Swift package resolution."
+        value: ${{ jobs.spm-package-resolved.outputs.cache_key }}
+
 jobs:
   spm-package-resolved:
     env:
@@ -54,8 +70,7 @@ jobs:
         run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
       - name: Generate Swift Package.resolved
         id: swift_package_resolve
-        run: |
-          swift package resolve
+        run: swift package resolve
       - name: Generate cache key
         id: generate_cache_key
         run: |
@@ -92,6 +107,9 @@ jobs:
     - name: Install visionOS, if needed.
       if: matrix.platform == 'visionOS'
       run: xcodebuild -downloadPlatform visionOS
+    - name: Run setup command, if needed.
+      if: inputs.setup_command != ''
+      run: ${{ inputs.setup_command }}
     - name: Initialize xcodebuild
       run: scripts/setup_spm_tests.sh
     - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3

+ 116 - 0
.github/workflows/common_cocoapods.yml

@@ -0,0 +1,116 @@
+name: common_cocoapods
+
+permissions:
+  contents: read
+
+on:
+  workflow_call:
+    inputs:
+      # The product to test be tested (e.g. `FirebaseABTesting`).
+      product:
+        type: string
+        required: true
+
+      # The platforms to build on. Defaults to all.
+      # To target specific platforms, pass a comma or space separated string of
+      # platforms.
+      #
+      # Examples:
+      # - build/test only for macOS: `macOS`
+      # - build/test only for macOS and tvOS: `macOS, tvOS`
+      platforms:
+        type: string
+        required: false
+        default: "iOS, tvOS, macOS, watchOS"
+
+      # By default, all platforms will be tested (see matrix in `spm` job).
+      # To build instead of test, pass a comma or space separated string of
+      # platforms.
+      #
+      # Platform options: [iOS, tvOS, macOS, watchOS, catalyst, visionOS]
+      #
+      # Note: Build-only platforms must be represented in the `platforms` input
+      # (which defaults to all platforms) in order to take effect.
+      #
+      # Examples:
+      # - build only for macOS: `macOS`
+      # - build only for macOS and tvOS: `macOS, tvOS`
+      # - build only for all platforms: `all`
+      buildonly_platforms:
+       type: string
+       required: false
+       default: ""
+
+      # Whether to lint with `--allow-warnings`. Defaults to false.
+      allow_warnings:
+        type: boolean
+        required: false
+        default: false
+
+      # Whether to additionally build with Swift 6. Defaults to false.
+      supports_swift6:
+        type: boolean
+        required: false
+        default: false
+
+      # A comma separated (no spaces) string that will be passed to
+      # pod lib lint's `--test-specs=` argument. By default, all
+      # test specs will be tested.
+      test_specs:
+       type: string
+       required: false
+       default: ""
+
+      # A command to execute before testing.
+      #
+      # This is useful for additional set up, like starting an emulator or
+      # downloading test data.
+      #
+      # Example: `FirebaseFunctions/Backend/start.sh synchronous`
+      setup_command:
+        type: string
+        required: false
+        default: ""
+
+jobs:
+  pod-lib-lint:
+    # Run on the main repo's scheduled jobs or pull requests and manual workflow invocations.
+    if: (github.repository == 'firebase/firebase-ios-sdk' && github.event_name == 'schedule') || contains(fromJSON('["pull_request", "workflow_dispatch"]'), github.event_name)
+    strategy:
+      matrix:
+        os: [macos-15]
+        xcode: [Xcode_16.3]
+        platform: [iOS, tvOS, macOS, watchOS]
+        include:
+          - os: macos-14
+            xcode: Xcode_16.2
+            platform: iOS
+    runs-on: ${{ matrix.os }}
+    steps:
+    - uses: actions/checkout@v4
+    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
+    - name: Setup Bundler
+      run: scripts/setup_bundler.sh
+    - name: Xcode
+      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
+    - name: Set conditional environment variable, if needed.
+      if: inputs.product == 'FirebaseAuth'
+      run: echo "FIREBASE_CI=true" >> $GITHUB_ENV
+    - name: Set podspec Swift version to 6.0, if supported.
+      if: inputs.supports_swift6 == true && matrix.os != 'macos-14'
+      run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '6.0'/" ${{ inputs.product }}.podspec
+    - name: Run setup command, if needed.
+      if: inputs.setup_command != ''
+      run: ${{ inputs.setup_command }}
+    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
+      if: contains(join(inputs.platforms), matrix.platform) || matrix.os == 'macos-14'
+      with:
+        timeout_minutes: 120
+        max_attempts: 3
+        retry_on: error
+        retry_wait_seconds: 120
+        command: |
+          scripts/pod_lib_lint.rb ${{ inputs.product }}.podspec --platforms=${{ matrix.platform }} \
+            ${{ inputs.allow_warnings == true && '--allow-warnings' || '' }} \
+            ${{ inputs.test_specs != '' && format('--test-specs={0}', inputs.test_specs) || '' }} \
+            ${{ (contains(inputs.buildonly_platforms, matrix.platform) || contains(inputs.buildonly_platforms, 'all')) && '--skip-tests' || '' }}

+ 10 - 26
.github/workflows/core.yml

@@ -1,11 +1,16 @@
 name: core
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
     paths:
     - 'FirebaseCore**'
     - '.github/workflows/core.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 2am (PST) - cron uses UTC times
@@ -27,31 +32,10 @@ jobs:
       product: FirebaseCore
       target: FirebaseCore-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532
-        target: [ios, tvos, macos --skip-tests, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-          # TODO: Add Xcode matrix when Xcode 16 is ubiquitous on CI runners.
-#          - os: macos-15
-#            xcode: Xcode_16.3
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCore.podspec --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseCore
 
   spm-package-resolved:
     env:
@@ -89,7 +73,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 10 - 26
.github/workflows/core_extension.yml

@@ -1,5 +1,8 @@
 name: core_extension
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseCoreExtension.podspec'
     - 'FirebaseCore/Extension/**'
     - '.github/workflows/core_extension.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 2am (PST) - cron uses UTC times
@@ -14,31 +19,10 @@ on:
 
 jobs:
   # Since `FirebaseCoreExtension` only contains headers, linting is sufficient for testing.
-
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-          # TODO: Enable when Xcode 16 is ubiquitous on CI runners.
-#          - os: macos-15
-#            xcode: Xcode_16.3
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreExtension.podspec --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseCoreExtension
 
   core-internal-cron-only:
     # Don't run on private repo.
@@ -50,7 +34,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 11 - 29
.github/workflows/core_internal.yml

@@ -1,5 +1,8 @@
 name: core_internal
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseCoreInternal.podspec'
     - 'FirebaseCore/Internal/**'
     - '.github/workflows/core_internal.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 2am (PST) - cron uses UTC times
@@ -27,34 +32,11 @@ jobs:
       product: FirebaseCoreInternal
       target: ${{ matrix.target }}
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-            swift_version: 5.9
-          - os: macos-15
-            xcode: Xcode_16.2
-            swift_version: 5.9
-          - os: macos-15
-            xcode: Xcode_16.2
-            swift_version: 6.0
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Set Swift swift_version
-      run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseCoreInternal.podspec
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreInternal.podspec --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseCoreInternal
+      supports_swift6: true
 
   core-internal-cron-only:
     # Don't run on private repo.
@@ -66,7 +48,7 @@ jobs:
         flags: [
           '--use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 13 - 35
.github/workflows/crashlytics.yml

@@ -1,5 +1,8 @@
 name: crashlytics
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'Crashlytics**'
     - 'FirebaseCrashlytics.podspec'
     - '.github/workflows/crashlytics.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Interop/Analytics/Public/*.h'
     - 'Gemfile*'
   schedule:
@@ -29,39 +34,11 @@ jobs:
       product: FirebaseCrashlytics
       target: FirebaseCrashlytics-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos --skip-tests]
-        flags: [
-          '--use-modular-headers --skip-tests',
-          ''
-        ]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-            tests:
-          - os: macos-15
-            xcode: Xcode_16.2
-            tests:
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/pod_lib_lint.rb FirebaseCrashlytics.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }} ${{ matrix.flags }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseCrashlytics
+      buildonly_platforms: tvOS, macOS, watchOS
 
   quickstart:
     # Don't run on private repo unless it is a PR.
@@ -142,9 +119,10 @@ jobs:
         # Disable watchos because it does not support XCTest.
         target: [ios, tvos, macos, watchos --skip-tests]
         flags: [
-          '--use-static-frameworks'
+          '--use-static-frameworks',
+          '--use-modular-headers --skip-tests'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 12 - 22
.github/workflows/database.yml

@@ -1,5 +1,8 @@
 name: database
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -10,6 +13,8 @@ on:
     - 'Example/Database/**'
     - 'FirebaseAuth/Interop/*.h'
     - '.github/workflows/database.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
     - 'scripts/run_database_emulator.sh'
   schedule:
@@ -35,27 +40,12 @@ jobs:
       product: FirebaseDatabase
       target: FirebaseDatabase-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        target: [ios, tvos, macos --skip-tests, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDatabase.podspec --test-specs=unit --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseDatabase
+      test_specs: unit
+      buildonly_platforms: macOS
 
   integration:
     # Don't run on private repo unless it is a PR.
@@ -110,7 +100,7 @@ jobs:
         flags: [
           '--skip-tests --use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 10 - 20
.github/workflows/dynamiclinks.yml

@@ -1,5 +1,8 @@
 name: dynamiclinks
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseDynamicLinks**'
     - '.github/workflows/dynamiclinks.yml'
     - 'Interop/Analytics/Public/*.h'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 1am (PST) - cron uses UTC times
@@ -28,26 +33,11 @@ jobs:
       platforms: iOS
 
   pod_lib_lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: FirebaseDynamicLinks
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDynamicLinks.podspec --allow-warnings
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseDynamicLinks
+      platforms: iOS # Dynamic Links only supports iOS.
+      allow_warnings: true
 
   dynamiclinks-cron-only:
     # Don't run on private repo.

+ 10 - 21
.github/workflows/firebase_app_check.yml

@@ -1,11 +1,16 @@
 name: firebase_app_check
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
     paths:
     - 'FirebaseAppCheck**'
     - '.github/workflows/firebase_app_check.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 11pm (PST) - cron uses UTC times
@@ -31,29 +36,13 @@ jobs:
       target: FirebaseAppCheck-Unit-unit
 
   pod_lib_lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
     strategy:
       matrix:
-        podspec: [FirebaseAppCheckInterop.podspec, FirebaseAppCheck.podspec]
-        target: [ios, tvos, macos --skip-tests, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Configure test keychain
-      run: scripts/configure_test_keychain.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: FirebaseAppCheck
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }}
+        product: [FirebaseAppCheckInterop, FirebaseAppCheck]
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: ${{  matrix.product }}
+      buildonly_platforms: macOS
 
   diagnostics:
     # Don't run on private repo unless it is a PR.

+ 15 - 108
.github/workflows/firebaseai.yml

@@ -5,6 +5,8 @@ on:
     paths:
     - 'FirebaseAI**'
     - '.github/workflows/firebaseai.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'scripts/quickstart_build_spm.sh'
     - 'scripts/quickstart_spm_xcodeproj.sh'
     - 'Gemfile*'
@@ -24,80 +26,11 @@ permissions:
   actions: write # Needed for actions/cache (save and restore)
 
 jobs:
-  spm-package-resolved:
-    runs-on: macos-14
-    outputs:
-      cache_key: ${{ steps.generate_cache_key.outputs.cache_key }}
-    env:
-      FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
-    steps:
-      - uses: actions/checkout@v4
-      - name: Generate Swift Package.resolved
-        id: swift_package_resolve
-        run: |
-          swift package resolve
-      - name: Generate cache key
-        id: generate_cache_key
-        run: |
-          cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}"
-          echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT"
-      - uses: actions/cache/save@v4
-        id: cache
-        with:
-          path: .build
-          key: ${{ steps.generate_cache_key.outputs.cache_key }}
-
-  spm-unit:
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-            target: iOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: iOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: tvOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: macOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: watchOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: catalyst
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: visionOS
-    runs-on: ${{ matrix.os }}
-    needs: spm-package-resolved
-    env:
-      FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
-    steps:
-    - uses: actions/checkout@v4
-    - uses: actions/cache/restore@v4
-      with:
-        path: .build
-        key: ${{needs.spm-package-resolved.outputs.cache_key}}
-    - name: Clone mock responses
-      run: scripts/update_vertexai_responses.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: Install visionOS, if needed.
-      if: matrix.target == 'visionOS'
-      run: xcodebuild -downloadPlatform visionOS
-    - name: Initialize xcodebuild
-      run: scripts/setup_spm_tests.sh
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/build.sh FirebaseAIUnit ${{ matrix.target }} spm
+  spm:
+    uses: ./.github/workflows/common.yml
+    with:
+      target: FirebaseAIUnit
+      setup_command: scripts/update_vertexai_responses.sh
 
   testapp-integration:
     strategy:
@@ -108,7 +41,7 @@ jobs:
           - os: macos-15
             xcode: Xcode_16.3
     runs-on: ${{ matrix.os }}
-    needs: spm-package-resolved
+    needs: spm
     env:
       TEST_RUNNER_FIRAAppCheckDebugToken: ${{ secrets.VERTEXAI_INTEGRATION_FAC_DEBUG_TOKEN }}
       TEST_RUNNER_VTXIntegrationImagen: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
@@ -119,7 +52,7 @@ jobs:
     - uses: actions/cache/restore@v4
       with:
         path: .build
-        key: ${{needs.spm-package-resolved.outputs.cache_key}}
+        key: ${{ needs.spm.outputs.cache_key }}
     - name: Install Secret GoogleService-Info.plist
       run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/VertexAI/TestApp-GoogleService-Info.plist.gpg \
         FirebaseAI/Tests/TestApp/Resources/GoogleService-Info.plist "$secrets_passphrase"
@@ -141,38 +74,12 @@ jobs:
         path: xcodebuild-*.log
         retention-days: 2
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-            swift_version: 5.9
-            warnings:
-          - os: macos-15
-            xcode: Xcode_16.3
-            swift_version: 5.9
-            warnings:
-          - os: macos-15
-            xcode: Xcode_16.3
-            swift_version: 6.0
-            warnings:
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - name: Clone mock responses
-      run: scripts/update_vertexai_responses.sh
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: Set Swift swift_version
-      run: sed -i "" "s#s.swift_version = '5.9'#s.swift_version = '${{ matrix.swift_version}}'#" FirebaseAI.podspec
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAI.podspec --platforms=${{ matrix.target }} ${{ matrix.warnings }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseAI
+      supports_swift6: true
+      setup_command: scripts/update_vertexai_responses.sh
 
   quickstart:
     runs-on: macos-15

+ 12 - 29
.github/workflows/functions.yml

@@ -1,5 +1,8 @@
 name: functions
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseFunctions**'
     - 'FirebaseSharedSwift**'
     - '.github/workflows/functions.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'FirebaseAuth/Interop/*.h'
     - 'FirebaseMessaging/Interop/*.h'
     - 'FirebaseTestingSupport/Functions/**'
@@ -23,34 +28,12 @@ concurrency:
     cancel-in-progress: true
 
 jobs:
-
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos]
-        swift_version: [5.9, 6.0]
-        build-env:
-          - os: macos-15
-            xcode: Xcode_16.3
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Integration Test Server
-      run: FirebaseFunctions/Backend/start.sh synchronous
-    - name: Set Swift swift_version
-      run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.swift_version }}'/" FirebaseFunctions.podspec
-    - name: Build and test
-      run: |
-        scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseFunctions.podspec \
-          --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseFunctions
+      supports_swift6: true
+      setup_command: FirebaseFunctions/Backend/start.sh synchronous
 
   spm-package-resolved:
     runs-on: macos-14
@@ -227,7 +210,7 @@ jobs:
         flags: [
           '--use-static-frameworks',
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 9 - 21
.github/workflows/inappmessaging.yml

@@ -1,5 +1,8 @@
 name: inappmessaging
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseInAppMessaging**'
     - 'Interop/Analytics/Public/*.h'
     - '.github/workflows/inappmessaging.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 10pm (PST) - cron uses UTC times
@@ -25,27 +30,10 @@ jobs:
       buildonly_platforms: iOS
 
   pod_lib_lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        podspec: [FirebaseInAppMessaging.podspec]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.2
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: FirebaseInAppMessaging
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec}}
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseInAppMessaging
+      platforms: iOS, tvOS
 
   tests:
     # Don't run on private repo unless it is a PR.

+ 14 - 25
.github/workflows/messaging.yml

@@ -1,5 +1,8 @@
 name: messaging
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -12,6 +15,9 @@ on:
     - 'FirebaseMessaging.podspec'
     # This file
     - '.github/workflows/messaging.yml'
+    # Re-usable workflows being used by this file.
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     # Rebuild on Ruby infrastructure changes
     - 'Gemfile*'
   schedule:
@@ -35,6 +41,14 @@ jobs:
       product: FirebaseMessaging
       target: FirebaseMessaging-Unit-unit
 
+  pod_lib_lint:
+    strategy:
+      matrix:
+        product: [FirebaseMessagingInterop, FirebaseMessaging]
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: ${{  matrix.product }}
+
   # TODO(#12205) Update the build.sh script for this job from "test" instead of "build"
   messaging-integration-tests:
     # Don't run on private repo unless it is a PR.
@@ -64,31 +78,6 @@ jobs:
     - name: BuildAndTest
       run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/build.sh Messaging all)
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        podspec: [FirebaseMessagingInterop.podspec, FirebaseMessaging.podspec]
-        target: [ios, tvos, macos --skip-tests, watchos --skip-tests] # skipping tests on mac because of keychain access
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-            tests: --test-specs=unit
-          - os: macos-15
-            xcode: Xcode_16.3
-            tests: --skip-tests
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} ${{ matrix.build-env.tests }} --platforms=${{ matrix.target }}
-
   quickstart:
     # Don't run on private repo unless it is a PR.
     if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'

+ 14 - 25
.github/workflows/performance.yml

@@ -2,6 +2,9 @@
 # Reference: https://github.community/t/on-schedule-per-branch/17525
 name: performance
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -12,6 +15,9 @@ on:
     - 'FirebasePerformance.podspec'
     # YML configuration file
     - '.github/workflows/performance.yml'
+    # Re-usable workflows depended on by this file.
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     # Rebuild on Ruby infrastructure changes
     - 'Gemfile*'
   schedule:
@@ -61,30 +67,13 @@ jobs:
     - name: BuildAndTest # can be replaced with pod lib lint with CocoaPods 1.10
       run: scripts/third_party/travis/retry.sh scripts/build.sh Performance ${{ matrix.target }} ${{ matrix.test }}
 
-  # Podspec lint check for Firebase Performance
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        target: [ios, tvos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          - os: macos-15
-            xcode: Xcode_16.3
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build
-    #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebasePerformance.podspec --skip-tests --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebasePerformance
+      platforms: iOS, tvOS
+      #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer
+      buildonly_platforms: iOS, tvOS
 
   quickstart:
     if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
@@ -150,7 +139,7 @@ jobs:
         flags: [
           '--skip-tests --use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 10 - 29
.github/workflows/remoteconfig.yml

@@ -1,5 +1,8 @@
 name: remoteconfig
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseRemoteConfig**'
     - 'Interop/Analytics/Public/*.h'
     - '.github/workflows/remoteconfig.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
     - 'scripts/generate_access_token.sh'
     - 'scripts/gha-encrypted/RemoteConfigSwiftAPI/**'
@@ -72,34 +77,10 @@ jobs:
       # No retry to avoid exhausting AccessToken quota.
       run: ([ -z $plist_secret ] || scripts/build.sh RemoteConfig iOS integration)
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532
-        target: [ios, tvos, macos --skip-tests, watchos]
-        podspec: [FirebaseRemoteConfig.podspec]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-          # Flaky tests on CI
-          - os: macos-15
-            xcode: Xcode_16.3
-            tests: --skip-tests
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Build and test
-      run: |
-       scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} \
-         ${{ matrix.build-env.tests }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseRemoteConfig
 
   quickstart:
     # Don't run on private repo unless it is a PR.
@@ -178,7 +159,7 @@ jobs:
         flags: [
           '--skip-tests --use-static-frameworks'
         ]
-    needs: pod-lib-lint
+    needs: pod_lib_lint
     steps:
     - uses: actions/checkout@v4
     - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1

+ 10 - 39
.github/workflows/sessions.yml

@@ -1,5 +1,8 @@
 name: sessions
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
@@ -7,6 +10,8 @@ on:
     - 'FirebaseSessions**'
     - 'FirebaseSessions.podspec'
     - '.github/workflows/sessions.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 9am (PST) - cron uses UTC times
@@ -28,42 +33,8 @@ jobs:
       product: FirebaseSessions
       target: FirebaseSessions-Unit-unit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-            tests:
-            swift_version: 5.9
-          # Flaky tests on CI
-          - os: macos-15
-            xcode: Xcode_16.3
-            tests: --skip-tests
-            swift_version: 5.9
-          # Flaky tests on CI
-          - os: macos-15
-            xcode: Xcode_16.2
-            tests: --skip-tests
-            swift_version: 6.0
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Set Swift swift_version
-      run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseSessions.podspec
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseSessions
+      supports_swift6: true

+ 10 - 29
.github/workflows/shared-swift.yml

@@ -1,11 +1,16 @@
 name: shared-swift
 
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   pull_request:
     paths:
     - 'FirebaseSharedSwift**'
     - '.github/workflows/shared-swift.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
 
   schedule:
@@ -22,32 +27,8 @@ jobs:
     with:
       target: FirebaseSharedSwiftTests
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-
-    strategy:
-      matrix:
-        target: [ios, tvos, macos, watchos]
-        build-env:
-          - os: macos-14
-            xcode: Xcode_16.2
-            swift_version: 5.9
-          - os: macos-15
-            xcode: Xcode_16.2
-            swift_version: 5.9
-          - os: macos-15
-            xcode: Xcode_16.3
-            swift_version: 6.0
-    runs-on: ${{ matrix.build-env.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer
-    - name: Set Swift swift_version
-      run: sed -i "" "s/s.swift_version[[:space:]]*=[[:space:]]*'5.9'/s.swift_version = '${{ matrix.build-env.swift_version }}'/" FirebaseSharedSwift.podspec
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSharedSwift.podspec --platforms=${{ matrix.target }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseSharedSwift
+      supports_swift6: true

+ 14 - 102
.github/workflows/vertexai.yml

@@ -1,11 +1,16 @@
 name: vertexai
 
+permissions:
+  contents: read
+
 on:
   pull_request:
     paths:
     - 'FirebaseAI**'
     - 'FirebaseVertexAI**'
     - '.github/workflows/vertexai.yml'
+    - '.github/workflows/common.yml'
+    - '.github/workflows/common_cocoapods.yml'
     - 'Gemfile*'
   schedule:
     # Run every day at 11pm (PST) - cron uses UTC times
@@ -17,106 +22,13 @@ concurrency:
   cancel-in-progress: true
 
 jobs:
-  spm-package-resolved:
-    runs-on: macos-14
-    outputs:
-      cache_key: ${{ steps.generate_cache_key.outputs.cache_key }}
-    env:
-      FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
-    steps:
-      - uses: actions/checkout@v4
-      - name: Generate Swift Package.resolved
-        id: swift_package_resolve
-        run: |
-          swift package resolve
-      - name: Generate cache key
-        id: generate_cache_key
-        run: |
-          cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}"
-          echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT"
-      - uses: actions/cache/save@v4
-        id: cache
-        with:
-          path: .build
-          key: ${{ steps.generate_cache_key.outputs.cache_key }}
-
-  spm-unit:
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-            target: iOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: iOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: tvOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: macOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: watchOS
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: catalyst
-          - os: macos-15
-            xcode: Xcode_16.3
-            target: visionOS
-    runs-on: ${{ matrix.os }}
-    needs: spm-package-resolved
-    env:
-      FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
-    steps:
-    - uses: actions/checkout@v4
-    - uses: actions/cache/restore@v4
-      with:
-        path: .build
-        key: ${{needs.spm-package-resolved.outputs.cache_key}}
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: Install visionOS, if needed.
-      if: matrix.target == 'visionOS'
-      run: xcodebuild -downloadPlatform visionOS
-    - name: Initialize xcodebuild
-      run: scripts/setup_spm_tests.sh
-    - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
-      with:
-        timeout_minutes: 120
-        max_attempts: 3
-        retry_on: error
-        retry_wait_seconds: 120
-        command: scripts/build.sh FirebaseVertexAIUnit ${{ matrix.target }} spm
+  spm:
+    uses: ./.github/workflows/common.yml
+    with:
+      target: FirebaseVertexAIUnit
 
-  pod-lib-lint:
-    # Don't run on private repo unless it is a PR.
-    if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request'
-    strategy:
-      matrix:
-        include:
-          - os: macos-14
-            xcode: Xcode_16.2
-            swift_version: 5.9
-            warnings:
-          - os: macos-15
-            xcode: Xcode_16.3
-            swift_version: 5.9
-            warnings:
-          - os: macos-15
-            xcode: Xcode_16.3
-            swift_version: 6.0
-            warnings:
-    runs-on: ${{ matrix.os }}
-    steps:
-    - uses: actions/checkout@v4
-    - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1
-    - name: Setup Bundler
-      run: scripts/setup_bundler.sh
-    - name: Xcode
-      run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
-    - name: Set Swift swift_version
-      run: sed -i "" "s#s.swift_version = '5.9'#s.swift_version = '${{ matrix.swift_version}}'#" FirebaseVertexAI.podspec
-    - name: Build and test
-      run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseVertexAI.podspec --platforms=${{ matrix.target }} ${{ matrix.warnings }}
+  pod_lib_lint:
+    uses: ./.github/workflows/common_cocoapods.yml
+    with:
+      product: FirebaseVertexAI
+      supports_swift6: true

+ 4 - 2
FirebaseMessaging/Tests/UnitTests/FIRMessagingRemoteNotificationsProxyTest.m

@@ -191,6 +191,8 @@
 
 #if !SWIFT_PACKAGE
 // The next 3 tests depend on a sharedApplication which is not available in the Swift PM test env.
+
+#if !TARGET_OS_OSX
 - (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod {
   XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
   IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
@@ -209,6 +211,7 @@
   [self.mockMessaging verify];
   [self waitForExpectationsWithTimeout:0.5 handler:nil];
 }
+#endif  // !TARGET_OS_OSX
 
 // This test demonstrates the difference between Firebase 10 and 11. In 10 and earlier the
 // swizzler inserts the old `didReceiveRemoteNotification` method. In 11, the new.
@@ -232,10 +235,9 @@
   [[GULAppDelegateSwizzler sharedApplication] setDelegate:appDelegate];
   [self.proxy swizzleMethodsIfPossible];
 
-  NSDictionary *notification = @{@"test" : @""};
-
   // Test application:didReceiveRemoteNotification:fetchCompletionHandler:
 #if TARGET_OS_IOS || TARGET_OS_TV
+  NSDictionary *notification = @{@"test" : @""};
   // Verify our swizzled method was called
   OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);