diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55082d8c8d0..4ad1bdc17bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,10 +37,10 @@ jobs: run_build_artifacts: ${{ steps.manifest.outputs.run_build_artifacts }} run_checks_fast: ${{ steps.manifest.outputs.run_checks_fast }} checks_fast_core_matrix: ${{ steps.manifest.outputs.checks_fast_core_matrix }} - checks_fast_extensions_matrix: ${{ steps.manifest.outputs.checks_fast_extensions_matrix }} + checks_node_extensions_matrix: ${{ steps.manifest.outputs.checks_node_extensions_matrix }} run_checks: ${{ steps.manifest.outputs.run_checks }} checks_matrix: ${{ steps.manifest.outputs.checks_matrix }} - checks_node_test_matrix: ${{ steps.manifest.outputs.checks_node_test_matrix }} + checks_node_core_test_matrix: ${{ steps.manifest.outputs.checks_node_core_test_matrix }} run_extension_fast: ${{ steps.manifest.outputs.run_extension_fast }} extension_fast_matrix: ${{ steps.manifest.outputs.extension_fast_matrix }} run_check: ${{ steps.manifest.outputs.run_check }} @@ -215,7 +215,7 @@ jobs: ] : [], ), - checks_fast_extensions_matrix: extensionShardMatrix, + checks_node_extensions_matrix: extensionShardMatrix, run_checks: runNode, checks_matrix: createMatrix( runNode @@ -235,7 +235,7 @@ jobs: ] : [], ), - checks_node_test_matrix: createMatrix( + checks_node_core_test_matrix: createMatrix( runNode ? createNodeTestShards().map((shard) => ({ check_name: shard.checkName, @@ -484,7 +484,7 @@ jobs: ;; esac - checks-fast-extensions-shard: + checks-node-extensions-shard: name: ${{ matrix.check_name }} needs: [preflight] if: needs.preflight.outputs.run_checks_fast == 'true' @@ -492,7 +492,7 @@ jobs: timeout-minutes: 60 strategy: fail-fast: false - matrix: ${{ fromJson(needs.preflight.outputs.checks_fast_extensions_matrix) }} + matrix: ${{ fromJson(needs.preflight.outputs.checks_node_extensions_matrix) }} steps: - name: Checkout uses: actions/checkout@v6 @@ -511,16 +511,16 @@ jobs: OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }} run: pnpm test:extensions:batch -- "$OPENCLAW_EXTENSION_BATCH" - checks-fast-extensions: - name: checks-fast-extensions - needs: [preflight, checks-fast-extensions-shard] + checks-node-extensions: + name: checks-node-extensions + needs: [preflight, checks-node-extensions-shard] if: always() && needs.preflight.outputs.run_checks_fast == 'true' runs-on: blacksmith-16vcpu-ubuntu-2404 timeout-minutes: 5 steps: - name: Verify extension shards env: - SHARD_RESULT: ${{ needs.checks-fast-extensions-shard.result }} + SHARD_RESULT: ${{ needs.checks-node-extensions-shard.result }} run: | if [ "$SHARD_RESULT" != "success" ]; then echo "Extension shard checks failed: $SHARD_RESULT" >&2 @@ -613,7 +613,7 @@ jobs: ;; esac - checks-node-test-shard: + checks-node-core-test-shard: name: ${{ matrix.check_name }} needs: [preflight, build-artifacts] if: always() && needs.preflight.outputs.run_checks == 'true' && needs.build-artifacts.result == 'success' @@ -621,7 +621,7 @@ jobs: timeout-minutes: 60 strategy: fail-fast: false - matrix: ${{ fromJson(needs.preflight.outputs.checks_node_test_matrix) }} + matrix: ${{ fromJson(needs.preflight.outputs.checks_node_core_test_matrix) }} steps: - name: Checkout uses: actions/checkout@v6 @@ -693,16 +693,16 @@ jobs: } EOF - checks-node-test: - name: checks-node-test - needs: [preflight, checks-node-test-shard] + checks-node-core-test: + name: checks-node-core-test + needs: [preflight, checks-node-core-test-shard] if: always() && needs.preflight.outputs.run_checks == 'true' runs-on: blacksmith-16vcpu-ubuntu-2404 timeout-minutes: 5 steps: - name: Verify node test shards env: - SHARD_RESULT: ${{ needs.checks-node-test-shard.result }} + SHARD_RESULT: ${{ needs.checks-node-core-test-shard.result }} run: | if [ "$SHARD_RESULT" != "success" ]; then echo "Node test shards failed: $SHARD_RESULT" >&2 diff --git a/docs/ci.md b/docs/ci.md index f1c24fb32f9..514ec5ab7cd 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -12,24 +12,25 @@ The CI runs on every push to `main` and every pull request. It uses smart scopin ## Job Overview -| Job | Purpose | When it runs | -| ------------------------ | ---------------------------------------------------------------------------------------- | ----------------------------------- | -| `preflight` | Detect docs-only changes, changed scopes, changed extensions, and build the CI manifest | Always on non-draft pushes and PRs | -| `security-fast` | Private key detection, workflow audit via `zizmor`, production dependency audit | Always on non-draft pushes and PRs | -| `build-artifacts` | Build `dist/` and the Control UI once, upload reusable artifacts for downstream jobs | Node-relevant changes | -| `checks-fast-core` | Fast Linux correctness lanes such as bundled/plugin-contract/protocol checks | Node-relevant changes | -| `checks-fast-extensions` | Aggregate the extension shard lanes after `checks-fast-extensions-shard` completes | Node-relevant changes | -| `extension-fast` | Focused tests for only the changed bundled plugins | When extension changes are detected | -| `check` | Main local gate in CI: `pnpm check` plus `pnpm build:strict-smoke` | Node-relevant changes | -| `check-additional` | Architecture, boundary, import-cycle guards plus the gateway watch regression harness | Node-relevant changes | -| `build-smoke` | Built-CLI smoke tests and startup-memory smoke | Node-relevant changes | -| `checks` | Heavier Linux Node lanes: full tests, channel tests, and push-only Node 22 compatibility | Node-relevant changes | -| `check-docs` | Docs formatting, lint, and broken-link checks | Docs changed | -| `skills-python` | Ruff + pytest for Python-backed skills | Python-skill-relevant changes | -| `checks-windows` | Windows-specific test lanes | Windows-relevant changes | -| `macos-node` | macOS TypeScript test lane using the shared built artifacts | macOS-relevant changes | -| `macos-swift` | Swift lint, build, and tests for the macOS app | macOS-relevant changes | -| `android` | Android build and test matrix | Android-relevant changes | +| Job | Purpose | When it runs | +| ------------------------ | --------------------------------------------------------------------------------------- | ----------------------------------- | +| `preflight` | Detect docs-only changes, changed scopes, changed extensions, and build the CI manifest | Always on non-draft pushes and PRs | +| `security-fast` | Private key detection, workflow audit via `zizmor`, production dependency audit | Always on non-draft pushes and PRs | +| `build-artifacts` | Build `dist/` and the Control UI once, upload reusable artifacts for downstream jobs | Node-relevant changes | +| `checks-fast-core` | Fast Linux correctness lanes such as bundled/plugin-contract/protocol checks | Node-relevant changes | +| `checks-node-extensions` | Full bundled-plugin test shards across the extension suite | Node-relevant changes | +| `checks-node-core-test` | Core Node test shards, excluding channel, bundled, contract, and extension lanes | Node-relevant changes | +| `extension-fast` | Focused tests for only the changed bundled plugins | When extension changes are detected | +| `check` | Main local gate in CI: `pnpm check` plus `pnpm build:strict-smoke` | Node-relevant changes | +| `check-additional` | Architecture, boundary, import-cycle guards plus the gateway watch regression harness | Node-relevant changes | +| `build-smoke` | Built-CLI smoke tests and startup-memory smoke | Node-relevant changes | +| `checks` | Remaining Linux Node lanes: channel tests and push-only Node 22 compatibility | Node-relevant changes | +| `check-docs` | Docs formatting, lint, and broken-link checks | Docs changed | +| `skills-python` | Ruff + pytest for Python-backed skills | Python-skill-relevant changes | +| `checks-windows` | Windows-specific test lanes | Windows-relevant changes | +| `macos-node` | macOS TypeScript test lane using the shared built artifacts | macOS-relevant changes | +| `macos-swift` | Swift lint, build, and tests for the macOS app | macOS-relevant changes | +| `android` | Android build and test matrix | Android-relevant changes | ## Fail-Fast Order @@ -38,7 +39,7 @@ Jobs are ordered so cheap checks fail before expensive ones run: 1. `preflight` decides which lanes exist at all. The `docs-scope` and `changed-scope` logic are steps inside this job, not standalone jobs. 2. `security-fast`, `check`, `check-additional`, `check-docs`, and `skills-python` fail quickly without waiting on the heavier artifact and platform matrix jobs. 3. `build-artifacts` overlaps with the fast Linux lanes so downstream consumers can start as soon as the shared build is ready. -4. Heavier platform and runtime lanes fan out after that: `checks-fast-core`, `checks-fast-extensions`, `extension-fast`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, and `android`. +4. Heavier platform and runtime lanes fan out after that: `checks-fast-core`, `checks-node-extensions`, `checks-node-core-test`, `extension-fast`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, and `android`. Scope logic lives in `scripts/ci-changed-scope.mjs` and is covered by unit tests in `src/scripts/ci-changed-scope.test.ts`. The separate `install-smoke` workflow reuses the same scope script through its own `preflight` job. It computes `run_install_smoke` from the narrower changed-smoke signal, so Docker/install smoke only runs for install, packaging, and container-relevant changes. diff --git a/scripts/lib/ci-node-test-plan.mjs b/scripts/lib/ci-node-test-plan.mjs index be06611c64c..082f5a6d821 100644 --- a/scripts/lib/ci-node-test-plan.mjs +++ b/scripts/lib/ci-node-test-plan.mjs @@ -21,7 +21,7 @@ export function createNodeTestShards() { return [ { - checkName: `checks-node-test-${shard.name}`, + checkName: `checks-node-core-test-${shard.name}`, shardName: shard.name, configs, }, diff --git a/scripts/lib/extension-test-plan.mjs b/scripts/lib/extension-test-plan.mjs index 7b5b23b4d9a..9139228ce2d 100644 --- a/scripts/lib/extension-test-plan.mjs +++ b/scripts/lib/extension-test-plan.mjs @@ -254,7 +254,7 @@ export function createExtensionTestShards(params = {}) { return shards .map((shard, index) => ({ index, - checkName: `checks-fast-extensions-shard-${index + 1}`, + checkName: `checks-node-extensions-shard-${index + 1}`, ...mergeTestPlans(shard.plans), })) .filter((shard) => shard.hasTests); diff --git a/test/scripts/ci-node-test-plan.test.ts b/test/scripts/ci-node-test-plan.test.ts new file mode 100644 index 00000000000..8e4f35b1d76 --- /dev/null +++ b/test/scripts/ci-node-test-plan.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; +import { createNodeTestShards } from "../../scripts/lib/ci-node-test-plan.mjs"; + +describe("scripts/lib/ci-node-test-plan.mjs", () => { + it("names the node shard checks as core test lanes", () => { + const shards = createNodeTestShards(); + + expect(shards).not.toHaveLength(0); + expect(shards.map((shard) => shard.checkName)).toEqual( + shards.map((shard) => `checks-node-core-test-${shard.shardName}`), + ); + }); + + it("keeps extension, bundled, contracts, and channels configs out of the core node lane", () => { + const configs = createNodeTestShards().flatMap((shard) => shard.configs); + + expect(configs).not.toContain("test/vitest/vitest.channels.config.ts"); + expect(configs).not.toContain("test/vitest/vitest.contracts.config.ts"); + expect(configs).not.toContain("test/vitest/vitest.bundled.config.ts"); + expect(configs).not.toContain("test/vitest/vitest.full-extensions.config.ts"); + expect(configs).not.toContain("test/vitest/vitest.extension-telegram.config.ts"); + }); +}); diff --git a/test/scripts/test-extension.test.ts b/test/scripts/test-extension.test.ts index 6de47d05149..a84235dd023 100644 --- a/test/scripts/test-extension.test.ts +++ b/test/scripts/test-extension.test.ts @@ -386,6 +386,9 @@ describe("scripts/test-extension.mjs", () => { }); expect(shards).toHaveLength(DEFAULT_EXTENSION_TEST_SHARD_COUNT); + expect(shards.map((shard) => shard.checkName)).toEqual( + shards.map((shard, index) => `checks-node-extensions-shard-${index + 1}`), + ); const assigned = shards.flatMap((shard) => shard.extensionIds); const uniqueAssigned = [...new Set(assigned)];