Repository: vercel/next.js
Pull request: [ci] Merge Cache Components and deploy tests manifests when running CC deploy tests

Part of https://linear.app/vercel/issue/NAR-719/

We previously only supported a single manifest for filtering tests. However, Cache Component deploy tests have two manifests. Now we merge manifests append-only. 

## Test plan

- [x] https://github.com/vercel/next.js/pull/88821 adds a failed deploy test to a test suite also listed in the CC manifest. Tests from CC and deploy manifest are skipped
   ```console
   $ NEXT_EXTERNAL_TESTS_FILTERS="test/deploy-tests-manifest.json,test/cache-components-tests-manifest.json" NEXT_TEST_MODE=deploy node run-tests.js -c 1 --retries 0 test/e2e/app-dir/searchparams-reuse-loading/searchparams-reuse-loading.test.ts
    ○ skipped should re-use loading from "full" prefetch for param-full URL when navigating to param-less route
    ○ skipped should re-use loading from "full" prefetch for param-less URL when navigating to param-full route
    ○ skipped should re-use loading from "full" prefetch for param-full URL when navigating to param-full route
    when aliasing is skipped
      ✕ should work for not found pages
      ✕ should work for route handlers
      ✕ should work for navigating to pages dir
    Without Middleware
      ✕ should correctly return different RSC data for full prefetches with different searchParam values
    With Middleware
      ○ skipped should correctly return different RSC data for full prefetches with different searchParam values
   ```

Changed files:
filename: .github/workflows/build_and_test.yml
patch: @@ -722,7 +722,7 @@ jobs:
       afterBuild: |
         export __NEXT_CACHE_COMPONENTS=true
         export __NEXT_EXPERIMENTAL_DEBUG_CHANNEL=true
-        export NEXT_EXTERNAL_TESTS_FILTERS="test/cache-components-tests-manifest.json"
+        export NEXT_EXTERNAL_TESTS_FILTERS="test/deploy-tests-manifest.json,test/cache-components-tests-manifest.json"
         export NEXT_E2E_TEST_TIMEOUT=240000
         export GH_PR_NUMBER=${{ github.event.pull_request && github.event.pull_request.number || '' }}
         node scripts/test-new-tests.mjs \

filename: test/get-test-filter.js
patch: @@ -1,10 +1,50 @@
 const path = require('path')
 const minimatch = require('minimatch')
 
+function getManifest() {
+  const nextExternalTestFilters = process.env.NEXT_EXTERNAL_TESTS_FILTERS
+  if (!nextExternalTestFilters) {
+    return null
+  }
+
+  return nextExternalTestFilters
+    .split(',')
+    .reduce((mergedManifest, manifestPath) => {
+      const manifest = require(path.resolve(manifestPath))
+      if (!mergedManifest) {
+        return manifest
+      }
+
+      if (manifest.version === 2) {
+        for (const suite in manifest.suites) {
+          if (mergedManifest.suites[suite]) {
+            const mergedSuite = mergedManifest.suites[suite]
+            const currentSuite = manifest.suites[suite]
+            mergedSuite.failed = [
+              ...(mergedSuite.failed || []),
+              ...(currentSuite.failed || []),
+            ]
+            mergedSuite.flakey = [
+              ...(mergedSuite.flakey || []),
+              ...(currentSuite.flakey || []),
+            ]
+          } else {
+            mergedManifest.suites[suite] = manifest.suites[suite]
+          }
+        }
+        mergedManifest.rules.include.push(...(manifest.rules.include || []))
+        mergedManifest.rules.exclude.push(...(manifest.rules.exclude || []))
+        return mergedManifest
+      }
+
+      throw new Error(
+        `Merging manifests is only supported for version 2: ${manifestPath}`
+      )
+    }, null)
+}
+
 function getTestFilter() {
-  const manifest = process.env.NEXT_EXTERNAL_TESTS_FILTERS
-    ? require(path.resolve(process.env.NEXT_EXTERNAL_TESTS_FILTERS))
-    : null
+  const manifest = getManifest()
   if (!manifest) return null
 
   console.log(