Files
openclaw/test/scripts/openclaw-npm-extended-stable-full-validation-workflow.test.ts
Peter Steinberger fe261b0f59 chore(tooling): typecheck root test/** with a dedicated tsgo lane (#104475)
* chore(types): add declaration files for scripts/lib and scripts/e2e modules

* chore(types): add declaration files for top-level script modules (a-m)

* chore(types): add declaration files for top-level script modules (n-z)

* test: use a non-secret-shaped gateway token fixture

* test: type ci workflow guard helpers for the root test lane

* chore(tooling): typecheck root test/** with a dedicated tsgo lane

- test/tsconfig/tsconfig.test.root.json: root-test program (strict unused checks,
  fixtures excluded; two Docker E2E clients that import built dist/** stay out,
  same rationale as the scripts/e2e exclusion in tsconfig.scripts.json)
- tsgo:test:root wired into tsgo:test, check:test-types, scripts/check.mjs, and
  the ci.yml test-types shard, mirroring the tsgo:scripts lane (#104348)
- changed-lane routing: test/**/*.ts (excluding fixtures) and the lane tsconfig
  now trigger 'typecheck test root' in check:changed; previously test/ paths ran
  lint only, so harness type errors surfaced first in CI (#104287 envDir case)
- burn down all 1071 latent type errors in the program: precise param/local
  types across test/scripts, test/vitest, test/e2e, and transitive scripts/e2e
  program members; 205 sibling .d.mts declaration files for imported .mjs
  modules (committed separately); zero any, zero ts-expect-error
- resolve the pre-existing testing star-export ambiguity in
  scripts/e2e/parallels/common.ts with an explicit re-export

Closes #104388

* chore(types): correct declaration fidelity per structured review

- re-derive 51 .d.mts files from implementation data flow instead of
  initializers: fix a wrong never return (runTestProjectsDelegation returns
  the child), add encoding-sensitive exec/spawn overloads (plain-gh), restore
  the full release profile union, make parsed paths string | null, add missing
  parseArgs fields via help/non-help unions, add a missing sibling declaration
  (budget-number-args), drop 15 unused lint directives
- precise install-record/tuple typing removes the type-aware oxlint
  regressions the first declarations caused in scripts/e2e implementations
- route .mts declaration edits under test/ to the testRoot lane and reference
  the test-root project from tsconfig.projects.json so tsgo:all covers it
  (closes both review findings against the lane wiring)

* chore(scripts): keep telegram runner dist typing structural for the boundary guard

* chore(types): declare runtime pack and gateway readiness exports added on main

* test: pin the importTargetPlan form of the plugin-contract plan import

The guard expectation still referenced the raw await import( form that
7ae5996bb3 (#103975) replaced with the importTargetPlan fallback helper;
the assertion fails on current main.
2026-07-11 06:15:41 -07:00

110 lines
3.8 KiB
TypeScript

import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { parse } from "yaml";
const fullValidationPath = ".github/workflows/full-release-validation.yml";
const releaseChecksPath = ".github/workflows/openclaw-release-checks.yml";
type Step = { name?: string; run?: string };
type Job = { steps?: Step[] };
type Workflow = { jobs?: Record<string, Job> };
function workflow(path: string): Workflow {
return parse(readFileSync(path, "utf8")) as Workflow;
}
function stepRun(path: string, jobName: string, stepName: string): string {
const job = workflow(path).jobs?.[jobName];
const step = job?.steps?.find((candidate) => candidate.name === stepName);
if (!step?.run) {
throw new Error(`Missing workflow step: ${jobName} / ${stepName}`);
}
return step.run;
}
function runReleaseChecksTrustedRefGuard(workflowRef: string): ReturnType<typeof spawnSync> {
const guard = stepRun(
releaseChecksPath,
"resolve_target",
"Require trusted workflow ref for release checks",
);
return spawnSync("bash", ["-euo", "pipefail", "-c", guard], {
encoding: "utf8",
env: {
...process.env,
RELEASE_REF: "extended-stable/2026.6.33",
WORKFLOW_REF: workflowRef,
},
});
}
describe("extended-stable Full Release Validation workflow", () => {
it("lets the exact extended-stable branch reach every child at the target SHA", () => {
const fullValidation = readFileSync(fullValidationPath, "utf8");
const childDispatches = [
{
job: "normal_ci",
step: "Dispatch and monitor CI",
workflow: "ci.yml",
target: '-f target_ref="$TARGET_SHA"',
},
{
job: "plugin_prerelease",
step: "Dispatch and monitor plugin prerelease",
workflow: "plugin-prerelease.yml",
target: '-f target_ref="$TARGET_SHA" -f expected_sha="$TARGET_SHA"',
},
{
job: "release_checks",
step: "Dispatch and monitor release checks",
workflow: "openclaw-release-checks.yml",
target: '-f expected_sha="$TARGET_SHA"',
},
{
job: "performance",
step: "Dispatch and monitor OpenClaw Performance",
workflow: "openclaw-performance.yml",
target: '-f target_ref="$TARGET_SHA"',
},
];
for (const child of childDispatches) {
const run = stepRun(fullValidationPath, child.job, child.step);
expect(run).toContain(child.workflow);
expect(run).toContain('--ref "$CHILD_WORKFLOW_REF"');
expect(run).toContain(child.target);
}
expect(fullValidation).toContain("PARENT_WORKFLOW_SHA: ${{ github.sha }}");
expect(fullValidation).toContain('if [[ "$head_sha" != "$PARENT_WORKFLOW_SHA" ]]');
expect(fullValidation).toContain(
"child run used workflow SHA ${head_sha}, expected parent workflow SHA ${PARENT_WORKFLOW_SHA}",
);
});
it("accepts only the exact extended-stable/YYYY.M.33 workflow-ref shape", () => {
for (const valid of [
"refs/heads/extended-stable/2026.6.33",
"refs/heads/extended-stable/2026.12.33",
]) {
const result = runReleaseChecksTrustedRefGuard(valid);
expect(result.status, String(result.stderr)).toBe(0);
}
for (const invalid of [
"refs/heads/extended-stable/2026.0.33",
"refs/heads/extended-stable/2026.01.33",
"refs/heads/extended-stable/2026.13.33",
"refs/heads/extended-stable/2026.6.32",
"refs/heads/extended-stable/2026.6.34",
"refs/heads/extended-stable/2026.6.33/extra",
"refs/heads/extended-stable/not-a-release",
]) {
const result = runReleaseChecksTrustedRefGuard(invalid);
expect(result.status, invalid).not.toBe(0);
expect(result.stderr).toContain("extended-stable/YYYY.M.33");
}
});
});