From 2be9eb1e9731887d2f67cc2f05821747fec4ec70 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Thu, 28 May 2026 13:28:22 -0700 Subject: [PATCH] ci: consolidate Blacksmith runner defaults (#87503) --- .github/workflows/ci.yml | 4 ++-- docs/ci.md | 20 +++++++++---------- scripts/lib/ci-node-test-plan.mjs | 4 +++- test/scripts/ci-node-test-plan.test.ts | 27 +++++++++++++++++++++----- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1caedc6e593..0651af91b518 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1035,7 +1035,7 @@ jobs: name: ${{ matrix.check_name }} needs: [preflight, pnpm-store-warmup] if: needs.preflight.outputs.run_checks_node_core_nondist == 'true' - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'ubuntu-24.04') || 'ubuntu-24.04') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-8vcpu-ubuntu-2404') || 'ubuntu-24.04') }} timeout-minutes: 60 strategy: fail-fast: false @@ -1141,7 +1141,7 @@ jobs: name: ${{ matrix.check_name }} needs: [preflight, pnpm-store-warmup] if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' && needs.pnpm-store-warmup.result == 'success' }} - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && matrix.runner || 'ubuntu-24.04') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }} timeout-minutes: 20 strategy: fail-fast: false diff --git a/docs/ci.md b/docs/ci.md index 833b27e5d5f7..8b014976be81 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -120,17 +120,17 @@ gh workflow run full-release-validation.yml --ref main -f ref= ## Runners -| Runner | Jobs | -| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`, docs checks, Python skills, workflow-sanity, labeler, auto-response; install-smoke preflight also uses GitHub-hosted Ubuntu so the Blacksmith matrix can queue earlier | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, `security-fast`, lower-weight extension shards, `checks-fast-core`, plugin/channel contract shards, `checks-node-compat-node22`, `check-guards`, `check-prod-types`, and `check-test-types` | -| `blacksmith-8vcpu-ubuntu-2404` | Linux Node test shards, bundled plugin test shards, `check-additional-*` shards, `android` | -| `blacksmith-16vcpu-ubuntu-2404` | `build-artifacts`, `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved); install-smoke Docker builds (32-vCPU queue time cost more than it saved) | -| `blacksmith-16vcpu-windows-2025` | `checks-windows` | -| `blacksmith-6vcpu-macos-15` | `macos-node` on `openclaw/openclaw`; forks fall back to `macos-15` | -| `blacksmith-12vcpu-macos-26` | `macos-swift` on `openclaw/openclaw`; forks fall back to `macos-26` | +| Runner | Jobs | +| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ubuntu-24.04` | Manual CI dispatch and non-canonical repository fallbacks, workflow-sanity, labeler, auto-response, docs workflows outside CI, and install-smoke preflight so the Blacksmith matrix can queue earlier | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, `preflight`, `security-fast`, lower-weight extension shards, `checks-fast-core`, plugin/channel contract shards, `checks-node-compat-node22`, `check-guards`, `check-prod-types`, and `check-test-types` | +| `blacksmith-8vcpu-ubuntu-2404` | Linux Node test shards, bundled plugin test shards, `check-additional-*` shards, `check-dependencies`, and `android` | +| `blacksmith-16vcpu-ubuntu-2404` | `build-artifacts`, `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved); install-smoke Docker builds (32-vCPU queue time cost more than it saved) | +| `blacksmith-16vcpu-windows-2025` | `checks-windows` | +| `blacksmith-6vcpu-macos-15` | `macos-node` on `openclaw/openclaw`; forks fall back to `macos-15` | +| `blacksmith-12vcpu-macos-26` | `macos-swift` on `openclaw/openclaw`; forks fall back to `macos-26` | -Canonical-repo CI keeps Blacksmith as the default runner path. During `preflight`, `scripts/ci-runner-labels.mjs` checks recent queued and in-progress Actions runs for queued Blacksmith jobs. If a specific Blacksmith label already has queued jobs, downstream jobs that would use that exact label fall back to the matching GitHub-hosted runner (`ubuntu-24.04`, `windows-2025`, `macos-15`, or `macos-26`) for that run only. Other Blacksmith sizes in the same OS family stay on their primary labels. If the API probe fails, no fallback is applied. +Canonical-repo CI keeps Blacksmith as the default runner path for normal push and pull-request runs. `workflow_dispatch` and non-canonical repository runs use GitHub-hosted runners, but normal canonical runs do not currently probe Blacksmith queue health or automatically fall back to GitHub-hosted labels when Blacksmith is unavailable. ## Local equivalents diff --git a/scripts/lib/ci-node-test-plan.mjs b/scripts/lib/ci-node-test-plan.mjs index e1857e78637f..1a584ed2f20a 100644 --- a/scripts/lib/ci-node-test-plan.mjs +++ b/scripts/lib/ci-node-test-plan.mjs @@ -10,6 +10,7 @@ const EXCLUDED_FULL_SUITE_SHARDS = new Set([ ]); const EXCLUDED_PROJECT_CONFIGS = new Set(["test/vitest/vitest.channels.config.ts"]); +const DEFAULT_NODE_TEST_RUNNER = "blacksmith-8vcpu-ubuntu-2404"; const RELEASE_ONLY_PLUGIN_SHARDS = new Set(["agentic-plugins"]); function listTestFiles(rootDir) { return listTrackedTestFiles(rootDir); @@ -442,7 +443,7 @@ export function createNodeTestShards(options = {}) { shardName: splitShard.shardName, configs: splitConfigs, ...(splitShard.includePatterns ? { includePatterns: splitShard.includePatterns } : {}), - ...(splitShard.runner ? { runner: splitShard.runner } : {}), + runner: splitShard.runner ?? DEFAULT_NODE_TEST_RUNNER, requiresDist: splitShard.requiresDist, }, ]; @@ -454,6 +455,7 @@ export function createNodeTestShards(options = {}) { checkName: formatNodeTestShardCheckName(shard.name), shardName: shard.name, configs, + runner: DEFAULT_NODE_TEST_RUNNER, requiresDist: DIST_DEPENDENT_NODE_SHARD_NAMES.has(shard.name), }, ]; diff --git a/test/scripts/ci-node-test-plan.test.ts b/test/scripts/ci-node-test-plan.test.ts index 9396c0113ebb..5f6b0fd7b9a4 100644 --- a/test/scripts/ci-node-test-plan.test.ts +++ b/test/scripts/ci-node-test-plan.test.ts @@ -21,6 +21,7 @@ type VitestConfig = { const PLUGIN_PRERELEASE_NPM_SPEC_TEST = "src/plugins/install.npm-spec.test.ts"; const PLUGIN_NPM_INSTALL_SECURITY_SCAN_TEST = "src/plugins/npm-install-security-scan.release.test.ts"; +const DEFAULT_NODE_TEST_RUNNER = "blacksmith-8vcpu-ubuntu-2404"; const GATEWAY_SERVER_BACKED_HTTP_TESTS = new Set([ "src/gateway/embeddings-http.test.ts", "src/gateway/models-http.test.ts", @@ -172,6 +173,13 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { expect(requiresDistShardNames).toEqual(["core-support-boundary"]); }); + it("assigns Blacksmith runners to every core node shard", () => { + const shards = createNodeTestShards(); + + expect(shards).not.toHaveLength(0); + expect(shards.every((shard) => shard.runner?.startsWith("blacksmith-"))).toBe(true); + }); + it("splits core runtime configs into smaller source-only shards", () => { const runtimeShards = createNodeTestShards() .filter((shard) => shard.shardName.startsWith("core-runtime-")) @@ -212,7 +220,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.wizard.config.ts", ], requiresDist: false, - runner: undefined, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "core-runtime-media-ui", }, { @@ -223,25 +231,25 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.utils.config.ts", ], requiresDist: false, - runner: undefined, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "core-runtime-shared", }, { configs: ["test/vitest/vitest.cron.config.ts"], requiresDist: false, - runner: undefined, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "core-runtime-cron-core", }, { configs: ["test/vitest/vitest.cron.config.ts"], requiresDist: false, - runner: undefined, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "core-runtime-cron-isolated-agent", }, { configs: ["test/vitest/vitest.cron.config.ts"], requiresDist: false, - runner: undefined, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "core-runtime-cron-service", }, ]); @@ -313,6 +321,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { shardName: "agentic-cli", configs: ["test/vitest/vitest.cli.config.ts"], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(commandSupportShard).toEqual({ checkName: "checks-node-agentic-command-support", @@ -322,6 +331,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.daemon.config.ts", ], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(commandShards.map((shard) => shard.shardName)).toEqual([ "agentic-commands-agent-channel", @@ -337,6 +347,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { configs: ["test/vitest/vitest.commands.config.ts"], includePatterns: shard.includePatterns, requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: shard.shardName, })), ); @@ -358,6 +369,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.agents-tools.config.ts", ], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(pluginSdkShard).toEqual({ checkName: "checks-node-agentic-plugin-sdk", @@ -367,6 +379,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.plugin-sdk.config.ts", ], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(gatewayCoreShard).toEqual({ checkName: "checks-node-agentic-gateway-core", @@ -376,18 +389,21 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { "test/vitest/vitest.gateway-client.config.ts", ], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(gatewayMethodsShard).toEqual({ checkName: "checks-node-agentic-gateway-methods", shardName: "agentic-gateway-methods", configs: ["test/vitest/vitest.gateway-methods.config.ts"], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); expect(pluginsShard).toEqual({ checkName: "checks-node-agentic-plugins", shardName: "agentic-plugins", configs: ["test/vitest/vitest.plugins.config.ts"], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, }); }); @@ -400,6 +416,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { checkName: "checks-node-agentic-plugins", configs: ["test/vitest/vitest.plugins.config.ts"], requiresDist: false, + runner: DEFAULT_NODE_TEST_RUNNER, shardName: "agentic-plugins", }); expect(listMatchedTestFiles(createPluginsVitestConfig({}))).toContain(