mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:40:44 +00:00
test: strengthen release workflow contract coverage
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parse } from "yaml";
|
||||
|
||||
const PACKAGE_ACCEPTANCE_WORKFLOW = ".github/workflows/package-acceptance.yml";
|
||||
const LIVE_E2E_WORKFLOW = ".github/workflows/openclaw-live-and-e2e-checks-reusable.yml";
|
||||
@@ -10,6 +11,50 @@ const FULL_RELEASE_VALIDATION_WORKFLOW = ".github/workflows/full-release-validat
|
||||
const QA_LIVE_TRANSPORTS_WORKFLOW = ".github/workflows/qa-live-transports-convex.yml";
|
||||
const UPGRADE_SURVIVOR_RUN_SCRIPT = "scripts/e2e/lib/upgrade-survivor/run.sh";
|
||||
|
||||
type WorkflowStep = {
|
||||
env?: Record<string, string>;
|
||||
if?: string;
|
||||
name?: string;
|
||||
run?: string;
|
||||
uses?: string;
|
||||
with?: Record<string, string>;
|
||||
};
|
||||
|
||||
type WorkflowJob = {
|
||||
env?: Record<string, string>;
|
||||
if?: string;
|
||||
name?: string;
|
||||
needs?: string | string[];
|
||||
steps?: WorkflowStep[];
|
||||
};
|
||||
|
||||
type Workflow = {
|
||||
jobs?: Record<string, WorkflowJob>;
|
||||
};
|
||||
|
||||
function readWorkflow(path: string): Workflow {
|
||||
return parse(readFileSync(path, "utf8")) as Workflow;
|
||||
}
|
||||
|
||||
function workflowJob(path: string, jobName: string): WorkflowJob {
|
||||
const job = readWorkflow(path).jobs?.[jobName];
|
||||
expect(job, `expected workflow job ${jobName}`).toBeDefined();
|
||||
return job!;
|
||||
}
|
||||
|
||||
function workflowStep(job: WorkflowJob, stepName: string): WorkflowStep {
|
||||
const step = job.steps?.find((candidate) => candidate.name === stepName);
|
||||
expect(step, `expected workflow step ${stepName}`).toBeDefined();
|
||||
return step!;
|
||||
}
|
||||
|
||||
function expectTextToIncludeAll(text: string | undefined, snippets: string[]): void {
|
||||
expect(text).toBeDefined();
|
||||
for (const snippet of snippets) {
|
||||
expect(text).toContain(snippet);
|
||||
}
|
||||
}
|
||||
|
||||
describe("package acceptance workflow", () => {
|
||||
it("resolves candidate package sources before reusing Docker E2E lanes", () => {
|
||||
const workflow = readFileSync(PACKAGE_ACCEPTANCE_WORKFLOW, "utf8");
|
||||
@@ -447,32 +492,101 @@ describe("package artifact reuse", () => {
|
||||
|
||||
it("runs full release children from the trusted workflow ref", () => {
|
||||
const workflow = readFileSync(FULL_RELEASE_VALIDATION_WORKFLOW, "utf8");
|
||||
const npmTelegramJob = workflowJob(FULL_RELEASE_VALIDATION_WORKFLOW, "npm_telegram");
|
||||
const dispatchStep = workflowStep(npmTelegramJob, "Dispatch and monitor npm Telegram E2E");
|
||||
|
||||
expect(workflow).toContain("CHILD_WORKFLOW_REF: ${{ github.ref_name }}");
|
||||
expect(workflow).toContain('gh workflow run "$workflow" --ref "$CHILD_WORKFLOW_REF" "$@"');
|
||||
expect(workflow).toContain(
|
||||
expect(npmTelegramJob.name).toBe("Run package Telegram E2E");
|
||||
expect(npmTelegramJob.needs).toEqual(["resolve_target", "release_checks"]);
|
||||
expect(npmTelegramJob.if).toContain(
|
||||
"inputs.rerun_group == 'all' && inputs.release_profile == 'full'",
|
||||
);
|
||||
expect(dispatchStep.env).toMatchObject({
|
||||
RELEASE_CHECKS_RUN_ID: "${{ needs.release_checks.outputs.run_id }}",
|
||||
TARGET_SHA: "${{ needs.resolve_target.outputs.sha }}",
|
||||
});
|
||||
expectTextToIncludeAll(dispatchStep.run, [
|
||||
'gh workflow run npm-telegram-beta-e2e.yml --ref "$CHILD_WORKFLOW_REF" "${args[@]}"',
|
||||
);
|
||||
expect(workflow).toContain('-f harness_ref="$TARGET_SHA"');
|
||||
expect(workflow).toContain("needs: [resolve_target, release_checks]");
|
||||
expect(workflow).toContain("inputs.rerun_group == 'all' && inputs.release_profile == 'full'");
|
||||
expect(workflow).toContain("RELEASE_CHECKS_RUN_ID: ${{ needs.release_checks.outputs.run_id }}");
|
||||
expect(workflow).toContain("-f package_artifact_name=release-package-under-test");
|
||||
expect(workflow).toContain('-f package_artifact_run_id="$RELEASE_CHECKS_RUN_ID"');
|
||||
expect(workflow).toContain('-f package_label="full-release-${TARGET_SHA:0:12}"');
|
||||
expect(workflow).toContain("child_rerun_group=all");
|
||||
expect(workflow).toContain('-f rerun_group="$child_rerun_group"');
|
||||
expect(workflow).toContain('args+=(-f live_suite_filter="$LIVE_SUITE_FILTER")');
|
||||
expect(workflow).toContain(
|
||||
'-f harness_ref="$TARGET_SHA"',
|
||||
'args=(-f package_spec="${PACKAGE_SPEC:-openclaw@beta}"',
|
||||
'if [[ -z "${PACKAGE_SPEC// }" ]]; then',
|
||||
"-f package_artifact_name=release-package-under-test",
|
||||
'-f package_artifact_run_id="$RELEASE_CHECKS_RUN_ID"',
|
||||
'-f package_label="full-release-${TARGET_SHA:0:12}"',
|
||||
'args+=(-f scenario="$SCENARIO")',
|
||||
]);
|
||||
expectTextToIncludeAll(workflow, [
|
||||
"child_rerun_group=all",
|
||||
'-f rerun_group="$child_rerun_group"',
|
||||
'args+=(-f live_suite_filter="$LIVE_SUITE_FILTER")',
|
||||
"cancel-in-progress: ${{ inputs.ref == 'main' && inputs.rerun_group == 'all' }}",
|
||||
);
|
||||
expect(workflow).toContain("gh run cancel");
|
||||
"gh run cancel",
|
||||
"NORMAL_CI_RESULT: ${{ needs.normal_ci.result }}",
|
||||
]);
|
||||
expect(workflow).not.toContain("force-cancel");
|
||||
expect(workflow).toContain("NORMAL_CI_RESULT: ${{ needs.normal_ci.result }}");
|
||||
expect(workflow).not.toContain("workflow_ref:");
|
||||
expect(workflow).not.toContain("inputs.workflow_ref");
|
||||
});
|
||||
|
||||
it("documents the full-release Telegram package path in operator summaries", () => {
|
||||
const workflow = readFileSync(FULL_RELEASE_VALIDATION_WORKFLOW, "utf8");
|
||||
const releaseDocs = readFileSync("docs/reference/RELEASING.md", "utf8");
|
||||
const fullReleaseDocs = readFileSync("docs/reference/full-release-validation.md", "utf8");
|
||||
|
||||
expectTextToIncludeAll(workflow, [
|
||||
"Published-package Telegram E2E:",
|
||||
"Package Telegram E2E: release package artifact from \\`OpenClaw Release Checks\\`",
|
||||
"Package Telegram E2E: skipped unless \\`release_profile=full\\` or \\`npm_telegram_package_spec\\` is provided",
|
||||
]);
|
||||
expect(releaseDocs).toContain(
|
||||
"Focused `npm-telegram` reruns require `npm_telegram_package_spec`",
|
||||
);
|
||||
expectTextToIncludeAll(fullReleaseDocs, [
|
||||
"full pre-publish candidate",
|
||||
"silently skip that",
|
||||
"Telegram package lane",
|
||||
"| `npm-telegram` | Published-package Telegram E2E; requires `npm_telegram_package_spec`. |",
|
||||
]);
|
||||
});
|
||||
|
||||
it("lets npm Telegram consume current-run or release-run package artifacts", () => {
|
||||
const job = workflowJob(NPM_TELEGRAM_WORKFLOW, "run_package_telegram_e2e");
|
||||
const currentRunDownload = workflowStep(job, "Download package-under-test artifact");
|
||||
const releaseRunDownload = workflowStep(
|
||||
job,
|
||||
"Download package-under-test artifact from release run",
|
||||
);
|
||||
const validateStep = workflowStep(job, "Validate inputs and secrets");
|
||||
const runStep = workflowStep(job, "Run package Telegram E2E");
|
||||
|
||||
expect(currentRunDownload).toMatchObject({
|
||||
if: "inputs.package_artifact_name != '' && inputs.package_artifact_run_id == ''",
|
||||
uses: "actions/download-artifact@v8",
|
||||
with: {
|
||||
name: "${{ inputs.package_artifact_name }}",
|
||||
path: ".artifacts/telegram-package-under-test",
|
||||
},
|
||||
});
|
||||
expect(releaseRunDownload).toMatchObject({
|
||||
if: "inputs.package_artifact_name != '' && inputs.package_artifact_run_id != ''",
|
||||
uses: "actions/download-artifact@v8",
|
||||
with: {
|
||||
"github-token": "${{ github.token }}",
|
||||
name: "${{ inputs.package_artifact_name }}",
|
||||
path: ".artifacts/telegram-package-under-test",
|
||||
"run-id": "${{ inputs.package_artifact_run_id }}",
|
||||
},
|
||||
});
|
||||
expectTextToIncludeAll(validateStep.run, [
|
||||
'if [[ -z "${PACKAGE_ARTIFACT_NAME// }" ]]; then',
|
||||
"package_spec must be openclaw@beta",
|
||||
]);
|
||||
expectTextToIncludeAll(runStep.run, [
|
||||
'export OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ="${package_tgzs[0]}"',
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps release QA and repo E2E lanes off scarce 32-core runners", () => {
|
||||
const releaseChecksWorkflow = readFileSync(RELEASE_CHECKS_WORKFLOW, "utf8");
|
||||
const qaWorkflow = readFileSync(QA_LIVE_TRANSPORTS_WORKFLOW, "utf8");
|
||||
|
||||
Reference in New Issue
Block a user