mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-25 16:37:51 +00:00
fix(ci): keep import-cycle checks blocking on pull requests
Run Madge in the existing check-guards job for TypeScript changes and conservative full-scope PR plans, including forks. The runtime-value cycle check already runs there. Keep the remaining architecture checks deferred and preserve hourly, manual, and release-gate behavior. Select the additional check in the check-family and manifest owners; add no jobs, runners, or checkout dependencies. Cover selection and blocking failure propagation in both existing guard execution paths. Validation: full test types; whole tooling with targeted prerequisite and upstream fixture recovery; full unit-fast and isolated configurations; check-changed including types, lint and dead exports; boundary and workflow lint; all four real preflight checkout/event shapes; independent P2 review. The existing runtime check took 16.9 seconds on four CPUs; the added Madge check took 75.8 seconds. Job and runner counts remain unchanged.
This commit is contained in:
parent
2d3a5c7bbc
commit
906eb2d2a9
9 changed files with 131 additions and 16 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -182,6 +182,7 @@ jobs:
|
|||
checks_node_core_nondist_matrix: ${{ steps.manifest.outputs.checks_node_core_nondist_matrix }}
|
||||
run_checks_node_core_dist: ${{ steps.manifest.outputs.run_checks_node_core_dist }}
|
||||
run_check: ${{ steps.manifest.outputs.run_check }}
|
||||
run_pr_madge_import_cycles: ${{ steps.manifest.outputs.run_pr_madge_import_cycles }}
|
||||
startup_corpus_node_revision: ${{ steps.manifest.outputs.startup_corpus_node_revision }}
|
||||
startup_corpus_test_files_json: ${{ steps.manifest.outputs.startup_corpus_test_files_json }}
|
||||
changed_core_test_paths_json: ${{ steps.manifest.outputs.changed_core_test_paths_json }}
|
||||
|
|
@ -3670,6 +3671,7 @@ jobs:
|
|||
FROZEN_TARGET: *frozen_target
|
||||
HISTORICAL_TARGET: *historical_target
|
||||
FORMAT_CHECK: ${{ needs.preflight.outputs.run_format_check }}
|
||||
RUN_PR_MADGE_IMPORT_CYCLES: ${{ needs.preflight.outputs.run_pr_madge_import_cycles }}
|
||||
RELEASE_GATE: &release_gate ${{ inputs.release_gate && (needs.preflight.outputs.node_runner_backend != 'runson' && needs.preflight.outputs.ci_qualification != 'true') && 'true' || 'false' }}
|
||||
RUN_CONTROL_UI_I18N: ${{ needs.preflight.outputs.run_control_ui_i18n }}
|
||||
RUN_UI_TESTS: ${{ needs.preflight.outputs.run_ui_tests }}
|
||||
|
|
@ -3762,6 +3764,9 @@ jobs:
|
|||
pnpm lint:auth:no-pairing-store-group
|
||||
pnpm lint:auth:pairing-account-scope
|
||||
pnpm check:import-cycles
|
||||
if [[ "${RUN_PR_MADGE_IMPORT_CYCLES:-false}" == "true" ]]; then
|
||||
GOGC="${GOGC:-30}" GOMEMLIMIT="${GOMEMLIMIT:-3GiB}" pnpm check:madge-import-cycles
|
||||
fi
|
||||
;;
|
||||
npm-lock)
|
||||
if [[ "$SKIP_NPM_LOCK" == "true" ]]; then
|
||||
|
|
@ -4294,6 +4299,7 @@ jobs:
|
|||
if: matrix.group == 'guards' || matrix.group == 'dependencies'
|
||||
env:
|
||||
TASK: ${{ matrix.group }}
|
||||
RUN_PR_MADGE_IMPORT_CYCLES: ${{ needs.preflight.outputs.run_pr_madge_import_cycles }}
|
||||
OPENCLAW_LOCAL_CHECK: "0"
|
||||
FROZEN_TARGET: *frozen_target
|
||||
HISTORICAL_TARGET: *historical_target
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ expensive jobs in `ci.yml`:
|
|||
- Real-Gateway Control UI E2E (mocked/bundled `checks-ui-e2e` remains owner-selected).
|
||||
- Windows Node tests, macOS Node tests, macOS Swift jobs, and iOS build/simulator smoke.
|
||||
- The published-npm-driver × candidate update cell, including on update-owner PRs.
|
||||
- Dependency/dead-export scanning (Knip) and runtime topology/architecture checks.
|
||||
- Dependency/dead-export scanning (Knip) and the full runtime topology/architecture job.
|
||||
Runtime import-cycle checks remain in the existing PR guard; TypeScript changes
|
||||
also select Madge there. See [scope selection](/ci/scope-and-routing/selection).
|
||||
- Android screenshot capture.
|
||||
|
||||
The first four groups retain their existing hourly main-tier and full release
|
||||
|
|
|
|||
|
|
@ -23,20 +23,33 @@ Scope logic lives in `scripts/ci-changed-scope.mjs` and is covered by unit tests
|
|||
|
||||
### PR vs hourly vs release
|
||||
|
||||
Ordinary `pull_request` runs, including contributions from forks, defer the
|
||||
following jobs. The preflight manifest emits false selection flags and omits
|
||||
check-matrix rows, so `openclaw/ci-gate` accepts their expected absence.
|
||||
Ordinary `pull_request` runs, including contributions from forks, use the
|
||||
following validation tiers. For deferred jobs, the preflight manifest emits false
|
||||
selection flags and omits check-matrix rows, so `openclaw/ci-gate` accepts their
|
||||
expected absence. Import-cycle checks remain blocking in the existing guard job.
|
||||
|
||||
| Proof | Ordinary PR | Hourly main tier | Full release validation |
|
||||
| ---------------------------------- | --------------------------------- | ---------------------------- | ----------------------------- |
|
||||
| Real-Gateway Control UI E2E | Deferred | Existing inventory | Existing inventory |
|
||||
| Windows Node tests | Deferred | Existing five-row inventory | Existing inventory |
|
||||
| macOS Node and Swift jobs | Deferred | Existing tests/packages | Existing native phases |
|
||||
| iOS build/simulator smoke | Deferred | Existing tests phase | Existing Release/tests phases |
|
||||
| Published-driver update | Deferred, including update owners | Existing managed update cell | Existing managed update cell |
|
||||
| Dependency/dead-export scan (Knip) | Deferred | Existing check | Existing check |
|
||||
| Runtime topology and architecture | Deferred | Existing check | Existing check |
|
||||
| Android screenshots | Deferred | Already excluded | Existing capture proof |
|
||||
| Proof | Ordinary PR | Hourly main tier | Full release validation |
|
||||
| ----------------------------------- | ------------------------------------- | ---------------------------- | ----------------------------- |
|
||||
| Real-Gateway Control UI E2E | Deferred | Existing inventory | Existing inventory |
|
||||
| Windows Node tests | Deferred | Existing five-row inventory | Existing inventory |
|
||||
| macOS Node and Swift jobs | Deferred | Existing tests/packages | Existing native phases |
|
||||
| iOS build/simulator smoke | Deferred | Existing tests phase | Existing Release/tests phases |
|
||||
| Published-driver update | Deferred, including update owners | Existing managed update cell | Existing managed update cell |
|
||||
| Dependency/dead-export scan (Knip) | Deferred | Existing check | Existing check |
|
||||
| Import cycles (runtime and types) | Existing guard for TypeScript changes | Existing checks | Existing checks |
|
||||
| Other runtime topology/architecture | Deferred | Existing check | Existing check |
|
||||
| Android screenshots | Deferred | Already excluded | Existing capture proof |
|
||||
|
||||
Import-cycle checks are blocking correctness guards. Four cycles reached main after
|
||||
the architecture deferral ([#165174](https://github.com/openclaw/openclaw/pull/165174),
|
||||
[#165274](https://github.com/openclaw/openclaw/pull/165274),
|
||||
[#165304](https://github.com/openclaw/openclaw/pull/165304), and
|
||||
[#165346](https://github.com/openclaw/openclaw/pull/165346)).
|
||||
[Hourly job 111622440413](https://github.com/openclaw/openclaw/actions/runs/37265802634/job/111622440413)
|
||||
spent about 14 seconds on runtime cycles and 57 seconds on Madge. The runtime
|
||||
checker already runs in the PR guard; adding Madge there restores type-cycle
|
||||
coverage without restoring the larger architecture row. Hourly and manual/release
|
||||
commands remain unchanged.
|
||||
|
||||
These jobs were frequent PR critical paths despite overlapping source tests and
|
||||
static checks. Moving their admission preserves the same cases, assertions,
|
||||
|
|
@ -144,7 +157,7 @@ The iOS, macOS, and both shared OpenClawKit Periphery scans use Xcode 27 on GitH
|
|||
- **Global and hub Node inputs** select their bounded owner tests, transitive import consumers, and protected regressions plus the fixed PR smoke set. Shared test bootstrap/configuration, root compiler resolution, workspace/install settings, patches, dependency hubs, and packing policy no longer request the complete runtime plan. Static checks retain full fallback where ownership is ambiguous. Missing changed paths or an unavailable bounded selector fail preflight instead of admitting every runtime family. Global package, lockfile, compiler, and shared Vitest inputs do not select every platform/browser family merely because Node ownership is broad; related protected tests remain selected. UI and wizard locale catalogs and translation metadata retain their dedicated localization and compiler checks without PR Node or browser rows; localization generators and runtime modules retain tests.
|
||||
- **Generated Control UI boot metadata** selects its chunking and Vite tests through the shared test-target map. The existing UI performance lane still builds and checks the generated chunks; the metadata alone does not require unrelated core suites.
|
||||
- **Preflight diagnostics** log `Node test plan changed-set` with the selected row count and any bounded owner-selection reason. Missing or unbounded PR plans fail preflight; they never become the full compact matrix. The logged changed-path manifest supplies replay inputs. Hourly main and ordinary manual/release validation retain complete inventories through their existing owners.
|
||||
- **PR check families** select static checks and guards from their own changed-path owners, independently of whether Node test targeting finds a precise plan. Lint and formatting reuse the local changed-check owner; lint configuration changes retain full lint. Semantic lint runs changed files and their transitive import consumers, including type-only imports and workspace/path aliases, through the existing shard owner. Each row receives only its assigned file list; workers do not rediscover the graph. Affected root tests retain their central compiler-config admission. Deleted, ambient, unsupported, and oversized selections retain full lint. Hourly main and Full Release Validation continue running full repository lint. Hosted profiles keep selected files in their existing stripes, while scripts, root tests, formatting, and localization checks retain their central owner. Preflight remains dependency-free and owns admission, static-check selection, and the original row/resource templates. For admitted narrow PRs, the hosted `check-plan` job installs through the existing Node setup owner, then materializes selected-file lint and compiler facts. It validates compiler ownership and selects every graph that consumes a changed file, including erased type imports into UI, plugins, scripts, and tests. Its consumers require a successful plan; failure cannot silently select a full fallback, and `openclaw/ci-gate` requires the planner itself. Existing production, test, and stripe jobs retain their runner placement and compiler concurrency; only rows with selected graphs run. GitHub and hybrid keep changed core-test consumers in their canonical stripes; the central row owns the selected extensions, scripts, and root-test graphs. Markdown and UI styles do not widen a mixed TypeScript change. Deleted, ambient, configuration, and unclassified inputs retain all compiler graphs. Shared fixtures and scanner policy inputs retain conservative check families. Conflict-marker and wall-clock deprecation guards run after Node setup in the required planner job. Other guards retain their generated native inputs. SDK subpath exports, extension import boundaries, declaration compile/canary proof, protocol generation, and schema drift remain blocking. Knip and runtime topology/architecture run in hourly main and full release validation instead of ordinary PRs. Plugin and channel runtime contract tests use the exact changed-owner Node plan, including their watched SDK documentation and packaged skills. Narrow code changes run coercion checks once in the guard job. Main, ordinary manual CI, and historical targets skip this additional planner and retain their full check families. Static full fallback never widens runtime families. Bundled config metadata follows the shared schema owner map. The bundled/protocol row always verifies protocol generation; its full bundled runtime suite runs only on hourly main and ordinary manual/release validation. Specialized Bun launcher proof opts in for its direct launcher and module-generation owners. Startup, plugin, and channel tests retain their canonical configs within the changed-owner plan.
|
||||
- **PR check families** select static checks and guards from their own changed-path owners, independently of whether Node test targeting finds a precise plan. Lint and formatting reuse the local changed-check owner; lint configuration changes retain full lint. Semantic lint runs changed files and their transitive import consumers, including type-only imports and workspace/path aliases, through the existing shard owner. Each row receives only its assigned file list; workers do not rediscover the graph. Affected root tests retain their central compiler-config admission. Deleted, ambient, unsupported, and oversized selections retain full lint. Hourly main and Full Release Validation continue running full repository lint. Hosted profiles keep selected files in their existing stripes, while scripts, root tests, formatting, and localization checks retain their central owner. Preflight remains dependency-free and owns admission, static-check selection, and the original row/resource templates. For admitted narrow PRs, the hosted `check-plan` job installs through the existing Node setup owner, then materializes selected-file lint and compiler facts. It validates compiler ownership and selects every graph that consumes a changed file, including erased type imports into UI, plugins, scripts, and tests. Its consumers require a successful plan; failure cannot silently select a full fallback, and `openclaw/ci-gate` requires the planner itself. Existing production, test, and stripe jobs retain their runner placement and compiler concurrency; only rows with selected graphs run. GitHub and hybrid keep changed core-test consumers in their canonical stripes; the central row owns the selected extensions, scripts, and root-test graphs. Markdown and UI styles do not widen a mixed TypeScript change. Deleted, ambient, configuration, and unclassified inputs retain all compiler graphs. Shared fixtures and scanner policy inputs retain conservative check families. Conflict-marker and wall-clock deprecation guards run after Node setup in the required planner job. Other guards retain their generated native inputs. SDK subpath exports, extension import boundaries, declaration compile/canary proof, protocol generation, and schema drift remain blocking. The existing required `check-guards` job retains `check:import-cycles` and also runs `check:madge-import-cycles` when TypeScript files change, including type declarations, TSX, MTS, and CTS. The check-family owner selects Madge from preflight’s changed paths; ambiguous/full scope and older owners retain it conservatively. Both same-repository and fork PRs use that same guard row, with no extra job, runner, checkout, or compiler-plan wait. Scoped non-TypeScript changes do not add Madge. Knip and the remaining runtime topology checks (deprecated APIs, wrapper shadowing, JSDoc, Kysely, and database-first guards) retain hourly main and full release validation instead of ordinary PRs. Plugin and channel runtime contract tests use the exact changed-owner Node plan, including their watched SDK documentation and packaged skills. Narrow code changes run coercion checks once in the guard job. Main, ordinary manual CI, and historical targets skip this additional planner and retain their full check families. Static full fallback never widens runtime families. Bundled config metadata follows the shared schema owner map. The bundled/protocol row always verifies protocol generation; its full bundled runtime suite runs only on hourly main and ordinary manual/release validation. Specialized Bun launcher proof opts in for its direct launcher and module-generation owners. Startup, plugin, and channel tests retain their canonical configs within the changed-owner plan.
|
||||
- **Browser integration on PRs** uses the mocked Control UI file selection above and retains the browser-extension family when its existing owners change. Real-Gateway files are excluded even when directly changed or selected as import consumers; they cannot return through changed-Node fallback. Unrelated families remain omitted unless protected or affected tests select a precise subset. Named release-only real-Gateway compositions retain their existing opt-in policy. Existing row caps, worker limits, serial/parallel ownership, and runner routes stay unchanged; small Control UI selections omit empty rows. Empty real-Gateway phase groups are removed; a desktop-only carrier keeps its required desktop proof without invoking a test phase with no files. Hourly main and Full Release Validation retain the full Control UI E2E set; historical manual targets without the selector retain their existing full target-owned path.
|
||||
- **Extension package boundary selection** uses the PR's own merge-base diff, independently of restored receipt age. The job reuses the extension-lint planner’s bounded base-fetch action. A depth-one PR merge is compared with its verified raw first-parent tree, without requiring a complete ancestry walk. It checks directly touched plugin packages. Core/SDK declaration and shared compiler/dependency changes add a fixed smoke set: Telegram, Codex and Slack, chosen to cover 119 distinct directly consumed public SDK entries. Changes to a public SDK entry file also select packages that directly import that entry, including type-only imports. Transitive declaration consumers and main-only drift are intentionally left to the complete hourly main and manual/release checks. Selected packages retain full compiler diagnostics and normal receipt validation. Declaration preparation follows their packaged entry points with the native compiler, emitting only consumed SDK roots and required plugin declaration producers, including transitive inputs and ambient declarations. Hourly and manual/release checks still prepare the complete declaration set. The negative boundary canary always runs. The job summary lists selected and skipped packages with reasons. Unset repository variable `OPENCLAW_CI_EXTENSION_BOUNDARY_FULL` enables this aggressive policy; `true`, `1` or `full` restores complete PR checks. An unavailable comparison or import inventory also retains full scope.
|
||||
- **Shared SDK declarations** keep the existing boundary check as a standalone producer on supported hybrid PRs targeting the canonical repository that already select both the boundary row and the check planner. The job count and check name stay unchanged. That producer validates a full native SDK and publishes its declaration tree and checked receipt; extension lint waits for that artifact and validates it through the usual preparation owner. Other additional checks and test-type jobs retain their existing dependencies. A content-keyed main cache supplies the same SDK to other consumers, with receipt validation on every restore. Compiler directory lookups use sorted file and directory membership, so relocation can retain a valid receipt when filesystem enumeration order changes. Scheduled, manual, release, frozen, and unsupported targets retain their complete existing checks.
|
||||
|
|
|
|||
|
|
@ -1395,6 +1395,10 @@ const manifest = {
|
|||
checks_node_core_nondist_matrix: createMatrix(nodeTestNonDistShards),
|
||||
run_checks_node_core_dist: runNodeCoreDist,
|
||||
run_check: runCheck,
|
||||
// The existing guards row already runs the runtime-value cycle check.
|
||||
// Older scope owners retain Madge rather than silently dropping the type graph.
|
||||
run_pr_madge_import_cycles:
|
||||
runCheck && ordinaryPullRequest && (proposedCheckScope?.madgeImportCycles ?? true),
|
||||
narrow_check_paths_json: runCheckPlan ? JSON.stringify(changedPaths) : "",
|
||||
run_check_plan: runCheckPlan,
|
||||
check_plan_input_json: runCheckPlan
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ type CiCheckFamilyScope = {
|
|||
fastTasks: string[];
|
||||
additionalGroups: string[];
|
||||
baselineRatchets: boolean;
|
||||
madgeImportCycles: boolean;
|
||||
lint: boolean;
|
||||
types: boolean;
|
||||
};
|
||||
|
|
@ -59,6 +60,7 @@ export function resolveCiCheckFamilyScope(changedPaths: readonly string[]): CiCh
|
|||
fastTasks: ["bundled-protocol", ...(bunLauncher ? ["bun-launcher"] : [])],
|
||||
additionalGroups: [...ADDITIONAL_GROUPS],
|
||||
baselineRatchets: true,
|
||||
madgeImportCycles: true,
|
||||
lint: true,
|
||||
types: true,
|
||||
};
|
||||
|
|
@ -120,6 +122,7 @@ export function resolveCiCheckFamilyScope(changedPaths: readonly string[]): CiCh
|
|||
(group === "runtime-topology-architecture" && (source || code || nativeStorage)),
|
||||
),
|
||||
baselineRatchets: code || runtimeSource || inventoryDocs,
|
||||
madgeImportCycles: matches(/\.(?:[cm]?ts|tsx)$/u),
|
||||
// The changed-lint row also owns formatting for YAML, JSON5, and other data.
|
||||
lint: true,
|
||||
types,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ type ScopeCase = {
|
|||
};
|
||||
const scoped: ScopeCase["expected"] = {
|
||||
baselineRatchets: true,
|
||||
madgeImportCycles: true,
|
||||
lint: true,
|
||||
types: true,
|
||||
};
|
||||
|
|
@ -23,6 +24,8 @@ const cases: ScopeCase[] = [
|
|||
},
|
||||
...[
|
||||
"src/shared/runtime.ts",
|
||||
"packages/media-core/src/runtime.mts",
|
||||
"packages/media-core/src/runtime.cts",
|
||||
"extensions/telegram/src/runtime.ts",
|
||||
"packages/media-core/src/types.d.ts",
|
||||
].map((path) => ({
|
||||
|
|
@ -90,7 +93,15 @@ const cases: ScopeCase[] = [
|
|||
expected: { checkTasks: expect.arrayContaining(["npm-lock"]) },
|
||||
},
|
||||
{ paths: ["src/config/catalog.yaml"], expected: { lint: true, types: false } },
|
||||
{ paths: ["src/config/catalog.json"], expected: { lint: true, types: true } },
|
||||
{
|
||||
paths: ["src/config/catalog.json"],
|
||||
expected: { lint: true, types: true, madgeImportCycles: false },
|
||||
},
|
||||
{ paths: ["src/shared/runtime.js"], expected: { madgeImportCycles: false } },
|
||||
{
|
||||
paths: ["ui/src/runtime.tsx"],
|
||||
expected: { madgeImportCycles: true, checkTasks: ["guards", "dependencies"] },
|
||||
},
|
||||
{ paths: ["test/openclaw-launcher.e2e.test.ts"], expected: { fastTasks: ["bun-launcher"] } },
|
||||
];
|
||||
|
||||
|
|
@ -102,6 +113,7 @@ describe("narrow PR check families", () => {
|
|||
fastTasks: [],
|
||||
additionalGroups: [],
|
||||
baselineRatchets: false,
|
||||
madgeImportCycles: false,
|
||||
lint: true,
|
||||
types: false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,38 @@ import {
|
|||
type WorkflowStep,
|
||||
} from "./ci-workflow.test-support.js";
|
||||
|
||||
it.each(["openclaw/openclaw", "contributor/openclaw"])(
|
||||
"keeps TypeScript cycle checks in the existing PR guard for %s",
|
||||
(headRepository) => {
|
||||
for (const [changedPath, selected] of [
|
||||
["src/skills/runtime/refresh.ts", true],
|
||||
["src/shared/runtime.js", false],
|
||||
] as const) {
|
||||
const result = runCiManifestFixture({
|
||||
bundledPlanner: true,
|
||||
checkFamilyScope: true,
|
||||
eventName: "pull_request",
|
||||
runnerProfile: "hybrid",
|
||||
changedPaths: [changedPath],
|
||||
scopeEnv: { OPENCLAW_CI_HEAD_REPOSITORY: headRepository },
|
||||
});
|
||||
expect(result.status, result.output).toBe(0);
|
||||
expect(result.outputs.run_pr_madge_import_cycles).toBe(String(selected));
|
||||
const rows = ["check_matrix", "check_additional_matrix"].flatMap(
|
||||
(key) =>
|
||||
JSON.parse(expectDefined(result.outputs[key], key)).include as Array<{
|
||||
check_name: string;
|
||||
task?: string;
|
||||
group?: string;
|
||||
}>,
|
||||
);
|
||||
expect(rows.filter((row) => (row.task ?? row.group) === "guards")).toHaveLength(1);
|
||||
expect(rows.some((row) => row.group === "runtime-topology-architecture")).toBe(false);
|
||||
expect(rows.some((row) => row.check_name.includes("import-cycle"))).toBe(false);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("does not budget a disabled PR screenshot request", () => {
|
||||
const results = ["false", "true"].map((hint) => {
|
||||
const result = runCiManifestFixture({
|
||||
|
|
@ -66,6 +98,7 @@ it.each([
|
|||
},
|
||||
});
|
||||
expect(result.status, result.output).toBe(0);
|
||||
expect(result.outputs.run_pr_madge_import_cycles).toBe(String(deferred));
|
||||
for (const flag of [
|
||||
"run_ui_real_gateway",
|
||||
"run_checks_windows",
|
||||
|
|
|
|||
|
|
@ -5136,6 +5136,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
|||
env: {
|
||||
TASK: task,
|
||||
RUN_BUNDLED_TESTS: String(eventName !== "pull_request"),
|
||||
RUN_PR_MADGE_IMPORT_CYCLES: String(eventName === "pull_request"),
|
||||
GITHUB_EVENT_NAME: eventName,
|
||||
CHECKOUT_KIND: "linux-node",
|
||||
CHECKOUT_BASE_SHA: String(checkoutBase),
|
||||
|
|
|
|||
|
|
@ -500,6 +500,8 @@ function runCheckShardFixture(options: {
|
|||
scripts: string[];
|
||||
task?: "guards" | "npm-lock" | "prod-types" | "test-types";
|
||||
earlyGuards?: boolean;
|
||||
madgeImportCycles?: boolean;
|
||||
failPackageScript?: string;
|
||||
checkoutBase?: string;
|
||||
types?: {
|
||||
compose?: boolean;
|
||||
|
|
@ -629,6 +631,7 @@ appendFileSync(process.env.TYPE_CALLS, [process.env.TYPE_ROW, process.env.OPENCL
|
|||
preflightOutputs: {
|
||||
compatibility_target: String(options.frozenTarget),
|
||||
run_format_check: "false",
|
||||
run_pr_madge_import_cycles: String(options.madgeImportCycles ?? false),
|
||||
changed_core_test_paths_json: options.types?.changedPathsJson ?? "",
|
||||
narrow_check_paths_json:
|
||||
options.types?.narrowPathsJson ?? (options.earlyGuards ? '["src/shared/runtime.ts"]' : ""),
|
||||
|
|
@ -701,6 +704,9 @@ appendFileSync(process.env.TYPE_CALLS, [process.env.TYPE_ROW, process.env.OPENCL
|
|||
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
|
||||
PNPM_CALLS: callsPath,
|
||||
TASK: options.task ?? "guards",
|
||||
RUN_PR_MADGE_IMPORT_CYCLES: String(
|
||||
resolveValue(row.step.env?.RUN_PR_MADGE_IMPORT_CYCLES) ?? "",
|
||||
),
|
||||
...(typeCheck || options.earlyGuards
|
||||
? {
|
||||
OPENCLAW_LOCAL_CHECK: undefined,
|
||||
|
|
@ -716,6 +722,7 @@ appendFileSync(process.env.TYPE_CALLS, [process.env.TYPE_ROW, process.env.OPENCL
|
|||
),
|
||||
}
|
||||
: {}),
|
||||
FAIL_PACKAGE_SCRIPT: options.failPackageScript ?? options.types?.failPackageScript,
|
||||
},
|
||||
}),
|
||||
{ name: row.name },
|
||||
|
|
@ -6661,6 +6668,40 @@ describe("ci workflow guards", () => {
|
|||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ earlyGuards: false, selected: false, failure: "" },
|
||||
{ earlyGuards: true, selected: false, failure: "" },
|
||||
{ earlyGuards: false, selected: true, failure: "" },
|
||||
{ earlyGuards: true, selected: true, failure: "" },
|
||||
{ earlyGuards: false, selected: true, failure: "check:import-cycles" },
|
||||
{ earlyGuards: true, selected: true, failure: "check:import-cycles" },
|
||||
{ earlyGuards: false, selected: true, failure: "check:madge-import-cycles" },
|
||||
{ earlyGuards: true, selected: true, failure: "check:madge-import-cycles" },
|
||||
])(
|
||||
"keeps cycle checks blocking in the existing guard row ($earlyGuards, $selected, $failure)",
|
||||
({ earlyGuards, selected, failure }) => {
|
||||
const result = runCheckShardFixture({
|
||||
frozenTarget: false,
|
||||
earlyGuards,
|
||||
madgeImportCycles: selected,
|
||||
failPackageScript: failure,
|
||||
scripts: [
|
||||
"check:doctor-deprecation-registry",
|
||||
"check:browser-inspect-script:swift",
|
||||
"check:temp-path-guardrails",
|
||||
"check:coercion-helpers",
|
||||
],
|
||||
});
|
||||
expect(result.status, result.output).toBe(failure ? 17 : 0);
|
||||
expect(result.calls.filter((call) => call.includes("import-cycles"))).toEqual(
|
||||
selected && failure !== "check:import-cycles"
|
||||
? ["check:import-cycles", "check:madge-import-cycles"]
|
||||
: ["check:import-cycles"],
|
||||
);
|
||||
expect(result.calls).not.toContain("check:architecture");
|
||||
},
|
||||
);
|
||||
|
||||
it("runs temp path guardrails in the hosted guard shard", () => {
|
||||
const requiredScripts = [
|
||||
"check:doctor-deprecation-registry",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue