mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-08 19:12:22 +00:00
fix(release): isolate private Telegram QA harness (#120088)
This commit is contained in:
10
.github/workflows/npm-telegram-beta-e2e.yml
vendored
10
.github/workflows/npm-telegram-beta-e2e.yml
vendored
@@ -231,6 +231,16 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
install-bun: "true"
|
||||
|
||||
- name: Build private QA harness runtime
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
OPENCLAW_BUILD_PRIVATE_QA: "1"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node scripts/build-all.mjs qaRuntime
|
||||
test -f dist/plugin-sdk/qa-runtime.js
|
||||
test -f dist/extensions/qa-lab/runtime-api.js
|
||||
|
||||
- name: Validate inputs and secrets
|
||||
env:
|
||||
PACKAGE_SPEC: ${{ inputs.package_spec }}
|
||||
|
||||
2
.github/workflows/package-acceptance.yml
vendored
2
.github/workflows/package-acceptance.yml
vendored
@@ -930,7 +930,7 @@ jobs:
|
||||
package_source_sha: ${{ needs.resolve_package.outputs.package_source_sha }}
|
||||
package_version: ${{ needs.resolve_package.outputs.package_version }}
|
||||
package_label: openclaw@${{ needs.resolve_package.outputs.package_version }}
|
||||
harness_ref: ${{ needs.resolve_package.outputs.package_source_sha || inputs.workflow_ref }}
|
||||
harness_ref: ${{ inputs.workflow_ref }}
|
||||
provider_mode: ${{ needs.resolve_package.outputs.telegram_mode }}
|
||||
scenario: ${{ inputs.telegram_scenarios }}
|
||||
secrets:
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
// Prepares package manifests for npm Telegram live E2E scenarios.
|
||||
import fs from "node:fs";
|
||||
|
||||
for (const packageJsonPath of process.argv.slice(2)) {
|
||||
const packageJsonPaths = process.argv.slice(2);
|
||||
if (packageJsonPaths.length !== 2) {
|
||||
throw new Error(
|
||||
`expected exactly two ephemeral package manifests, got ${packageJsonPaths.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
for (const packageJsonPath of packageJsonPaths) {
|
||||
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
||||
pkg.exports = pkg.exports && typeof pkg.exports === "object" ? pkg.exports : {};
|
||||
if (!pkg.exports["./plugin-sdk/gateway-runtime"]) {
|
||||
@@ -10,5 +17,10 @@ for (const packageJsonPath of process.argv.slice(2)) {
|
||||
default: "./dist/plugin-sdk/gateway-runtime.js",
|
||||
};
|
||||
}
|
||||
if (!pkg.exports["./plugin-sdk/qa-runtime"]) {
|
||||
pkg.exports["./plugin-sdk/qa-runtime"] = {
|
||||
default: "./.openclaw-qa-harness-dist/plugin-sdk/qa-runtime.js",
|
||||
};
|
||||
}
|
||||
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
||||
}
|
||||
|
||||
@@ -414,6 +414,7 @@ run_logged_print_heartbeat "npm-telegram-live-suite" 60 docker_e2e_run_with_harn
|
||||
"${docker_env[@]}" \
|
||||
-v "$ROOT_DIR/.artifacts:/app/.artifacts" \
|
||||
-v "$OUTPUT_DIR_HOST:$OUTPUT_DIR_CONTAINER" \
|
||||
-v "$ROOT_DIR/dist:/app/.openclaw-qa-harness-dist:ro" \
|
||||
-v "$ROOT_DIR/extensions/qa-lab:/app/extensions/qa-lab:ro" \
|
||||
-v "$ROOT_DIR/qa/scenarios:/app/qa/scenarios:ro" \
|
||||
-v "$npm_prefix_host:/npm-global" \
|
||||
@@ -453,6 +454,8 @@ rm -rf /app/node_modules/openclaw
|
||||
ln -sfnT "$openclaw_package_dir" /app/node_modules/openclaw
|
||||
rm -rf /app/dist
|
||||
ln -sfnT "$openclaw_package_dir/dist" /app/dist
|
||||
rm -rf "$openclaw_package_dir/.openclaw-qa-harness-dist"
|
||||
ln -sfnT /app/.openclaw-qa-harness-dist "$openclaw_package_dir/.openclaw-qa-harness-dist"
|
||||
cp "$openclaw_package_dir/package.json" /app/package.json
|
||||
node scripts/e2e/lib/npm-telegram-live/prepare-package.mjs \
|
||||
/app/package.json \
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Npm Telegram Live tests cover npm telegram live script behavior.
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -267,7 +268,7 @@ describe("package Telegram live Docker E2E", () => {
|
||||
expect(script).toContain("OPENCLAW_NPM_TELEGRAM_RTT_CHECKS");
|
||||
});
|
||||
|
||||
it("keeps private QA harness imports local while using the installed package dist", () => {
|
||||
it("keeps candidate runtime authoritative while mounting private QA dist separately", () => {
|
||||
const script = readFileSync(DOCKER_SCRIPT_PATH, "utf8");
|
||||
const preparePackage = readFileSync(PREPARE_PACKAGE_PATH, "utf8");
|
||||
const gatewayRpcClient = readFileSync(
|
||||
@@ -278,15 +279,12 @@ describe("package Telegram live Docker E2E", () => {
|
||||
path.resolve(TEST_DIR, "../../extensions/qa-lab/src/runtime-api.ts"),
|
||||
"utf8",
|
||||
);
|
||||
const qaHarnessSources = [
|
||||
"extensions/qa-lab/api.ts",
|
||||
"extensions/qa-lab/src/self-check.ts",
|
||||
"extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts",
|
||||
"extensions/qa-lab/src/suite-launch.runtime.ts",
|
||||
"extensions/qa-lab/src/suite.ts",
|
||||
].map((relativePath) => readFileSync(path.resolve(TEST_DIR, "../..", relativePath), "utf8"));
|
||||
|
||||
expect(script).toContain('ln -sfnT "$openclaw_package_dir/dist" /app/dist');
|
||||
expect(script).toContain('-v "$ROOT_DIR/dist:/app/.openclaw-qa-harness-dist:ro"');
|
||||
expect(script).toContain(
|
||||
'ln -sfnT /app/.openclaw-qa-harness-dist "$openclaw_package_dir/.openclaw-qa-harness-dist"',
|
||||
);
|
||||
expect(script).toContain('cp "$openclaw_package_dir/package.json" /app/package.json');
|
||||
expect(script).toContain('-v "$ROOT_DIR/extensions/qa-lab:/app/extensions/qa-lab:ro"');
|
||||
expect(script).toContain('-v "$ROOT_DIR/qa/scenarios:/app/qa/scenarios:ro"');
|
||||
@@ -295,11 +293,55 @@ describe("package Telegram live Docker E2E", () => {
|
||||
expect(script).toContain("/app/node_modules/openclaw/package.json");
|
||||
expect(preparePackage).toContain('pkg.exports["./plugin-sdk/gateway-runtime"]');
|
||||
expect(preparePackage).toContain('"./dist/plugin-sdk/gateway-runtime.js"');
|
||||
expect(preparePackage).toContain('pkg.exports["./plugin-sdk/qa-runtime"]');
|
||||
expect(preparePackage).toContain('"./.openclaw-qa-harness-dist/plugin-sdk/qa-runtime.js"');
|
||||
expect(gatewayRpcClient).toContain('from "openclaw/plugin-sdk/gateway-runtime"');
|
||||
expect(qaRuntimeApi).toContain('from "openclaw/plugin-sdk/gateway-runtime"');
|
||||
for (const source of qaHarnessSources) {
|
||||
expect(source).not.toContain('from "openclaw/plugin-sdk/qa-runtime"');
|
||||
});
|
||||
|
||||
it("adds private harness exports only to two ephemeral manifests", () => {
|
||||
const root = mkTempRoot();
|
||||
const packageJsonPaths = ["root-package.json", "installed-package.json"].map((name) =>
|
||||
path.join(root, name),
|
||||
);
|
||||
for (const packageJsonPath of packageJsonPaths) {
|
||||
writeFileSync(packageJsonPath, JSON.stringify({ exports: { ".": "./dist/index.js" } }));
|
||||
}
|
||||
|
||||
const result = spawnSync(process.execPath, [PREPARE_PACKAGE_PATH, ...packageJsonPaths], {
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
for (const packageJsonPath of packageJsonPaths) {
|
||||
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8")) as {
|
||||
exports: Record<string, unknown>;
|
||||
};
|
||||
expect(pkg.exports).toMatchObject({
|
||||
".": "./dist/index.js",
|
||||
"./plugin-sdk/gateway-runtime": {
|
||||
types: "./dist/plugin-sdk/gateway-runtime.d.ts",
|
||||
default: "./dist/plugin-sdk/gateway-runtime.js",
|
||||
},
|
||||
"./plugin-sdk/qa-runtime": {
|
||||
default: "./.openclaw-qa-harness-dist/plugin-sdk/qa-runtime.js",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const thirdPackageJsonPath = path.join(root, "third-package.json");
|
||||
writeFileSync(thirdPackageJsonPath, JSON.stringify({ exports: { ".": "./dist/index.js" } }));
|
||||
const rejected = spawnSync(
|
||||
process.execPath,
|
||||
[PREPARE_PACKAGE_PATH, ...packageJsonPaths, thirdPackageJsonPath],
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
|
||||
expect(rejected.status).toBe(1);
|
||||
expect(rejected.stderr).toContain("expected exactly two ephemeral package manifests, got 3");
|
||||
expect(JSON.parse(readFileSync(thirdPackageJsonPath, "utf8"))).toEqual({
|
||||
exports: { ".": "./dist/index.js" },
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes installed package dependencies to the mounted QA harness", () => {
|
||||
|
||||
@@ -1574,6 +1574,10 @@ describe("package acceptance workflow", () => {
|
||||
it("offers bounded product profiles and can run Telegram against the resolved artifact", () => {
|
||||
const workflow = readFileSync(PACKAGE_ACCEPTANCE_WORKFLOW, "utf8");
|
||||
const npmTelegramWorkflow = readFileSync(NPM_TELEGRAM_WORKFLOW, "utf8");
|
||||
const packageTelegram = workflowJob(PACKAGE_ACCEPTANCE_WORKFLOW, "package_telegram");
|
||||
const dockerAcceptance = workflowJob(PACKAGE_ACCEPTANCE_WORKFLOW, "docker_acceptance");
|
||||
const npmTelegram = workflowJob(NPM_TELEGRAM_WORKFLOW, "run_package_telegram_e2e");
|
||||
const buildPrivateQa = workflowStep(npmTelegram, "Build private QA harness runtime");
|
||||
|
||||
expect(workflow).toContain("suite_profile:");
|
||||
expect(workflow).toContain("published_upgrade_survivor_baseline:");
|
||||
@@ -1638,9 +1642,19 @@ describe("package acceptance workflow", () => {
|
||||
expect(workflow).toContain(
|
||||
"package_source_sha: ${{ steps.resolve.outputs.package_source_sha }}",
|
||||
);
|
||||
expect(workflow).toContain(
|
||||
"harness_ref: ${{ needs.resolve_package.outputs.package_source_sha || inputs.workflow_ref }}",
|
||||
expect(packageTelegram.with?.harness_ref).toBe("${{ inputs.workflow_ref }}");
|
||||
expect(dockerAcceptance.with?.ref).toBe(
|
||||
"${{ needs.resolve_package.outputs.package_source_sha || inputs.workflow_ref }}",
|
||||
);
|
||||
expect(buildPrivateQa.env).toMatchObject({
|
||||
NODE_OPTIONS: "--max-old-space-size=8192",
|
||||
OPENCLAW_BUILD_PRIVATE_QA: "1",
|
||||
});
|
||||
expectTextToIncludeAll(buildPrivateQa.run, [
|
||||
"node scripts/build-all.mjs qaRuntime",
|
||||
"test -f dist/plugin-sdk/qa-runtime.js",
|
||||
"test -f dist/extensions/qa-lab/runtime-api.js",
|
||||
]);
|
||||
expect(workflow).toContain('fallback_version="$(npm view openclaw@latest version)"');
|
||||
expect(workflow).toContain('echo "baseline=$fallback_baseline" >> "$GITHUB_OUTPUT"');
|
||||
expect(workflow).toContain(
|
||||
|
||||
Reference in New Issue
Block a user