From 5f538ce4514295bbcfc25d45c4b8cccebb67a0b9 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 5 Jan 2026 15:43:08 -0500 Subject: [PATCH 01/31] Change the behaviour of not-in and != --- .../Integration/QueryIntegrationTests.swift | 3 ++ .../Integration/QueryToPipelineTests.swift | 33 ++++++++++++++++++- Firestore/core/src/core/pipeline_util.cc | 24 +++++++++++--- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift b/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift index e3f5b5f6888..293eb62fc60 100644 --- a/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift @@ -206,6 +206,9 @@ class QueryIntegrationTests: FSTIntegrationTestCase { } func testMultipleInOps() async throws { + try XCTSkipIf(!FSTIntegrationTestCase.isRunningAgainstEmulator(), + "Skip this test if running against production.") + let collRef = collectionRef( withDocuments: ["doc1": ["a": 1, "b": 0], "doc2": ["b": 1], diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index 8588bd1b0b9..59efc9840df 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -565,6 +565,11 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNeqNan() async throws { + try XCTSkipIf( + FSTIntegrationTestCase.isRunningAgainstEmulator(), + "Skipping test because the emulator's behavior deviates from the expected outcome." + ) + let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": Double.nan], "2": ["foo": 2, "bar": 1], @@ -579,6 +584,11 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsEqNull() async throws { + try XCTSkipIf( + FSTIntegrationTestCase.isRunningAgainstEmulator(), + "Skipping test because the emulator's behavior deviates from the expected outcome." + ) + let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": NSNull()], "2": ["foo": 2, "bar": 1], @@ -593,6 +603,11 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNeqNull() async throws { + try XCTSkipIf( + FSTIntegrationTestCase.isRunningAgainstEmulator(), + "Skipping test because the emulator's behavior deviates from the expected outcome." + ) + let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": NSNull()], "2": ["foo": 2, "bar": 1], @@ -701,6 +716,11 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNotInWith1() async throws { + try XCTSkipIf( + FSTIntegrationTestCase.isRunningAgainstEmulator(), + "Skipping test because the emulator's behavior deviates from the expected outcome." + ) + let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": 2], "2": ["foo": 2], @@ -712,7 +732,18 @@ class QueryToPipelineTests: FSTIntegrationTestCase { let pipeline = db.pipeline().create(from: query) let snapshot = try await pipeline.execute() - verifyResults(snapshot, [["foo": 3, "bar": 10]]) + switch FSTIntegrationTestCase.backendEdition() { + case .standard: + // In Standard, `NOT_IN` requires the field to exist. + // So document "2" (with no "bar" field) is filtered out. + verifyResults(snapshot, [["foo": 3, "bar": 10]]) + case .enterprise: + // In Enterprise, `NOT_IN` does not require the field to exist. + // So document "2" (with no "bar" field) is included. + verifyResults(snapshot, [["foo": 2], ["foo": 3, "bar": 10]]) + @unknown default: + XCTFail("Unknown backend edition") + } } func testSupportsOrOperator() async throws { diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 0ebd3c39b52..0acfac5c5b0 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -602,6 +602,10 @@ std::shared_ptr ToPipelineBooleanExpr(const Filter& filter) { comparison_expr = std::make_shared( func_name, std::vector>{api_field, api_constant}); + if (op == FieldFilter::Operator::NotIn || + op == FieldFilter::Operator::NotEqual) { + return comparison_expr; + } return std::make_shared( "and", std::vector>{exists_expr, comparison_expr}); @@ -703,16 +707,26 @@ std::vector> ToPipelineStages( if (!query_order_bys.empty()) { std::vector> exists_exprs; exists_exprs.reserve(query_order_bys.size()); + const auto inequality_fields = query.InequalityFilterFields(); for (const auto& core_order_by : query_order_bys) { + if (inequality_fields.find(core_order_by.field()) != + inequality_fields.end()) { + continue; + } + if (core_order_by.field().IsKeyFieldPath()) { + continue; + } exists_exprs.push_back(std::make_shared( "exists", std::vector>{ std::make_shared(core_order_by.field())})); } - if (exists_exprs.size() == 1) { - stages.push_back(std::make_shared(exists_exprs[0])); - } else { - stages.push_back(std::make_shared( - std::make_shared("and", exists_exprs))); + if (!exists_exprs.empty()) { + if (exists_exprs.size() == 1) { + stages.push_back(std::make_shared(exists_exprs[0])); + } else { + stages.push_back(std::make_shared( + std::make_shared("and", exists_exprs))); + } } } From 41369e3a76a6ef5476987329ddefa656bc05093c Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Wed, 7 Jan 2026 13:42:36 -0500 Subject: [PATCH 02/31] add environment variable --- .github/workflows/firestore.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index a3f97b5912b..c7819d263c4 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -377,7 +377,7 @@ jobs: - name: Build and test run: | - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild + BACKEND_EDITION="enterprise" scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild pod_lib_lint: needs: check From 8b1506191901de8b1d053dac04c41f7ab1dee3e2 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Thu, 8 Jan 2026 15:02:47 -0500 Subject: [PATCH 03/31] remove the flag, adding scheme for enterprise testing --- .github/workflows/firestore.yml | 30 ++++- ...e_IntegrationTests_Enterprise_iOS.xcscheme | 103 ++++++++++++++++++ ...IntegrationTests_Enterprise_macOS.xcscheme | 102 +++++++++++++++++ ..._IntegrationTests_Enterprise_tvOS.xcscheme | 102 +++++++++++++++++ scripts/build.sh | 13 +++ 5 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_iOS.xcscheme create mode 100644 Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_macOS.xcscheme create mode 100644 Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_tvOS.xcscheme diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index c7819d263c4..2892e922e25 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -377,7 +377,35 @@ jobs: - name: Build and test run: | - BACKEND_EDITION="enterprise" scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild + scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild + + xcodebuild_enterprise: + needs: check + # Either a scheduled run from public repo, or a pull request with firestore changes. + if: | + (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + (github.event_name == 'pull_request') + runs-on: macos-15 + + strategy: + matrix: + target: [iOS, macOS, tvOS] + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + + # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. + - name: Setup build + run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild + + - name: Build and test + run: | + scripts/third_party/travis/retry.sh scripts/build.sh FirestoreEnterprise ${{ matrix.target }} xcodebuild pod_lib_lint: needs: check diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_iOS.xcscheme new file mode 100644 index 00000000000..2204c0ccc65 --- /dev/null +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_iOS.xcscheme @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_macOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_macOS.xcscheme new file mode 100644 index 00000000000..41d441e5a80 --- /dev/null +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_macOS.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_tvOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_tvOS.xcscheme new file mode 100644 index 00000000000..2318375ff5e --- /dev/null +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_Enterprise_tvOS.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/build.sh b/scripts/build.sh index 171b15cb228..d3adbf309c2 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -31,6 +31,7 @@ USAGE: $0 product [platform] [method] product can be one of: Firebase Firestore + FirestoreEnterprise CombineSwift InAppMessaging Messaging @@ -365,6 +366,18 @@ case "$product-$platform-$method" in test ;; + FirestoreEnterprise-*-xcodebuild) + "${firestore_emulator}" start + trap '"${firestore_emulator}" stop' ERR EXIT + + RunXcodebuild \ + -workspace 'Firestore/Example/Firestore.xcworkspace' \ + -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ + -enableCodeCoverage YES \ + "${xcb_flags[@]}" \ + test + ;; + Firestore-macOS-cmake | Firestore-Linux-cmake) "${firestore_emulator}" start trap '"${firestore_emulator}" stop' ERR EXIT From 30f173586abb62d33a1ff2098a9a90d039cd4835 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Tue, 13 Jan 2026 17:01:30 -0500 Subject: [PATCH 04/31] remove firestore-nightly job since cmake cannot fully cover integration test as the new Swift tests introduced --- .github/workflows/firestore-nightly.yml | 95 -------------- .github/workflows/firestore.yml | 168 +++++++----------------- 2 files changed, 46 insertions(+), 217 deletions(-) delete mode 100644 .github/workflows/firestore-nightly.yml diff --git a/.github/workflows/firestore-nightly.yml b/.github/workflows/firestore-nightly.yml deleted file mode 100644 index b5698c9143e..00000000000 --- a/.github/workflows/firestore-nightly.yml +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2023 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. - -name: firestore_nightly - -on: - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -jobs: - check: - runs-on: macos-14 - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: 3.11 - - - name: Setup check - run: scripts/setup_check.sh - - - name: Run check - run: scripts/check.sh --test-only - - cmake-prod-db: - needs: check - - strategy: - matrix: - os: [macos-14] - databaseId: [(default)] - - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - MINT_PATH: ${{ github.workspace }}/mint - TARGET_DATABASE_ID: ${{ matrix.databaseId }} - USE_LATEST_CMAKE: false - - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Prepare ccache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ runner.temp }}/ccache - key: firestore-ccache-${{ matrix.databaseId }}-${{ runner.os }}-${{ github.sha }} - restore-keys: | - firestore-ccache-${{ matrix.databaseId }}-${{ runner.os }}- - - - name: Cache Mint packages - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ env.MINT_PATH }} - key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} - restore-keys: ${{ runner.os }}-mint- - - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.11' - - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore-nightly.plist.gpg \ - Firestore/Example/App/GoogleService-Info.plist "$plist_secret" - - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v2 - with: - cmake-version: '3.31.1' - - # Skipping terraform index creation because we are not allowed to download SA key json. - - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - - name: Build and test - run: | - export CCACHE_DIR=${{ runner.temp }}/ccache - export TARGET_BACKEND=nightly - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 2892e922e25..80d8ca3393f 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -160,8 +160,7 @@ jobs: export CCACHE_DIR=${{ runner.temp }}/ccache scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - - cmake-prod-db: + sanitizers-mac: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | @@ -171,15 +170,14 @@ jobs: strategy: matrix: os: [macos-14] - databaseId: [(default), test-db] + sanitizer: [asan, tsan] + + runs-on: ${{ matrix.os }} env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - MINT_PATH: ${{ github.workspace }}/mint - TARGET_DATABASE_ID: ${{ matrix.databaseId }} + SANITIZERS: ${{ matrix.sanitizer }} USE_LATEST_CMAKE: false - runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 @@ -187,59 +185,14 @@ jobs: uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 with: path: ${{ runner.temp }}/ccache - key: firestore-ccache-${{ matrix.databaseId }}-${{ runner.os }}-${{ github.sha }} + key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} restore-keys: | - firestore-ccache-${{ matrix.databaseId }}-${{ runner.os }}- - - - name: Cache Mint packages - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ env.MINT_PATH }} - key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} - restore-keys: ${{ runner.os }}-mint- + ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: '3.11' - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore.plist.gpg \ - Firestore/Example/App/GoogleService-Info.plist "$plist_secret" - - - name: Install Google Service Account key - run: | - scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore-integration.json.gpg \ - google-service-account.json "$plist_secret" - - # create composite indexes with Terraform - - name: Set up Google Cloud SDK - uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1 - - name: Setup Terraform - uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2 - - name: Terraform Init - run: | - cd Firestore - terraform init - - name: Terraform Apply - run: | - cd Firestore - - # Define a temporary file, redirect both stdout and stderr to it - output_file=$(mktemp) - if ! terraform apply -var-file=../google-service-account.json -auto-approve > "$output_file" 2>&1 ; then - cat "$output_file" - if cat "$output_file" | grep -q "index already exists"; then - echo "===================================================================================" - echo "Terraform apply failed due to index already exists; We can safely ignore this error." - echo "===================================================================================" - fi - exit 1 - fi - rm -f "$output_file" - env: - GOOGLE_APPLICATION_CREDENTIALS: ../google-service-account.json - continue-on-error: true - - name: Setup cmake uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be with: @@ -254,7 +207,7 @@ jobs: scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - sanitizers-mac: + sanitizers-ubuntu: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | @@ -263,13 +216,17 @@ jobs: strategy: matrix: - os: [macos-14] - sanitizer: [asan, tsan] + os: [ubuntu-latest] + # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. + # This could be due to Apple Clang provide additional support for synchronization + # on Apple platforms, which is what we primarily care about. + sanitizer: [asan] runs-on: ${{ matrix.os }} env: SANITIZERS: ${{ matrix.sanitizer }} + ASAN_OPTIONS: detect_leaks=0 USE_LATEST_CMAKE: false steps: @@ -301,58 +258,43 @@ jobs: scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - sanitizers-ubuntu: + xcodebuild_prod: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + (github.event_name == 'pull_request') + runs-on: macos-15 strategy: matrix: - os: [ubuntu-latest] - # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. - # This could be due to Apple Clang provide additional support for synchronization - # on Apple platforms, which is what we primarily care about. - sanitizer: [asan] - - runs-on: ${{ matrix.os }} + target: [iOS, macOS, tvOS] + scheme: [Firestore, FirestoreEnterprise] env: - SANITIZERS: ${{ matrix.sanitizer }} - ASAN_OPTIONS: detect_leaks=0 - USE_LATEST_CMAKE: false + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Prepare ccache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ runner.temp }}/ccache - key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} - restore-keys: | - ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.11' + - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - with: - cmake-version: '3.31.1' + - name: Install Secret GoogleService-Info.plist + run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore.plist.gpg \ + Firestore/Example/App/GoogleService-Info.plist "$plist_secret" - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Build and test - run: | - export CCACHE_DIR=${{ runner.temp }}/ccache - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. + - name: Setup build + run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild + - name: Build and test + run: | + scripts/third_party/travis/retry.sh scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild - xcodebuild: + xcodebuild_emulator: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | @@ -363,6 +305,8 @@ jobs: strategy: matrix: target: [iOS, macOS, tvOS] + # Skip the FirestoreEnterprise test against emulator since emulator is under development. + scheme: [Firestore] steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 @@ -373,39 +317,12 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup build + # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - name: Build and test run: | - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ matrix.target }} xcodebuild - - xcodebuild_enterprise: - needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request') - runs-on: macos-15 - - strategy: - matrix: - target: [iOS, macOS, tvOS] - - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - - - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/build.sh FirestoreEnterprise ${{ matrix.target }} xcodebuild + scripts/third_party/travis/retry.sh scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild pod_lib_lint: needs: check @@ -574,7 +491,14 @@ jobs: check-required-tests: runs-on: ubuntu-latest name: Check all required Firestore tests results - needs: [cmake, cmake-prod-db, xcodebuild, spm-source, spm-binary] + needs: + - cmake + - xcodebuild_prod + - spm-source + - spm-binary + - sanitizers-mac + - sanitizers-ubuntu + - pod_lib_lint steps: - name: Check test matrix if: needs.*.result == 'failure' From 1449f086e7c0c32a70914a7b085ba05f833a0041 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Tue, 13 Jan 2026 18:18:38 -0500 Subject: [PATCH 05/31] re-enable some tests --- .github/workflows/firestore.yml | 31 ++++++++-------- .../Integration/API/FIRAggregateTests.mm | 21 ++++++----- .../Tests/Integration/API/FIRQueryTests.mm | 6 ---- .../AggregationIntegrationTests.swift | 10 ------ .../Tests/Integration/PipelineTests.swift | 35 ------------------- .../Integration/QueryToPipelineTests.swift | 5 --- 6 files changed, 27 insertions(+), 81 deletions(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 80d8ca3393f..84bdeeea2f4 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -453,22 +453,21 @@ jobs: platforms: iOS buildonly_platforms: iOS - # TODO: Re-enable either in or after #11706. - # spm-source-cron: - # # Don't run on private repo. - # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - # runs-on: macos-14 - # strategy: - # matrix: - # target: [tvOS, macOS, catalyst] - # env: - # FIREBASE_SOURCE_FIRESTORE: 1 - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # - name: Initialize xcodebuild - # run: scripts/setup_spm_tests.sh - # - name: Build Test - Binary - # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + spm-source-cron: + # Don't run on private repo. + if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + runs-on: macos-14 + strategy: + matrix: + target: [tvOS, macOS, catalyst] + env: + FIREBASE_SOURCE_FIRESTORE: 1 + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Initialize xcodebuild + run: scripts/setup_spm_tests.sh + - name: Build Test - Binary + run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly spm-binary-cron: # Don't run on private repo. diff --git a/Firestore/Example/Tests/Integration/API/FIRAggregateTests.mm b/Firestore/Example/Tests/Integration/API/FIRAggregateTests.mm index 9899875e052..24664eb6510 100644 --- a/Firestore/Example/Tests/Integration/API/FIRAggregateTests.mm +++ b/Firestore/Example/Tests/Integration/API/FIRAggregateTests.mm @@ -680,9 +680,6 @@ - (void)testPerformsAggregationsOnNestedMapValues { } - (void)testPerformsSumThatOverflowsMaxLong { - XCTSkipIf([FSTIntegrationTestCase isRunningAgainstEmulator], - @"Skipping test because the emulator's behavior deviates from the expected outcome."); - FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{ @"a" : @{ @"author" : @"authorA", @@ -708,6 +705,10 @@ - (void)testPerformsSumThatOverflowsMaxLong { break; } case FSTBackendEditionEnterprise: { + XCTSkipIf( + [FSTIntegrationTestCase isRunningAgainstEmulator], + @"Skipping test because the emulator's behavior deviates from the expected outcome."); + XCTestExpectation* expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; __block NSError* anError = nil; [query aggregationWithSource:FIRAggregateSourceServer @@ -748,9 +749,6 @@ - (void)testPerformsSumThatCanOverflowLongValuesDuringAccumulation { } - (void)testPerformsSumThatIsNegative { - XCTSkipIf([FSTIntegrationTestCase isRunningAgainstEmulator], - @"Skipping test because the emulator's behavior deviates from the expected outcome."); - FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{ @"a" : @{ @"author" : @"authorA", @@ -781,6 +779,10 @@ - (void)testPerformsSumThatIsNegative { break; } case FSTBackendEditionEnterprise: { + XCTSkipIf( + [FSTIntegrationTestCase isRunningAgainstEmulator], + @"Skipping test because the emulator's behavior deviates from the expected outcome."); + XCTestExpectation* expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; __block NSError* anError = nil; [query aggregationWithSource:FIRAggregateSourceServer @@ -873,9 +875,6 @@ - (void)testPerformsSumThatIsValidButCouldOverflowDuringAggregation { } - (void)testPerformsSumOverResultSetOfZeroDocuments { - XCTSkipIf([FSTIntegrationTestCase isRunningAgainstEmulator], - @"Skipping test because the emulator's behavior deviates from the expected outcome."); - FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{ @"a" : @{ @"author" : @"authorA", @@ -910,6 +909,10 @@ - (void)testPerformsSumOverResultSetOfZeroDocuments { break; } case FSTBackendEditionEnterprise: { + XCTSkipIf( + [FSTIntegrationTestCase isRunningAgainstEmulator], + @"Skipping test because the emulator's behavior deviates from the expected outcome."); + XCTAssertEqual([snapshot valueForAggregateField:sumOfPages], [NSNull null]); break; } diff --git a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm index b6393c8e6aa..8ee797f93e1 100644 --- a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm +++ b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm @@ -570,9 +570,6 @@ - (void)testSDKUsesNotEqualFiltersSameAsServer { } - (void)testQueriesCanUseArrayContainsFilters { - XCTSkipIf([FSTIntegrationTestCase isRunningAgainstEmulator], - @"Skipping test because the emulator's behavior deviates from the expected outcome."); - NSDictionary *testDocs = @{ @"a" : @{@"array" : @[ @42 ]}, @"b" : @{@"array" : @[ @"a", @42, @"c" ]}, @@ -615,9 +612,6 @@ - (void)testQueriesCanUseArrayContainsFilters { } - (void)testQueriesCanUseInFilters { - XCTSkipIf([FSTIntegrationTestCase isRunningAgainstEmulator], - @"Skipping test because the emulator's behavior deviates from the expected outcome."); - NSDictionary *testDocs = @{ @"a" : @{@"zip" : @98101}, @"b" : @{@"zip" : @91102}, diff --git a/Firestore/Swift/Tests/Integration/AggregationIntegrationTests.swift b/Firestore/Swift/Tests/Integration/AggregationIntegrationTests.swift index babee43e94d..080ea3be03e 100644 --- a/Firestore/Swift/Tests/Integration/AggregationIntegrationTests.swift +++ b/Firestore/Swift/Tests/Integration/AggregationIntegrationTests.swift @@ -295,11 +295,6 @@ class AggregationIntegrationTests: FSTIntegrationTestCase { } func testPerformsAggregateOverResultSetOfZeroDocuments() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collection = collectionRef() try await collection.addDocument(data: ["pages": 100]) try await collection.addDocument(data: ["pages": 50]) @@ -328,11 +323,6 @@ class AggregationIntegrationTests: FSTIntegrationTestCase { } func testPerformsAggregateOverResultSetOfZeroFields() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collection = collectionRef() try await collection.addDocument(data: ["pages": 100]) try await collection.addDocument(data: ["pages": 50]) diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 0d80737ad73..15e64dff7dd 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -2068,11 +2068,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testLike() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Emulator does not support this function." - ) - let collRef = collectionRef(withDocuments: bookDocs) let db = collRef.firestore @@ -2091,11 +2086,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testRegexContains() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Emulator does not support this function." - ) - let collRef = collectionRef(withDocuments: bookDocs) let db = collRef.firestore @@ -2109,11 +2099,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testRegexMatches() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Emulator does not support this function." - ) - let collRef = collectionRef(withDocuments: bookDocs) let db = collRef.firestore @@ -2394,11 +2379,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testExpOverflow() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "doc1": ["value": 1000], ]) @@ -2504,11 +2484,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testChecks() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: bookDocs) let db = collRef.firestore @@ -3249,11 +3224,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testTimestampTruncWorks() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Emulator does not support this function." - ) - let db = firestore() let randomCol = collectionRef() try await randomCol.document("dummyDoc").setData(["field": "value"]) @@ -3716,11 +3686,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { } func testTypeWorks() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "doc1": [ "a": 1, diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index 8588bd1b0b9..c1d2440bf43 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -543,11 +543,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsEqNan() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": Double.nan], "2": ["foo": 2, "bar": 1], From 59f6ced4d83fc7e4425a933716c02e05c6fa277a Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Wed, 14 Jan 2026 16:24:08 -0500 Subject: [PATCH 06/31] correct code logic --- .../Integration/QueryToPipelineTests.swift | 20 ------------------- Firestore/core/src/core/pipeline_util.cc | 18 +---------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index 59efc9840df..a408f708019 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -565,11 +565,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNeqNan() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": Double.nan], "2": ["foo": 2, "bar": 1], @@ -584,11 +579,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsEqNull() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": NSNull()], "2": ["foo": 2, "bar": 1], @@ -603,11 +593,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNeqNull() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": NSNull()], "2": ["foo": 2, "bar": 1], @@ -716,11 +701,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { } func testSupportsNotInWith1() async throws { - try XCTSkipIf( - FSTIntegrationTestCase.isRunningAgainstEmulator(), - "Skipping test because the emulator's behavior deviates from the expected outcome." - ) - let collRef = collectionRef(withDocuments: [ "1": ["foo": 1, "bar": 2], "2": ["foo": 2], diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 0acfac5c5b0..5c58886c929 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -703,31 +703,15 @@ std::vector> ToPipelineStages( } // 3. OrderBy Existence Checks - const auto& query_order_bys = query.normalized_order_bys(); + const auto& query_order_bys = query.explicit_order_bys(); if (!query_order_bys.empty()) { std::vector> exists_exprs; exists_exprs.reserve(query_order_bys.size()); - const auto inequality_fields = query.InequalityFilterFields(); for (const auto& core_order_by : query_order_bys) { - if (inequality_fields.find(core_order_by.field()) != - inequality_fields.end()) { - continue; - } - if (core_order_by.field().IsKeyFieldPath()) { - continue; - } exists_exprs.push_back(std::make_shared( "exists", std::vector>{ std::make_shared(core_order_by.field())})); } - if (!exists_exprs.empty()) { - if (exists_exprs.size() == 1) { - stages.push_back(std::make_shared(exists_exprs[0])); - } else { - stages.push_back(std::make_shared( - std::make_shared("and", exists_exprs))); - } - } } // 4. Orderings, Cursors, Limit From 909eacc331bef43aa274102533c6a230d202e528 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Thu, 15 Jan 2026 00:48:43 -0500 Subject: [PATCH 07/31] fix failing spec tests --- Firestore/core/src/api/realtime_pipeline.cc | 18 ++++++++++++++++++ Firestore/core/src/api/realtime_pipeline.h | 3 +++ Firestore/core/src/core/pipeline_util.cc | 6 ++++++ 3 files changed, 27 insertions(+) diff --git a/Firestore/core/src/api/realtime_pipeline.cc b/Firestore/core/src/api/realtime_pipeline.cc index 743c64aa2b1..21155a28ca1 100644 --- a/Firestore/core/src/api/realtime_pipeline.cc +++ b/Firestore/core/src/api/realtime_pipeline.cc @@ -52,6 +52,24 @@ RealtimePipeline& RealtimePipeline::operator=(const RealtimePipeline& other) { return *this; } +RealtimePipeline::RealtimePipeline(RealtimePipeline&& other) noexcept + : stages_(std::move(other.stages_)), + rewritten_stages_(std::move(other.rewritten_stages_)), + serializer_(std::move(other.serializer_)), + listen_options_(std::move(other.listen_options_)) { +} + +RealtimePipeline& RealtimePipeline::operator=( + RealtimePipeline&& other) noexcept { + if (this != &other) { + stages_ = std::move(other.stages_); + rewritten_stages_ = std::move(other.rewritten_stages_); + serializer_ = std::move(other.serializer_); + listen_options_ = std::move(other.listen_options_); + } + return *this; +} + RealtimePipeline RealtimePipeline::AddingStage( std::shared_ptr stage) { auto copy = std::vector>(this->stages_); diff --git a/Firestore/core/src/api/realtime_pipeline.h b/Firestore/core/src/api/realtime_pipeline.h index dab00a1c335..c74c395c075 100644 --- a/Firestore/core/src/api/realtime_pipeline.h +++ b/Firestore/core/src/api/realtime_pipeline.h @@ -41,6 +41,9 @@ class RealtimePipeline { RealtimePipeline(const RealtimePipeline& other); RealtimePipeline& operator=(const RealtimePipeline& other); + RealtimePipeline(RealtimePipeline&& other) noexcept; + RealtimePipeline& operator=(RealtimePipeline&& other) noexcept; + RealtimePipeline AddingStage(std::shared_ptr stage); const std::vector>& stages() const; diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 5c58886c929..f609767c995 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -712,6 +712,12 @@ std::vector> ToPipelineStages( "exists", std::vector>{ std::make_shared(core_order_by.field())})); } + if (exists_exprs.size() == 1) { + stages.push_back(std::make_shared(exists_exprs[0])); + } else { + stages.push_back(std::make_shared( + std::make_shared("and", exists_exprs))); + } } // 4. Orderings, Cursors, Limit From d72381c9a3e3b442093df170523815eb518f961d Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Thu, 15 Jan 2026 12:07:51 -0500 Subject: [PATCH 08/31] change config for tvOS --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index d3adbf309c2..8c73a011a1a 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -190,7 +190,7 @@ macos_flags=( -destination 'platform=OS X,arch=x86_64' ) tvos_flags=( - -destination 'platform=tvOS Simulator,name=Apple TV' + -destination 'platform=tvOS Simulator,OS=latest' ) visionos_flags=( # As of Aug 15, 2025, the default OS "latest" was failing as it matched both From 6a7a185f81b88d4c483b9d7a04830b0040a030de Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Thu, 15 Jan 2026 14:42:06 -0500 Subject: [PATCH 09/31] revert tvOS changes --- scripts/build.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 8c73a011a1a..1b5dfbe2aa9 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -121,7 +121,13 @@ 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 + if command -v xcbeautify &> /dev/null; then + xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging) + else + echo "xcbeautify not found, using raw xcodebuild output." + xcbeautify_cmd=(cat) + fi local result=0 NSUnbufferedIO=YES xcodebuild "$@" 2>&1 | tee "$log_filename" | \ @@ -190,7 +196,7 @@ macos_flags=( -destination 'platform=OS X,arch=x86_64' ) tvos_flags=( - -destination 'platform=tvOS Simulator,OS=latest' + -destination 'platform=tvOS Simulator,name=Apple TV' ) visionos_flags=( # As of Aug 15, 2025, the default OS "latest" was failing as it matched both From c66338a9feb65910ce23e647ad4a7d9c85f5fe93 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 16 Jan 2026 11:49:43 -0500 Subject: [PATCH 10/31] fix bugs --- .../Integration/QueryToPipelineTests.swift | 73 +++++++++++++++++++ Firestore/core/src/core/pipeline_util.cc | 4 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index a408f708019..d61784060d7 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -750,4 +750,77 @@ class QueryToPipelineTests: FSTIntegrationTestCase { enforceOrder: true ) } + +// private func verifyIDs(_ snapshot: Pipeline.Snapshot, +// _ expected: [String], +// enforceOrder: Bool = false, +// file: StaticString = #file, +// line: UInt = #line) { +// let results = snapshot.results.map { $0.ref!.documentID } +// if enforceOrder { +// XCTAssertEqual(results, expected, "Result IDs do not match or are not in order.", +// file: file, line: line) +// } else { +// XCTAssertEqual(Set(results), Set(expected), "Result ID sets do not match.", +// file: file, line: line) +// } +// } +// +// func testNotInRemovesExistenceFilter() async throws { +// let collRef = collectionRef(withDocuments: [ +// "doc1": ["field": 2], +// "doc2": ["field": 1], +// "doc3": [:], +// ]) +// let db = collRef.firestore +// +// let query = collRef.whereField("field", notIn: [1]) +// let pipeline = db.pipeline().create(from: query) +// let snapshot = try await pipeline.execute() +// +// verifyIDs(snapshot, ["doc1", "doc3"]) +// } +// +// func testNotEqualRemovesExistenceFilter() async throws { +// let collRef = collectionRef(withDocuments: [ +// "doc1": ["field": 2], +// "doc2": ["field": 1], +// "doc3": [:], +// ]) +// let db = collRef.firestore +// +// let query = collRef.whereField("field", isNotEqualTo: 1) +// let pipeline = db.pipeline().create(from: query) +// let snapshot = try await pipeline.execute() +// +// verifyIDs(snapshot, ["doc1", "doc3"]) +// } +// +// func testInequalityMaintainsExistenceFilter() async throws { +// let collRef = collectionRef(withDocuments: [ +// "doc1": ["field": 0], +// "doc2": [:], +// ]) +// let db = collRef.firestore +// +// let query = collRef.whereField("field", isLessThan: 1) +// let pipeline = db.pipeline().create(from: query) +// let snapshot = try await pipeline.execute() +// +// verifyIDs(snapshot, ["doc1"]) +// } +// +// func testExplicitOrderMaintainsExistenceFilter() async throws { +// let collRef = collectionRef(withDocuments: [ +// "doc1": ["field": 1], +// "doc2": [:], +// ]) +// let db = collRef.firestore +// +// let query = collRef.order(by: "field") +// let pipeline = db.pipeline().create(from: query) +// let snapshot = try await pipeline.execute() +// +// verifyIDs(snapshot, ["doc1"]) +// } } diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 5c58886c929..be8064a9ab2 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -755,7 +755,9 @@ std::vector> ToPipelineStages( stages.push_back(std::make_shared(api_orderings)); } } else { - stages.push_back(std::make_shared(api_orderings)); + if (!api_orderings.empty()) { + stages.push_back(std::make_shared(api_orderings)); + } } return stages; From 25e9896cead338b86f0f77f353f0209b92368de5 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:22:38 -0500 Subject: [PATCH 11/31] Update sdk.firestore.yml --- .github/workflows/sdk.firestore.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index ae199046bfc..a4a27a5de9f 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -286,13 +286,26 @@ jobs: - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Install simulators in case they are missing. + if: matrix.target != 'macOS' + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 5 + retry_wait_seconds: 120 + command: sudo xcodebuild -downloadPlatform ${{ matrix.target }} + # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 60 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild xcodebuild_emulator: needs: check From e37e1f55c9477a137744d0860572e6194872db93 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:26:51 -0500 Subject: [PATCH 12/31] Add retries to xcodebuild_emulator --- .github/workflows/sdk.firestore.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index a4a27a5de9f..cc22028489a 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -329,13 +329,26 @@ jobs: - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Install simulators in case they are missing. + if: matrix.target != 'macOS' + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 5 + retry_wait_seconds: 120 + command: sudo xcodebuild -downloadPlatform ${{ matrix.target }} + - name: Setup build # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. - run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild + run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - name: Build and test - run: | - scripts/third_party/travis/retry.sh scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 60 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild pod_lib_lint: needs: check From 2b04ce49b08609ad29ceda42ebf13ce9b797e800 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:28:09 -0500 Subject: [PATCH 13/31] isolate xcodebuild jobs --- .github/workflows/sdk.firestore.yml | 672 ++++++++++++++-------------- 1 file changed, 336 insertions(+), 336 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index cc22028489a..71328c55fb5 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -110,152 +110,152 @@ jobs: - name: Run check run: scripts/check.sh --test-only - cmake: - needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - strategy: - matrix: - os: [macos-14, ubuntu-latest] - - env: - MINT_PATH: ${{ github.workspace }}/mint - USE_LATEST_CMAKE: false - - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Prepare ccache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ runner.temp }}/ccache - key: firestore-ccache-${{ runner.os }}-${{ github.sha }} - restore-keys: | - firestore-ccache-${{ runner.os }}- - - - name: Cache Mint packages - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ env.MINT_PATH }} - key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} - restore-keys: ${{ runner.os }}-mint- - - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.11' - - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - with: - cmake-version: '3.31.1' - - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - - name: Build and test - run: | - export CCACHE_DIR=${{ runner.temp }}/ccache - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - - sanitizers-mac: - needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - - strategy: - matrix: - os: [macos-14] - sanitizer: [asan, tsan] - - runs-on: ${{ matrix.os }} - - env: - SANITIZERS: ${{ matrix.sanitizer }} - USE_LATEST_CMAKE: false - - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Prepare ccache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ runner.temp }}/ccache - key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} - restore-keys: | - ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- - - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.11' - - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - with: - cmake-version: '3.31.1' - - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - - name: Build and test - run: | - export CCACHE_DIR=${{ runner.temp }}/ccache - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - - - sanitizers-ubuntu: - needs: check - # Either a scheduled run from public repo, or a pull request with firestore changes. - if: | - (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - - strategy: - matrix: - os: [ubuntu-latest] - # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. - # This could be due to Apple Clang provide additional support for synchronization - # on Apple platforms, which is what we primarily care about. - sanitizer: [asan] - - runs-on: ${{ matrix.os }} - - env: - SANITIZERS: ${{ matrix.sanitizer }} - ASAN_OPTIONS: detect_leaks=0 - USE_LATEST_CMAKE: false - - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Prepare ccache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: ${{ runner.temp }}/ccache - key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} - restore-keys: | - ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- - - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: '3.11' - - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - with: - cmake-version: '3.31.1' - - - name: Setup build - run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - - name: Build and test - run: | - export CCACHE_DIR=${{ runner.temp }}/ccache - scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + # cmake: + # needs: check + # # Either a scheduled run from public repo, or a pull request with firestore changes. + # if: | + # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + # strategy: + # matrix: + # os: [macos-14, ubuntu-latest] + + # env: + # MINT_PATH: ${{ github.workspace }}/mint + # USE_LATEST_CMAKE: false + + # runs-on: ${{ matrix.os }} + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + # - name: Prepare ccache + # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + # with: + # path: ${{ runner.temp }}/ccache + # key: firestore-ccache-${{ runner.os }}-${{ github.sha }} + # restore-keys: | + # firestore-ccache-${{ runner.os }}- + + # - name: Cache Mint packages + # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + # with: + # path: ${{ env.MINT_PATH }} + # key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} + # restore-keys: ${{ runner.os }}-mint- + + # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + # with: + # python-version: '3.11' + + # - name: Setup cmake + # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + # with: + # cmake-version: '3.31.1' + + # - name: Setup build + # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + # - name: Build and test + # run: | + # export CCACHE_DIR=${{ runner.temp }}/ccache + # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + + # sanitizers-mac: + # needs: check + # # Either a scheduled run from public repo, or a pull request with firestore changes. + # if: | + # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + + # strategy: + # matrix: + # os: [macos-14] + # sanitizer: [asan, tsan] + + # runs-on: ${{ matrix.os }} + + # env: + # SANITIZERS: ${{ matrix.sanitizer }} + # USE_LATEST_CMAKE: false + + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + # - name: Prepare ccache + # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + # with: + # path: ${{ runner.temp }}/ccache + # key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} + # restore-keys: | + # ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- + + # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + # with: + # python-version: '3.11' + + # - name: Setup cmake + # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + # with: + # cmake-version: '3.31.1' + + # - name: Setup build + # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + # - name: Build and test + # run: | + # export CCACHE_DIR=${{ runner.temp }}/ccache + # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + + + # sanitizers-ubuntu: + # needs: check + # # Either a scheduled run from public repo, or a pull request with firestore changes. + # if: | + # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + + # strategy: + # matrix: + # os: [ubuntu-latest] + # # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. + # # This could be due to Apple Clang provide additional support for synchronization + # # on Apple platforms, which is what we primarily care about. + # sanitizer: [asan] + + # runs-on: ${{ matrix.os }} + + # env: + # SANITIZERS: ${{ matrix.sanitizer }} + # ASAN_OPTIONS: detect_leaks=0 + # USE_LATEST_CMAKE: false + + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + # - name: Prepare ccache + # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + # with: + # path: ${{ runner.temp }}/ccache + # key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} + # restore-keys: | + # ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- + + # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + # with: + # python-version: '3.11' + + # - name: Setup cmake + # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + # with: + # cmake-version: '3.31.1' + + # - name: Setup build + # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + # - name: Build and test + # run: | + # export CCACHE_DIR=${{ runner.temp }}/ccache + # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake xcodebuild_prod: @@ -350,194 +350,194 @@ jobs: retry_wait_seconds: 120 command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild - pod_lib_lint: - needs: check - strategy: - matrix: - product: ['FirebaseFirestoreInternal', 'FirebaseFirestore'] - uses: ./.github/workflows/_cocoapods.yml - with: - product: ${{ matrix.product }} - platforms: iOS - allow_warnings: true - analyze: false # TODO(#9565, b/227461966): Remove when absl is fixed. - timeout_minutes: 30 - - # `pod lib lint` takes a long time so only run the other platforms and static frameworks build in the cron. - pod-lib-lint-cron: - needs: check - if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - strategy: - matrix: - podspec: [ - 'FirebaseFirestoreInternal.podspec', - 'FirebaseFirestore.podspec', - ] - platforms: [ - 'macos', - 'tvos', - 'ios', - ] - flags: [ - '--use-static-frameworks', - '', - ] - os: [macos-15, macos-14] - # Skip matrix cells covered by pod-lib-lint job. - exclude: - - os: macos-15 - platforms: 'ios' - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - 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: Pod lib lint - # TODO(#9565, b/227461966): Remove --no-analyze when absl is fixed. - run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }}\ - ${{ matrix.flags }} \ - --platforms=${{ matrix.platforms }} \ - --allow-warnings \ - --no-analyze - - spm-package-resolved: - runs-on: macos-14 - env: - FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - FIREBASE_SOURCE_FIRESTORE: 1 - outputs: - cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Xcode - 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 - - 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@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - id: cache - with: - path: .build - key: ${{ steps.generate_cache_key.outputs.cache_key }} - - spm-source: - needs: [check, spm-package-resolved] - # Either a scheduled run from public repo, or a pull request with firestore changes. - 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.4 - target: iOS - - os: macos-15 - xcode: Xcode_16.4 - target: tvOS - - os: macos-15 - xcode: Xcode_16.4 - target: macOS - - os: macos-15 - xcode: Xcode_16.4 - target: catalyst - - os: macos-15 - xcode: Xcode_16.4 - target: visionOS - runs-on: ${{ matrix.os }} - env: - FIREBASE_SOURCE_FIRESTORE: 1 - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: iOS Build Test - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - spm-binary: - uses: ./.github/workflows/_spm.yml - with: - target: FirebaseFirestore - platforms: iOS - buildonly_platforms: iOS - - spm-source-cron: - # Don't run on private repo. - if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - runs-on: macos-14 - strategy: - matrix: - target: [tvOS, macOS, catalyst] - env: - FIREBASE_SOURCE_FIRESTORE: 1 - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: Build Test - Binary - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - spm-binary-cron: - # Don't run on private repo. - if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - runs-on: macos-15 - strategy: - matrix: - target: [tvOS, macOS, catalyst] - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Initialize xcodebuild - run: scripts/setup_spm_tests.sh - - name: Build Test - Binary - run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - # A job that fails if any required job in the test matrix fails, - # to be used as a required check for merging. - check-required-tests: - runs-on: ubuntu-latest - name: Check all required Firestore tests results - needs: - - cmake - - xcodebuild_prod - - spm-source - - spm-binary - - sanitizers-mac - - sanitizers-ubuntu - - pod_lib_lint - steps: - - name: Check test matrix - if: needs.*.result == 'failure' - run: exit 1 - - # TODO: Disable until FirebaseUI is updated to accept Firebase 9 and - # quickstart is updated to accept Firebase UI 12 - # quickstart: - # uses: ./.github/workflows/_quickstart.yml + # pod_lib_lint: + # needs: check + # strategy: + # matrix: + # product: ['FirebaseFirestoreInternal', 'FirebaseFirestore'] + # uses: ./.github/workflows/_cocoapods.yml + # with: + # product: ${{ matrix.product }} + # platforms: iOS + # allow_warnings: true + # analyze: false # TODO(#9565, b/227461966): Remove when absl is fixed. + # timeout_minutes: 30 + + # # `pod lib lint` takes a long time so only run the other platforms and static frameworks build in the cron. + # pod-lib-lint-cron: + # needs: check + # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + # strategy: + # matrix: + # podspec: [ + # 'FirebaseFirestoreInternal.podspec', + # 'FirebaseFirestore.podspec', + # ] + # platforms: [ + # 'macos', + # 'tvos', + # 'ios', + # ] + # flags: [ + # '--use-static-frameworks', + # '', + # ] + # os: [macos-15, macos-14] + # # Skip matrix cells covered by pod-lib-lint job. + # exclude: + # - os: macos-15 + # platforms: 'ios' + # runs-on: ${{ matrix.os }} + + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + # - 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: Pod lib lint + # # TODO(#9565, b/227461966): Remove --no-analyze when absl is fixed. + # run: | + # scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }}\ + # ${{ matrix.flags }} \ + # --platforms=${{ matrix.platforms }} \ + # --allow-warnings \ + # --no-analyze + + # spm-package-resolved: + # runs-on: macos-14 + # env: + # FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 + # FIREBASE_SOURCE_FIRESTORE: 1 + # outputs: + # cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + # - name: Xcode + # 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 + # - 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@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + # id: cache + # with: + # path: .build + # key: ${{ steps.generate_cache_key.outputs.cache_key }} + + # spm-source: + # needs: [check, spm-package-resolved] + # # Either a scheduled run from public repo, or a pull request with firestore changes. + # 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.4 + # target: iOS + # - os: macos-15 + # xcode: Xcode_16.4 + # target: tvOS + # - os: macos-15 + # xcode: Xcode_16.4 + # target: macOS + # - os: macos-15 + # xcode: Xcode_16.4 + # target: catalyst + # - os: macos-15 + # xcode: Xcode_16.4 + # target: visionOS + # runs-on: ${{ matrix.os }} + # env: + # FIREBASE_SOURCE_FIRESTORE: 1 + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + # - name: Xcode + # run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + # - name: Initialize xcodebuild + # run: scripts/setup_spm_tests.sh + # - name: iOS Build Test + # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + # spm-binary: + # uses: ./.github/workflows/_spm.yml # with: - # product: Firestore - # setup_command: scripts/setup_quickstart.sh firestore - # plist_src_path: scripts/gha-encrypted/qs-firestore.plist.gpg - # plist_dst_path: quickstart-ios/firestore/GoogleService-Info.plist - # run_tests: false - # secrets: - # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + # target: FirebaseFirestore + # platforms: iOS + # buildonly_platforms: iOS + + # spm-source-cron: + # # Don't run on private repo. + # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + # runs-on: macos-14 + # strategy: + # matrix: + # target: [tvOS, macOS, catalyst] + # env: + # FIREBASE_SOURCE_FIRESTORE: 1 + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + # - name: Initialize xcodebuild + # run: scripts/setup_spm_tests.sh + # - name: Build Test - Binary + # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + # spm-binary-cron: + # # Don't run on private repo. + # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + # runs-on: macos-15 + # strategy: + # matrix: + # target: [tvOS, macOS, catalyst] + # steps: + # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + # - name: Xcode + # run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + # - name: Initialize xcodebuild + # run: scripts/setup_spm_tests.sh + # - name: Build Test - Binary + # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + # # A job that fails if any required job in the test matrix fails, + # # to be used as a required check for merging. + # check-required-tests: + # runs-on: ubuntu-latest + # name: Check all required Firestore tests results + # needs: + # - cmake + # - xcodebuild_prod + # - spm-source + # - spm-binary + # - sanitizers-mac + # - sanitizers-ubuntu + # - pod_lib_lint + # steps: + # - name: Check test matrix + # if: needs.*.result == 'failure' + # run: exit 1 + + # # TODO: Disable until FirebaseUI is updated to accept Firebase 9 and + # # quickstart is updated to accept Firebase UI 12 + # # quickstart: + # # uses: ./.github/workflows/_quickstart.yml + # # with: + # # product: Firestore + # # setup_command: scripts/setup_quickstart.sh firestore + # # plist_src_path: scripts/gha-encrypted/qs-firestore.plist.gpg + # # plist_dst_path: quickstart-ios/firestore/GoogleService-Info.plist + # # run_tests: false + # # secrets: + # # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} From 28b24e8f7346d7a215dc9dbf1bd5922cc38b9606 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:33:28 -0500 Subject: [PATCH 14/31] remove trailing whitespace --- .github/workflows/sdk.firestore.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index 71328c55fb5..3124a28f49e 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -294,7 +294,7 @@ jobs: max_attempts: 5 retry_wait_seconds: 120 command: sudo xcodebuild -downloadPlatform ${{ matrix.target }} - + # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild @@ -340,7 +340,7 @@ jobs: - name: Setup build # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. - run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild + run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - name: Build and test uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 From f1abfe5c3de2d651f18788702471aec0d28555e4 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:29:29 -0500 Subject: [PATCH 15/31] Apply suggestion from @ncooke3 --- .github/workflows/sdk.firestore.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index 3124a28f49e..d1f5433fbac 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -345,7 +345,7 @@ jobs: - name: Build and test uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 60 + timeout_minutes: 120 max_attempts: 3 retry_wait_seconds: 120 command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild From c9e642c025480645f334688557a9705258ac4510 Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:08:25 -0500 Subject: [PATCH 16/31] Update build.sh --- scripts/build.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 1b5dfbe2aa9..f8069e5cf12 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -373,9 +373,6 @@ case "$product-$platform-$method" in ;; FirestoreEnterprise-*-xcodebuild) - "${firestore_emulator}" start - trap '"${firestore_emulator}" stop' ERR EXIT - RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ From ed027677723793718a076e0b4f39e241903b2f93 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 19 Jan 2026 16:03:33 -0500 Subject: [PATCH 17/31] fix impl error --- .../Tests/Integration/QueryToPipelineTests.swift | 12 +++++++++++- Firestore/core/src/core/pipeline_util.cc | 13 +++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index d61784060d7..5d125cfad7c 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -37,7 +37,17 @@ class QueryToPipelineTests: FSTIntegrationTestCase { file: StaticString = #file, line: UInt = #line) { let results = snapshot.results.map { $0.data as! [String: AnyHashable?] } - XCTAssertEqual(results.count, expected.count, "Result count mismatch.", file: file, line: line) + print("results: \(results)") + print("expected: \(expected.map(\.debugDescription).joined(separator: "\n"))") + print("results.count: \(results.count), expected.count: \(expected.count)") + guard results.count == expected.count else { + XCTFail( + "Result count mismatch. Got \(results.count), expected \(expected.count)", + file: file, + line: line + ) + return + } if enforceOrder { for i in 0 ..< expected.count { diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index be8064a9ab2..2b1d70b4bfe 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -703,11 +703,11 @@ std::vector> ToPipelineStages( } // 3. OrderBy Existence Checks - const auto& query_order_bys = query.explicit_order_bys(); - if (!query_order_bys.empty()) { + const auto& query_explicit_order_bys = query.explicit_order_bys(); + if (!query_explicit_order_bys.empty()) { std::vector> exists_exprs; - exists_exprs.reserve(query_order_bys.size()); - for (const auto& core_order_by : query_order_bys) { + exists_exprs.reserve(query_explicit_order_bys.size()); + for (const auto& core_order_by : query.explicit_order_bys()) { exists_exprs.push_back(std::make_shared( "exists", std::vector>{ std::make_shared(core_order_by.field())})); @@ -716,8 +716,9 @@ std::vector> ToPipelineStages( // 4. Orderings, Cursors, Limit std::vector api_orderings; - api_orderings.reserve(query_order_bys.size()); - for (const auto& core_order_by : query_order_bys) { + const auto& query_normalized_order_bys = query.normalized_order_bys(); + api_orderings.reserve(query_normalized_order_bys.size()); + for (const auto& core_order_by : query_normalized_order_bys) { api_orderings.emplace_back( std::make_shared(core_order_by.field()), core_order_by.direction() == Direction::Ascending From 3900a4504f6448c7a3a57646d4eb8738266a3b4f Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 19 Jan 2026 16:59:29 -0500 Subject: [PATCH 18/31] fix impl --- .../Integration/QueryToPipelineTests.swift | 147 +++++++++--------- Firestore/core/src/core/pipeline_util.cc | 11 ++ 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index 5d125cfad7c..fd946669333 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -37,9 +37,6 @@ class QueryToPipelineTests: FSTIntegrationTestCase { file: StaticString = #file, line: UInt = #line) { let results = snapshot.results.map { $0.data as! [String: AnyHashable?] } - print("results: \(results)") - print("expected: \(expected.map(\.debugDescription).joined(separator: "\n"))") - print("results.count: \(results.count), expected.count: \(expected.count)") guard results.count == expected.count else { XCTFail( "Result count mismatch. Got \(results.count), expected \(expected.count)", @@ -761,76 +758,76 @@ class QueryToPipelineTests: FSTIntegrationTestCase { ) } -// private func verifyIDs(_ snapshot: Pipeline.Snapshot, -// _ expected: [String], -// enforceOrder: Bool = false, -// file: StaticString = #file, -// line: UInt = #line) { -// let results = snapshot.results.map { $0.ref!.documentID } -// if enforceOrder { -// XCTAssertEqual(results, expected, "Result IDs do not match or are not in order.", -// file: file, line: line) -// } else { -// XCTAssertEqual(Set(results), Set(expected), "Result ID sets do not match.", -// file: file, line: line) -// } -// } -// -// func testNotInRemovesExistenceFilter() async throws { -// let collRef = collectionRef(withDocuments: [ -// "doc1": ["field": 2], -// "doc2": ["field": 1], -// "doc3": [:], -// ]) -// let db = collRef.firestore -// -// let query = collRef.whereField("field", notIn: [1]) -// let pipeline = db.pipeline().create(from: query) -// let snapshot = try await pipeline.execute() -// -// verifyIDs(snapshot, ["doc1", "doc3"]) -// } -// -// func testNotEqualRemovesExistenceFilter() async throws { -// let collRef = collectionRef(withDocuments: [ -// "doc1": ["field": 2], -// "doc2": ["field": 1], -// "doc3": [:], -// ]) -// let db = collRef.firestore -// -// let query = collRef.whereField("field", isNotEqualTo: 1) -// let pipeline = db.pipeline().create(from: query) -// let snapshot = try await pipeline.execute() -// -// verifyIDs(snapshot, ["doc1", "doc3"]) -// } -// -// func testInequalityMaintainsExistenceFilter() async throws { -// let collRef = collectionRef(withDocuments: [ -// "doc1": ["field": 0], -// "doc2": [:], -// ]) -// let db = collRef.firestore -// -// let query = collRef.whereField("field", isLessThan: 1) -// let pipeline = db.pipeline().create(from: query) -// let snapshot = try await pipeline.execute() -// -// verifyIDs(snapshot, ["doc1"]) -// } -// -// func testExplicitOrderMaintainsExistenceFilter() async throws { -// let collRef = collectionRef(withDocuments: [ -// "doc1": ["field": 1], -// "doc2": [:], -// ]) -// let db = collRef.firestore -// -// let query = collRef.order(by: "field") -// let pipeline = db.pipeline().create(from: query) -// let snapshot = try await pipeline.execute() -// -// verifyIDs(snapshot, ["doc1"]) -// } + private func verifyIDs(_ snapshot: Pipeline.Snapshot, + _ expected: [String], + enforceOrder: Bool = false, + file: StaticString = #file, + line: UInt = #line) { + let results = snapshot.results.map { $0.ref!.documentID } + if enforceOrder { + XCTAssertEqual(results, expected, "Result IDs do not match or are not in order.", + file: file, line: line) + } else { + XCTAssertEqual(Set(results), Set(expected), "Result ID sets do not match.", + file: file, line: line) + } + } + + func testNotInRemovesExistenceFilter() async throws { + let collRef = collectionRef(withDocuments: [ + "doc1": ["field": 2], + "doc2": ["field": 1], + "doc3": [:], + ]) + let db = collRef.firestore + + let query = collRef.whereField("field", notIn: [1]) + let pipeline = db.pipeline().create(from: query) + let snapshot = try await pipeline.execute() + + verifyIDs(snapshot, ["doc1", "doc3"]) + } + + func testNotEqualRemovesExistenceFilter() async throws { + let collRef = collectionRef(withDocuments: [ + "doc1": ["field": 2], + "doc2": ["field": 1], + "doc3": [:], + ]) + let db = collRef.firestore + + let query = collRef.whereField("field", isNotEqualTo: 1) + let pipeline = db.pipeline().create(from: query) + let snapshot = try await pipeline.execute() + + verifyIDs(snapshot, ["doc1", "doc3"]) + } + + func testInequalityMaintainsExistenceFilter() async throws { + let collRef = collectionRef(withDocuments: [ + "doc1": ["field": 0], + "doc2": [:], + ]) + let db = collRef.firestore + + let query = collRef.whereField("field", isLessThan: 1) + let pipeline = db.pipeline().create(from: query) + let snapshot = try await pipeline.execute() + + verifyIDs(snapshot, ["doc1"]) + } + + func testExplicitOrderMaintainsExistenceFilter() async throws { + let collRef = collectionRef(withDocuments: [ + "doc1": ["field": 1], + "doc2": [:], + ]) + let db = collRef.firestore + + let query = collRef.order(by: "field") + let pipeline = db.pipeline().create(from: query) + let snapshot = try await pipeline.execute() + + verifyIDs(snapshot, ["doc1"]) + } } diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 2b1d70b4bfe..c400a654182 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -712,6 +712,17 @@ std::vector> ToPipelineStages( "exists", std::vector>{ std::make_shared(core_order_by.field())})); } + + if (!exists_exprs.empty()) { + std::shared_ptr final_exists_expr; + if (exists_exprs.size() == 1) { + final_exists_expr = exists_exprs[0]; + } else { + final_exists_expr = + std::make_shared("and", exists_exprs); + } + stages.push_back(std::make_shared(final_exists_expr)); + } } // 4. Orderings, Cursors, Limit From 04550106a771bc32fd077dc9936b7d92b042931a Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:52:07 -0500 Subject: [PATCH 19/31] Update build.sh - add job number --- scripts/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build.sh b/scripts/build.sh index f8069e5cf12..6c25d0c0aa2 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -378,6 +378,7 @@ case "$product-$platform-$method" in -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ -enableCodeCoverage YES \ "${xcb_flags[@]}" \ + -jobs 4 test ;; From eaff497d3fd525e1f7e7cb3e6812fd7a8fb4401f Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 20 Jan 2026 10:52:11 -0500 Subject: [PATCH 20/31] Update build.sh use build-for-testing --- scripts/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 6c25d0c0aa2..630abfc19e6 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -378,8 +378,8 @@ case "$product-$platform-$method" in -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ -enableCodeCoverage YES \ "${xcb_flags[@]}" \ - -jobs 4 - test + -jobs 4 \ + build-for-testing ;; Firestore-macOS-cmake | Firestore-Linux-cmake) From cd09ae2b0c5c8e57b0cdc4315ef54107519ae111 Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:45:45 -0500 Subject: [PATCH 21/31] Update build.sh - add test after building --- scripts/build.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/build.sh b/scripts/build.sh index 630abfc19e6..b4d0510903b 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -380,6 +380,15 @@ case "$product-$platform-$method" in "${xcb_flags[@]}" \ -jobs 4 \ build-for-testing + + sleep 10 + + RunXcodebuild \ + -workspace 'Firestore/Example/Firestore.xcworkspace' \ + -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ + -enableCodeCoverage YES \ + "${xcb_flags[@]}" \ + test-without-building ;; Firestore-macOS-cmake | Firestore-Linux-cmake) From fe9d317453548689eede1f4a5f61cecc3f7ac9ab Mon Sep 17 00:00:00 2001 From: cherylEnkidu <96084918+cherylEnkidu@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:51:40 -0500 Subject: [PATCH 22/31] Update build.sh - remove whitespace --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index b4d0510903b..20eb2149007 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -382,7 +382,7 @@ case "$product-$platform-$method" in build-for-testing sleep 10 - + RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ From 16d07b65fe6b6943ca27b7c1cde24d80f550471f Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 23 Jan 2026 15:34:38 -0500 Subject: [PATCH 23/31] improve the workflow for CI running --- .github/workflows/sdk.firestore.yml | 24 ++++++++++++++++------ scripts/build.sh | 31 +++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index d1f5433fbac..1ae9445b8db 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -258,7 +258,7 @@ jobs: # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - xcodebuild_prod: + xcodetest_prod: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | @@ -299,15 +299,21 @@ jobs: - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - - name: Build and test + - name: Build + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 60 + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + + - name: Test uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 60 max_attempts: 3 retry_wait_seconds: 120 - command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodetest - xcodebuild_emulator: + xcodetest_emulator: needs: check # Either a scheduled run from public repo, or a pull request with firestore changes. if: | @@ -342,13 +348,19 @@ jobs: # 'FirestoreEnterprise' is used as product name for `build.sh` to select the enterprise build variant. `install_prereqs.sh` does not require this distinction, so 'Firestore' is used. run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild - - name: Build and test + - name: Build + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 120 + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + + - name: Test uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 120 max_attempts: 3 retry_wait_seconds: 120 - command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodebuild + command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodetest # pod_lib_lint: # needs: check diff --git a/scripts/build.sh b/scripts/build.sh index 20eb2149007..3fcb83a3c8f 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -372,17 +372,44 @@ case "$product-$platform-$method" in test ;; + Firestore-*-xcodebuild) + "${firestore_emulator}" start + trap '"${firestore_emulator}" stop' ERR EXIT + + RunXcodebuild \ + -workspace 'Firestore/Example/Firestore.xcworkspace' \ + -scheme "Firestore_IntegrationTests_$platform" \ + -enableCodeCoverage YES \ + "${xcb_flags[@]}" \ + # Memory intensive, so we limit jobs + -jobs 4 \ + build-for-testing + ;; + + Firestore-*-xcodetest) + RunXcodebuild \ + -workspace 'Firestore/Example/Firestore.xcworkspace' \ + -scheme "Firestore_IntegrationTests_$platform" \ + -enableCodeCoverage YES \ + "${xcb_flags[@]}" \ + test-without-building + ;; + FirestoreEnterprise-*-xcodebuild) + "${firestore_emulator}" start + trap '"${firestore_emulator}" stop' ERR EXIT + RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ -enableCodeCoverage YES \ "${xcb_flags[@]}" \ + # Memory intensive, so we limit jobs -jobs 4 \ build-for-testing + ;; - sleep 10 - + FirestoreEnterprise-*-xcodetest) RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ From 99ec422227dfba39847fed2ce483b9be169fd4c4 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 23 Jan 2026 15:35:53 -0500 Subject: [PATCH 24/31] Revert "isolate xcodebuild jobs" This reverts commit 2b04ce49b08609ad29ceda42ebf13ce9b797e800. --- .github/workflows/sdk.firestore.yml | 672 ++++++++++++++-------------- 1 file changed, 336 insertions(+), 336 deletions(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index 1ae9445b8db..70306140fa6 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -110,152 +110,152 @@ jobs: - name: Run check run: scripts/check.sh --test-only - # cmake: - # needs: check - # # Either a scheduled run from public repo, or a pull request with firestore changes. - # if: | - # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - # strategy: - # matrix: - # os: [macos-14, ubuntu-latest] - - # env: - # MINT_PATH: ${{ github.workspace }}/mint - # USE_LATEST_CMAKE: false - - # runs-on: ${{ matrix.os }} - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - # - name: Prepare ccache - # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - # with: - # path: ${{ runner.temp }}/ccache - # key: firestore-ccache-${{ runner.os }}-${{ github.sha }} - # restore-keys: | - # firestore-ccache-${{ runner.os }}- - - # - name: Cache Mint packages - # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - # with: - # path: ${{ env.MINT_PATH }} - # key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} - # restore-keys: ${{ runner.os }}-mint- - - # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - # with: - # python-version: '3.11' - - # - name: Setup cmake - # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - # with: - # cmake-version: '3.31.1' - - # - name: Setup build - # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - # - name: Build and test - # run: | - # export CCACHE_DIR=${{ runner.temp }}/ccache - # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - - # sanitizers-mac: - # needs: check - # # Either a scheduled run from public repo, or a pull request with firestore changes. - # if: | - # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - - # strategy: - # matrix: - # os: [macos-14] - # sanitizer: [asan, tsan] - - # runs-on: ${{ matrix.os }} - - # env: - # SANITIZERS: ${{ matrix.sanitizer }} - # USE_LATEST_CMAKE: false - - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - # - name: Prepare ccache - # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - # with: - # path: ${{ runner.temp }}/ccache - # key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} - # restore-keys: | - # ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- - - # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - # with: - # python-version: '3.11' - - # - name: Setup cmake - # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - # with: - # cmake-version: '3.31.1' - - # - name: Setup build - # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - # - name: Build and test - # run: | - # export CCACHE_DIR=${{ runner.temp }}/ccache - # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake - - - # sanitizers-ubuntu: - # needs: check - # # Either a scheduled run from public repo, or a pull request with firestore changes. - # if: | - # (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || - # (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') - - # strategy: - # matrix: - # os: [ubuntu-latest] - # # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. - # # This could be due to Apple Clang provide additional support for synchronization - # # on Apple platforms, which is what we primarily care about. - # sanitizer: [asan] - - # runs-on: ${{ matrix.os }} - - # env: - # SANITIZERS: ${{ matrix.sanitizer }} - # ASAN_OPTIONS: detect_leaks=0 - # USE_LATEST_CMAKE: false - - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - # - name: Prepare ccache - # uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - # with: - # path: ${{ runner.temp }}/ccache - # key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} - # restore-keys: | - # ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- - - # - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - # with: - # python-version: '3.11' - - # - name: Setup cmake - # uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be - # with: - # cmake-version: '3.31.1' - - # - name: Setup build - # run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake - - # - name: Build and test - # run: | - # export CCACHE_DIR=${{ runner.temp }}/ccache - # scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + cmake: + needs: check + # Either a scheduled run from public repo, or a pull request with firestore changes. + if: | + (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + strategy: + matrix: + os: [macos-14, ubuntu-latest] + + env: + MINT_PATH: ${{ github.workspace }}/mint + USE_LATEST_CMAKE: false + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Prepare ccache + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + with: + path: ${{ runner.temp }}/ccache + key: firestore-ccache-${{ runner.os }}-${{ github.sha }} + restore-keys: | + firestore-ccache-${{ runner.os }}- + + - name: Cache Mint packages + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + with: + path: ${{ env.MINT_PATH }} + key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} + restore-keys: ${{ runner.os }}-mint- + + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + with: + python-version: '3.11' + + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + with: + cmake-version: '3.31.1' + + - name: Setup build + run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + - name: Build and test + run: | + export CCACHE_DIR=${{ runner.temp }}/ccache + scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + + sanitizers-mac: + needs: check + # Either a scheduled run from public repo, or a pull request with firestore changes. + if: | + (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + + strategy: + matrix: + os: [macos-14] + sanitizer: [asan, tsan] + + runs-on: ${{ matrix.os }} + + env: + SANITIZERS: ${{ matrix.sanitizer }} + USE_LATEST_CMAKE: false + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Prepare ccache + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + with: + path: ${{ runner.temp }}/ccache + key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} + restore-keys: | + ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- + + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + with: + python-version: '3.11' + + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + with: + cmake-version: '3.31.1' + + - name: Setup build + run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + - name: Build and test + run: | + export CCACHE_DIR=${{ runner.temp }}/ccache + scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake + + + sanitizers-ubuntu: + needs: check + # Either a scheduled run from public repo, or a pull request with firestore changes. + if: | + (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || + (github.event_name == 'pull_request' && needs.changes.outputs.changed == 'true') + + strategy: + matrix: + os: [ubuntu-latest] + # Excluding TSAN on ubuntu because of the warnings it generates around schedule.cc. + # This could be due to Apple Clang provide additional support for synchronization + # on Apple platforms, which is what we primarily care about. + sanitizer: [asan] + + runs-on: ${{ matrix.os }} + + env: + SANITIZERS: ${{ matrix.sanitizer }} + ASAN_OPTIONS: detect_leaks=0 + USE_LATEST_CMAKE: false + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Prepare ccache + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + with: + path: ${{ runner.temp }}/ccache + key: ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}-${{ github.sha }} + restore-keys: | + ${{ matrix.sanitizer }}-firestore-ccache-${{ runner.os }}- + + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + with: + python-version: '3.11' + + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be + with: + cmake-version: '3.31.1' + + - name: Setup build + run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake + + - name: Build and test + run: | + export CCACHE_DIR=${{ runner.temp }}/ccache + scripts/third_party/travis/retry.sh scripts/build.sh Firestore ${{ runner.os }} cmake xcodetest_prod: @@ -362,194 +362,194 @@ jobs: retry_wait_seconds: 120 command: scripts/build.sh ${{ matrix.scheme }} ${{ matrix.target }} xcodetest - # pod_lib_lint: - # needs: check - # strategy: - # matrix: - # product: ['FirebaseFirestoreInternal', 'FirebaseFirestore'] - # uses: ./.github/workflows/_cocoapods.yml - # with: - # product: ${{ matrix.product }} - # platforms: iOS - # allow_warnings: true - # analyze: false # TODO(#9565, b/227461966): Remove when absl is fixed. - # timeout_minutes: 30 - - # # `pod lib lint` takes a long time so only run the other platforms and static frameworks build in the cron. - # pod-lib-lint-cron: - # needs: check - # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - # strategy: - # matrix: - # podspec: [ - # 'FirebaseFirestoreInternal.podspec', - # 'FirebaseFirestore.podspec', - # ] - # platforms: [ - # 'macos', - # 'tvos', - # 'ios', - # ] - # flags: [ - # '--use-static-frameworks', - # '', - # ] - # os: [macos-15, macos-14] - # # Skip matrix cells covered by pod-lib-lint job. - # exclude: - # - os: macos-15 - # platforms: 'ios' - # runs-on: ${{ matrix.os }} - - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - # - 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: Pod lib lint - # # TODO(#9565, b/227461966): Remove --no-analyze when absl is fixed. - # run: | - # scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }}\ - # ${{ matrix.flags }} \ - # --platforms=${{ matrix.platforms }} \ - # --allow-warnings \ - # --no-analyze - - # spm-package-resolved: - # runs-on: macos-14 - # env: - # FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - # FIREBASE_SOURCE_FIRESTORE: 1 - # outputs: - # cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # - name: Xcode - # 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 - # - 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@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - # id: cache - # with: - # path: .build - # key: ${{ steps.generate_cache_key.outputs.cache_key }} - - # spm-source: - # needs: [check, spm-package-resolved] - # # Either a scheduled run from public repo, or a pull request with firestore changes. - # 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.4 - # target: iOS - # - os: macos-15 - # xcode: Xcode_16.4 - # target: tvOS - # - os: macos-15 - # xcode: Xcode_16.4 - # target: macOS - # - os: macos-15 - # xcode: Xcode_16.4 - # target: catalyst - # - os: macos-15 - # xcode: Xcode_16.4 - # target: visionOS - # runs-on: ${{ matrix.os }} - # env: - # FIREBASE_SOURCE_FIRESTORE: 1 - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # - name: Xcode - # run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - # - name: Initialize xcodebuild - # run: scripts/setup_spm_tests.sh - # - name: iOS Build Test - # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - # spm-binary: - # uses: ./.github/workflows/_spm.yml + pod_lib_lint: + needs: check + strategy: + matrix: + product: ['FirebaseFirestoreInternal', 'FirebaseFirestore'] + uses: ./.github/workflows/_cocoapods.yml + with: + product: ${{ matrix.product }} + platforms: iOS + allow_warnings: true + analyze: false # TODO(#9565, b/227461966): Remove when absl is fixed. + timeout_minutes: 30 + + # `pod lib lint` takes a long time so only run the other platforms and static frameworks build in the cron. + pod-lib-lint-cron: + needs: check + if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + strategy: + matrix: + podspec: [ + 'FirebaseFirestoreInternal.podspec', + 'FirebaseFirestore.podspec', + ] + platforms: [ + 'macos', + 'tvos', + 'ios', + ] + flags: [ + '--use-static-frameworks', + '', + ] + os: [macos-15, macos-14] + # Skip matrix cells covered by pod-lib-lint job. + exclude: + - os: macos-15 + platforms: 'ios' + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - 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: Pod lib lint + # TODO(#9565, b/227461966): Remove --no-analyze when absl is fixed. + run: | + scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }}\ + ${{ matrix.flags }} \ + --platforms=${{ matrix.platforms }} \ + --allow-warnings \ + --no-analyze + + spm-package-resolved: + runs-on: macos-14 + env: + FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 + FIREBASE_SOURCE_FIRESTORE: 1 + outputs: + cache_key: ${{ steps.generate_cache_key.outputs.cache_key }} + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Xcode + 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 + - 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@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + id: cache + with: + path: .build + key: ${{ steps.generate_cache_key.outputs.cache_key }} + + spm-source: + needs: [check, spm-package-resolved] + # Either a scheduled run from public repo, or a pull request with firestore changes. + 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.4 + target: iOS + - os: macos-15 + xcode: Xcode_16.4 + target: tvOS + - os: macos-15 + xcode: Xcode_16.4 + target: macOS + - os: macos-15 + xcode: Xcode_16.4 + target: catalyst + - os: macos-15 + xcode: Xcode_16.4 + target: visionOS + runs-on: ${{ matrix.os }} + env: + FIREBASE_SOURCE_FIRESTORE: 1 + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + - name: Initialize xcodebuild + run: scripts/setup_spm_tests.sh + - name: iOS Build Test + run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + spm-binary: + uses: ./.github/workflows/_spm.yml + with: + target: FirebaseFirestore + platforms: iOS + buildonly_platforms: iOS + + spm-source-cron: + # Don't run on private repo. + if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + runs-on: macos-14 + strategy: + matrix: + target: [tvOS, macOS, catalyst] + env: + FIREBASE_SOURCE_FIRESTORE: 1 + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Initialize xcodebuild + run: scripts/setup_spm_tests.sh + - name: Build Test - Binary + run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + spm-binary-cron: + # Don't run on private repo. + if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + runs-on: macos-15 + strategy: + matrix: + target: [tvOS, macOS, catalyst] + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Initialize xcodebuild + run: scripts/setup_spm_tests.sh + - name: Build Test - Binary + run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly + + # A job that fails if any required job in the test matrix fails, + # to be used as a required check for merging. + check-required-tests: + runs-on: ubuntu-latest + name: Check all required Firestore tests results + needs: + - cmake + - xcodebuild_prod + - spm-source + - spm-binary + - sanitizers-mac + - sanitizers-ubuntu + - pod_lib_lint + steps: + - name: Check test matrix + if: needs.*.result == 'failure' + run: exit 1 + + # TODO: Disable until FirebaseUI is updated to accept Firebase 9 and + # quickstart is updated to accept Firebase UI 12 + # quickstart: + # uses: ./.github/workflows/_quickstart.yml # with: - # target: FirebaseFirestore - # platforms: iOS - # buildonly_platforms: iOS - - # spm-source-cron: - # # Don't run on private repo. - # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - # runs-on: macos-14 - # strategy: - # matrix: - # target: [tvOS, macOS, catalyst] - # env: - # FIREBASE_SOURCE_FIRESTORE: 1 - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # - name: Initialize xcodebuild - # run: scripts/setup_spm_tests.sh - # - name: Build Test - Binary - # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - # spm-binary-cron: - # # Don't run on private repo. - # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' - # runs-on: macos-15 - # strategy: - # matrix: - # target: [tvOS, macOS, catalyst] - # steps: - # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - # - name: Xcode - # run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - # - name: Initialize xcodebuild - # run: scripts/setup_spm_tests.sh - # - name: Build Test - Binary - # run: scripts/third_party/travis/retry.sh ./scripts/build.sh FirebaseFirestore ${{ matrix.target }} spmbuildonly - - # # A job that fails if any required job in the test matrix fails, - # # to be used as a required check for merging. - # check-required-tests: - # runs-on: ubuntu-latest - # name: Check all required Firestore tests results - # needs: - # - cmake - # - xcodebuild_prod - # - spm-source - # - spm-binary - # - sanitizers-mac - # - sanitizers-ubuntu - # - pod_lib_lint - # steps: - # - name: Check test matrix - # if: needs.*.result == 'failure' - # run: exit 1 - - # # TODO: Disable until FirebaseUI is updated to accept Firebase 9 and - # # quickstart is updated to accept Firebase UI 12 - # # quickstart: - # # uses: ./.github/workflows/_quickstart.yml - # # with: - # # product: Firestore - # # setup_command: scripts/setup_quickstart.sh firestore - # # plist_src_path: scripts/gha-encrypted/qs-firestore.plist.gpg - # # plist_dst_path: quickstart-ios/firestore/GoogleService-Info.plist - # # run_tests: false - # # secrets: - # # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + # product: Firestore + # setup_command: scripts/setup_quickstart.sh firestore + # plist_src_path: scripts/gha-encrypted/qs-firestore.plist.gpg + # plist_dst_path: quickstart-ios/firestore/GoogleService-Info.plist + # run_tests: false + # secrets: + # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} From 8f80cc54080df3b2c5083b6888efa9786bab8167 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 23 Jan 2026 16:04:39 -0500 Subject: [PATCH 25/31] fix the wrong name --- .github/workflows/sdk.firestore.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index 70306140fa6..2b06009570a 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -530,7 +530,8 @@ jobs: name: Check all required Firestore tests results needs: - cmake - - xcodebuild_prod + - xcodetest_emulator + - xcodetest_prod - spm-source - spm-binary - sanitizers-mac From ae61807040f3f9756975e6865097177844ab2b36 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Fri, 23 Jan 2026 16:15:49 -0500 Subject: [PATCH 26/31] fix the wrong flag --- scripts/build.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 3fcb83a3c8f..362050816e9 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -379,7 +379,6 @@ case "$product-$platform-$method" in RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_$platform" \ - -enableCodeCoverage YES \ "${xcb_flags[@]}" \ # Memory intensive, so we limit jobs -jobs 4 \ @@ -402,7 +401,6 @@ case "$product-$platform-$method" in RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ - -enableCodeCoverage YES \ "${xcb_flags[@]}" \ # Memory intensive, so we limit jobs -jobs 4 \ From c123b4614fcbfdd341712f37f1c28632f4bd74cd Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 2 Feb 2026 14:59:58 -0500 Subject: [PATCH 27/31] change build script --- scripts/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 18d229deb2a..f1483c7ccce 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -383,11 +383,11 @@ case "$product-$platform-$method" in "${firestore_emulator}" start trap '"${firestore_emulator}" stop' ERR EXIT + # Memory intensive, so we limit jobs RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_$platform" \ "${xcb_flags[@]}" \ - # Memory intensive, so we limit jobs -jobs 4 \ build-for-testing ;; @@ -405,11 +405,11 @@ case "$product-$platform-$method" in "${firestore_emulator}" start trap '"${firestore_emulator}" stop' ERR EXIT + # Memory intensive, so we limit jobs RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_Enterprise_$platform" \ "${xcb_flags[@]}" \ - # Memory intensive, so we limit jobs -jobs 4 \ build-for-testing ;; From 9eff0ad7ae8560ffce86f34b84ba412660a6e112 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 2 Feb 2026 15:49:18 -0500 Subject: [PATCH 28/31] revert unnecessary change --- Firestore/core/src/core/pipeline_util.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index c400a654182..53950a4384d 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -767,9 +767,7 @@ std::vector> ToPipelineStages( stages.push_back(std::make_shared(api_orderings)); } } else { - if (!api_orderings.empty()) { - stages.push_back(std::make_shared(api_orderings)); - } + stages.push_back(std::make_shared(api_orderings)); } return stages; From fda6bd2089ee61ddd6ade60f82b26356d1743abf Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Mon, 2 Feb 2026 16:18:54 -0500 Subject: [PATCH 29/31] address feedbacks --- .../Integration/QueryToPipelineTests.swift | 13 +------------ Firestore/core/src/core/pipeline_util.cc | 18 ++++++++---------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift index 8b80080d144..95400a682ad 100644 --- a/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryToPipelineTests.swift @@ -714,18 +714,7 @@ class QueryToPipelineTests: FSTIntegrationTestCase { let pipeline = db.pipeline().create(from: query) let snapshot = try await pipeline.execute() - switch FSTIntegrationTestCase.backendEdition() { - case .standard: - // In Standard, `NOT_IN` requires the field to exist. - // So document "2" (with no "bar" field) is filtered out. - verifyResults(snapshot, [["foo": 3, "bar": 10]]) - case .enterprise: - // In Enterprise, `NOT_IN` does not require the field to exist. - // So document "2" (with no "bar" field) is included. - verifyResults(snapshot, [["foo": 2], ["foo": 3, "bar": 10]]) - @unknown default: - XCTFail("Unknown backend edition") - } + verifyResults(snapshot, [["foo": 2], ["foo": 3, "bar": 10]]) } func testSupportsOrOperator() async throws { diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 53950a4384d..35f345c6f9e 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -707,22 +707,20 @@ std::vector> ToPipelineStages( if (!query_explicit_order_bys.empty()) { std::vector> exists_exprs; exists_exprs.reserve(query_explicit_order_bys.size()); - for (const auto& core_order_by : query.explicit_order_bys()) { + for (const auto& core_order_by : query_explicit_order_bys) { exists_exprs.push_back(std::make_shared( "exists", std::vector>{ std::make_shared(core_order_by.field())})); } - if (!exists_exprs.empty()) { - std::shared_ptr final_exists_expr; - if (exists_exprs.size() == 1) { - final_exists_expr = exists_exprs[0]; - } else { - final_exists_expr = - std::make_shared("and", exists_exprs); - } - stages.push_back(std::make_shared(final_exists_expr)); + std::shared_ptr final_exists_expr; + if (exists_exprs.size() == 1) { + final_exists_expr = exists_exprs[0]; + } else { + final_exists_expr = + std::make_shared("and", exists_exprs); } + stages.push_back(std::make_shared(final_exists_expr)); } // 4. Orderings, Cursors, Limit From b354c930e7a06b07fc279e6783e9a5db8b6e8e97 Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Tue, 3 Feb 2026 15:21:56 -0500 Subject: [PATCH 30/31] remove macos version no longer support --- .github/workflows/sdk.firestore.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk.firestore.yml b/.github/workflows/sdk.firestore.yml index 2d3bb63d442..885b25b9dd4 100644 --- a/.github/workflows/sdk.firestore.yml +++ b/.github/workflows/sdk.firestore.yml @@ -394,7 +394,7 @@ jobs: '--use-static-frameworks', '', ] - os: [macos-15, macos-14] + os: [macos-15] # Skip matrix cells covered by pod-lib-lint job. exclude: - os: macos-15 From 99abf1480c1420f3ace6103c7ff0f19acb22908c Mon Sep 17 00:00:00 2001 From: cherylEnkidu Date: Wed, 4 Feb 2026 15:00:02 -0500 Subject: [PATCH 31/31] move emulator start process --- scripts/build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index f1483c7ccce..261c18c2157 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -380,10 +380,7 @@ case "$product-$platform-$method" in ;; Firestore-*-xcodebuild) - "${firestore_emulator}" start - trap '"${firestore_emulator}" stop' ERR EXIT - - # Memory intensive, so we limit jobs + # Memory intensive, so we limit jobs. RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_$platform" \ @@ -393,6 +390,9 @@ case "$product-$platform-$method" in ;; Firestore-*-xcodetest) + "${firestore_emulator}" start + trap '"${firestore_emulator}" stop' ERR EXIT + RunXcodebuild \ -workspace 'Firestore/Example/Firestore.xcworkspace' \ -scheme "Firestore_IntegrationTests_$platform" \