mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
chore: scope SQLite session lifecycle CI (#121917)
* oc-358: scope SQLite lifecycle CI * chore(ci): cover shared session lifecycle owner
This commit is contained in:
+50
-13
@@ -93,6 +93,7 @@ jobs:
|
||||
frozen_target: ${{ steps.manifest.outputs.frozen_target }}
|
||||
run_qa_smoke_ci: ${{ steps.manifest.outputs.run_qa_smoke_ci }}
|
||||
run_prompt_snapshots: ${{ steps.manifest.outputs.run_prompt_snapshots }}
|
||||
run_sqlite_session_lifecycle: ${{ steps.manifest.outputs.run_sqlite_session_lifecycle }}
|
||||
checks_fast_core_matrix: ${{ steps.manifest.outputs.checks_fast_core_matrix }}
|
||||
run_plugin_contracts_shards: ${{ steps.manifest.outputs.run_plugin_contracts_shards }}
|
||||
plugin_contracts_matrix: ${{ steps.manifest.outputs.plugin_contracts_matrix }}
|
||||
@@ -681,7 +682,20 @@ jobs:
|
||||
eventName !== "pull_request" ||
|
||||
typeof changedNodeTestPlan.hasPromptSnapshotAffectingChange !== "function" ||
|
||||
changedNodeTestPlan.hasPromptSnapshotAffectingChange(changedPaths);
|
||||
const runBuildArtifacts = runNodeFull && changedScopeHasBuildImpact;
|
||||
const supportsSqliteSessionLifecycleProof = existsSync(
|
||||
"test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts",
|
||||
);
|
||||
const changedScopeHasSqliteSessionLifecycleImpact =
|
||||
changedPaths === null ||
|
||||
eventName === "workflow_dispatch" ||
|
||||
typeof changedNodeTestPlan.hasSqliteSessionLifecycleAffectingChange !== "function" ||
|
||||
changedNodeTestPlan.hasSqliteSessionLifecycleAffectingChange(changedPaths);
|
||||
const runSqliteSessionLifecycle =
|
||||
runNodeFull &&
|
||||
supportsSqliteSessionLifecycleProof &&
|
||||
changedScopeHasSqliteSessionLifecycleImpact;
|
||||
const runBuildArtifacts =
|
||||
runNodeFull && (changedScopeHasBuildImpact || runSqliteSessionLifecycle);
|
||||
const runQaSmokeCi =
|
||||
runNodeFull &&
|
||||
changedScopeHasQaImpact &&
|
||||
@@ -752,6 +766,7 @@ jobs:
|
||||
compatibility_target: compatibilityTarget,
|
||||
run_qa_smoke_ci: runQaSmokeCi,
|
||||
run_prompt_snapshots: runNodeFull && changedScopeHasPromptSnapshotImpact,
|
||||
run_sqlite_session_lifecycle: runSqliteSessionLifecycle,
|
||||
checks_fast_core_matrix: createMatrix(checksFastCoreTasks),
|
||||
run_plugin_contracts_shards: runPluginContractShards,
|
||||
plugin_contracts_matrix: createMatrix(
|
||||
@@ -1437,6 +1452,38 @@ jobs:
|
||||
path: .local/gateway-watch-regression/
|
||||
retention-days: 7
|
||||
|
||||
sqlite-session-lifecycle:
|
||||
permissions:
|
||||
contents: read
|
||||
name: check-sqlite-session-lifecycle
|
||||
needs: [preflight, build-artifacts]
|
||||
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_sqlite_session_lifecycle == 'true' && needs.build-artifacts.result == 'success' }}
|
||||
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- *linux_node_checkout_step
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
install-bun: "false"
|
||||
sticky-disk: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'true' || 'false' }}
|
||||
use-actions-cache: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'openclaw/openclaw') && 'false' || 'true' }}
|
||||
|
||||
- name: Download exact-run built runtime
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: dist-runtime-build
|
||||
path: .artifacts/dist-runtime-build
|
||||
|
||||
- name: Extract built runtime
|
||||
run: tar --extract --file .artifacts/dist-runtime-build/dist-runtime-build.tar.zst --use-compress-program unzstd
|
||||
|
||||
- name: Verify SQLite session lifecycle
|
||||
env:
|
||||
OPENCLAW_E2E_USE_PREBUILT_DIST: "1"
|
||||
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: "660000"
|
||||
run: node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts
|
||||
|
||||
native-i18n:
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -2545,9 +2592,6 @@ jobs:
|
||||
- check_name: check-plugin-sdk-api-baseline
|
||||
group: plugin-sdk-api-baseline
|
||||
runner: blacksmith-4vcpu-ubuntu-2404
|
||||
- check_name: check-sqlite-session-flip-proof
|
||||
group: sqlite-session-flip-proof
|
||||
runner: blacksmith-8vcpu-ubuntu-2404
|
||||
- check_name: check-additional-extension-package-boundary
|
||||
group: extension-package-boundary
|
||||
# Light-run critical-path pole: cold runs spend ~100s in nine
|
||||
@@ -2774,15 +2818,6 @@ jobs:
|
||||
plugin-sdk-api-baseline)
|
||||
run_check "plugin-sdk:api:check" pnpm run plugin-sdk:api:check
|
||||
;;
|
||||
sqlite-session-flip-proof)
|
||||
if [ ! -f test/scripts/sqlite-sessions-transcripts-flip-proof.e2e.test.ts ]; then
|
||||
echo "[skip] SQLite sessions/transcripts flip proof is not present in this checkout"
|
||||
else
|
||||
# This lane owns a 420-second E2E case plus cold hosted-runner setup;
|
||||
# keep the global watchdog strict and scope compatibility headroom here.
|
||||
run_check "sqlite sessions/transcripts flip proof" env OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=660000 node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts test/scripts/sqlite-sessions-transcripts-flip-proof.e2e.test.ts
|
||||
fi
|
||||
;;
|
||||
extension-package-boundary)
|
||||
run_check "test:extensions:package-boundary:compile" pnpm run test:extensions:package-boundary:compile
|
||||
run_check "test:extensions:package-boundary:canary" pnpm run test:extensions:package-boundary:canary
|
||||
@@ -3751,6 +3786,7 @@ jobs:
|
||||
- security-fast
|
||||
- pnpm-store-warmup
|
||||
- build-artifacts
|
||||
- sqlite-session-lifecycle
|
||||
- native-i18n
|
||||
- checks-ui
|
||||
- checks-ui-e2e
|
||||
@@ -3784,6 +3820,7 @@ jobs:
|
||||
SELECTED_RESULTS: |
|
||||
pnpm-store-warmup=${{ needs.pnpm-store-warmup.result }}
|
||||
build-artifacts=${{ needs.build-artifacts.result }}
|
||||
sqlite-session-lifecycle=${{ needs.sqlite-session-lifecycle.result }}
|
||||
native-i18n=${{ needs.native-i18n.result }}
|
||||
checks-ui=${{ needs.checks-ui.result }}
|
||||
checks-ui-e2e=${{ needs.checks-ui-e2e.result }}
|
||||
|
||||
+10
-9
@@ -102,6 +102,7 @@ Separate iOS and macOS Periphery workflows enforce a zero-findings dead-code pol
|
||||
- **Workflow Sanity** runs `actionlint`, `zizmor` over all workflow YAML files, the composite-action interpolation guard, and the conflict-marker guard. The PR-scoped `security-fast` job also runs `zizmor` over changed workflow files so workflow security findings fail early in the main CI graph.
|
||||
- **Docs on `main` pushes** are checked by the standalone `Docs` workflow with the same ClawHub docs mirror used by CI, so mixed code+docs pushes do not also queue the CI `check-docs` shard. Pull requests and manual CI still run `check-docs` from CI when docs changed.
|
||||
- **TUI PTY** splits by proof ownership. The dedicated `core-runtime-tui-pty` Node shard owns the full real-backend suite against the exact-head built CLI. The `build-artifacts` job keeps only a local model roundtrip and a real Gateway connection canary, so every artifact boundary proves the built launcher without duplicating the full serial suite inside the build job.
|
||||
- **SQLite session lifecycle** runs the built-CLI migration, restart, compaction, cleanup, and session RPC proof only when the diff touches its direct storage/session owners or a reachable session path in the embedded runner. The dedicated `check-sqlite-session-lifecycle` job downloads the exact runtime produced by `build-artifacts`; manual and release dispatches always select it when the target contains the proof.
|
||||
- **CI routing-only edits, the small set of core-test fixtures the fast task runs directly, and narrow plugin contract helper edits** use a fast Node-only manifest path: `preflight`, `security-fast`, and only the fast lanes the change touches — a single `checks-fast-core` CI-routing task, the two plugin contract shards, or both. That path skips build artifacts, Node 22 compatibility, channel contracts, full core shards, bundled-plugin shards, and additional guard matrices.
|
||||
- **Windows Node checks** are scoped to Windows-specific process/path wrappers, npm/pnpm/UI runner helpers, package manager config, and the CI workflow surfaces that execute that lane; unrelated source, plugin, install-smoke, and test-only changes stay on the Linux Node lanes.
|
||||
|
||||
@@ -182,15 +183,15 @@ for commands and recovery.
|
||||
|
||||
## Runners
|
||||
|
||||
| Runner | Jobs |
|
||||
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ubuntu-24.04` | `security-fast`, manual CI dispatch and non-canonical repository fallbacks, pull-request retries of both UI E2E jobs, the QA Smoke aggregate, CodeQL security and quality scans, workflow-sanity, labeler, auto-response, the standalone Docs workflow, and the whole Install Smoke workflow |
|
||||
| `blacksmith-4vcpu-ubuntu-2404` | `preflight`, `pnpm-store-warmup`, `native-i18n`, `checks-fast-core` except QA Smoke CI, plugin/channel contract shards, most bundled/lower-weight Linux Node shards, `check-*` lanes except `check-lint`, selected `check-additional-*` shards, `check-docs`, and `skills-python` |
|
||||
| `blacksmith-8vcpu-ubuntu-2404` | Retained heavy Linux Node suites, first-attempt same-repo pull requests and pushes for the serial Chromium/Vite `checks-ui-e2e` lane (three Control UI shards plus one browser extension shard), boundary/extension-heavy `check-additional-*` shards, and `android` |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | Automatic QA Smoke CI shards, first-attempt same-repo pull requests and pushes for `checks-ui-e2e-real-gateway`, `build-artifacts` in CI and Testbox, and `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved) |
|
||||
| `blacksmith-8vcpu-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` and `ios-build` on `openclaw/openclaw`; forks fall back to `macos-26` |
|
||||
| Runner | Jobs |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `ubuntu-24.04` | `security-fast`, manual CI dispatch and non-canonical repository fallbacks, pull-request retries of both UI E2E jobs, the QA Smoke aggregate, CodeQL security and quality scans, workflow-sanity, labeler, auto-response, the standalone Docs workflow, and the whole Install Smoke workflow |
|
||||
| `blacksmith-4vcpu-ubuntu-2404` | `preflight`, `pnpm-store-warmup`, `native-i18n`, `checks-fast-core` except QA Smoke CI, plugin/channel contract shards, most bundled/lower-weight Linux Node shards, `check-*` lanes except `check-lint`, selected `check-additional-*` shards, `check-docs`, and `skills-python` |
|
||||
| `blacksmith-8vcpu-ubuntu-2404` | Retained heavy Linux Node suites, first-attempt same-repo pull requests and pushes for the serial Chromium/Vite `checks-ui-e2e` lane (three Control UI shards plus one browser extension shard), boundary/extension-heavy `check-additional-*` shards, `check-sqlite-session-lifecycle`, and `android` |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | Automatic QA Smoke CI shards, first-attempt same-repo pull requests and pushes for `checks-ui-e2e-real-gateway`, `build-artifacts` in CI and Testbox, and `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved) |
|
||||
| `blacksmith-8vcpu-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` and `ios-build` on `openclaw/openclaw`; forks fall back to `macos-26` |
|
||||
|
||||
## Runner registration budget
|
||||
|
||||
|
||||
@@ -148,6 +148,52 @@ export function hasPromptSnapshotAffectingChange(changedPaths: string[], options
|
||||
return hasImportGraphImpactOnTargets(sourcePaths, [PROMPT_SNAPSHOT_ENTRY], cwd);
|
||||
}
|
||||
|
||||
// The lifecycle proof crosses dynamic Gateway method registration, doctor
|
||||
// migrations, shared session coordination, the public session SDK, and the
|
||||
// built CLI. Keep those owners on the direct surface; use the import graph only
|
||||
// inside the embedded-runner neighborhood, whose session reachability is not
|
||||
// apparent from filenames.
|
||||
const SQLITE_SESSION_LIFECYCLE_PREFIX_RE =
|
||||
/^(?:src\/(?:agents\/(?:sessions\/|[^/]*(?:session|transcript|compaction)[^/]*)|commands\/doctor-session-|config\/sessions\/|gateway\/(?:agent-turn\/agent-session-persist|server-chat\.(?:load-gateway-session-row|persist-session-lifecycle)|server-methods\/sessions|server\.sessions|session-|sessions-)|plugin-sdk\/session-|sessions\/|state\/openclaw-agent-(?:db|schema))|\.github\/actions\/setup-node-env\/)/u;
|
||||
const SQLITE_SESSION_LIFECYCLE_EXACT_RE =
|
||||
/^(?:src\/config\/sessions\.ts|test\/helpers\/(?:openclaw-test-instance|sqlite-sessions-transcripts-flip-proof(?:-assertions)?)\.ts|test\/scripts\/(?:sqlite-sessions-transcripts-flip-proof(?:\.built-cli)?\.e2e\.test|vitest-e2e-global-setup\.test)\.ts|test\/vitest\/vitest\.e2e\.(?:config|global-setup)\.ts|scripts\/lib\/ci-changed-node-test-plan\.mts|\.github\/workflows\/ci\.yml|openclaw\.mjs|package\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml)$/u;
|
||||
const SQLITE_SESSION_LIFECYCLE_ENTRY =
|
||||
"test/scripts/sqlite-sessions-transcripts-flip-proof.e2e.test.ts";
|
||||
const SQLITE_SESSION_LIFECYCLE_IMPORT_CANDIDATE_RE = /^src\/agents\/embedded-agent-runner\/run\//u;
|
||||
|
||||
/**
|
||||
* True when a changed path touches a SQLite session lifecycle owner or reaches
|
||||
* the proof from the embedded-runner neighborhood.
|
||||
*/
|
||||
export function hasSqliteSessionLifecycleAffectingChange(
|
||||
changedPaths: string[],
|
||||
options: CwdOptions = {},
|
||||
) {
|
||||
const cwd = options.cwd ?? process.cwd();
|
||||
if (
|
||||
changedPaths.some(
|
||||
(changedPath) =>
|
||||
(!isTestFileTarget(changedPath) && SQLITE_SESSION_LIFECYCLE_PREFIX_RE.test(changedPath)) ||
|
||||
SQLITE_SESSION_LIFECYCLE_EXACT_RE.test(changedPath),
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
const sourcePaths = changedPaths.filter(
|
||||
(changedPath) =>
|
||||
SQLITE_SESSION_LIFECYCLE_IMPORT_CANDIDATE_RE.test(changedPath) &&
|
||||
!isTestFileTarget(changedPath),
|
||||
);
|
||||
// Deleted sources cannot be graphed; fail safe to running the lifecycle proof.
|
||||
if (sourcePaths.some((changedPath) => !existsSync(path.join(cwd, changedPath)))) {
|
||||
return true;
|
||||
}
|
||||
if (sourcePaths.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return hasImportGraphImpactOnTargets(sourcePaths, [SQLITE_SESSION_LIFECYCLE_ENTRY], cwd);
|
||||
}
|
||||
|
||||
function createBoundaryShard() {
|
||||
// Boundary tests scan the source tree (including test files) and build
|
||||
// their own fixtures; they do not consume the built dist artifact. When the
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
hasBuildArtifactAffectingChange,
|
||||
hasPromptSnapshotAffectingChange,
|
||||
hasQaSmokeAffectingChange,
|
||||
hasSqliteSessionLifecycleAffectingChange,
|
||||
} from "../../scripts/lib/ci-changed-node-test-plan.mts";
|
||||
import { hasImportGraphImpactOnTargets } from "../../scripts/test-projects.test-support.mts";
|
||||
import { listGitTrackedFiles } from "../../src/test-utils/repo-files.js";
|
||||
@@ -135,6 +136,46 @@ describe("CI changed Node test plan", () => {
|
||||
expect(hasPromptSnapshotAffectingChange(["src/infra/definitely-deleted-module.ts"])).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies SQLite session lifecycle impact by owner and import graph", () => {
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange([
|
||||
"src/agents/embedded-agent-runner/run/attempt-session-runtime-prepare.ts",
|
||||
]),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange(["src/gateway/server-methods/sessions.ts"]),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange(["src/sessions/session-lifecycle-admission.ts"]),
|
||||
).toBe(true);
|
||||
expect(hasSqliteSessionLifecycleAffectingChange(["src/config/sessions.ts"])).toBe(true);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange([
|
||||
"test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts",
|
||||
]),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange(["src/media-understanding/provider-id.ts"]),
|
||||
).toBe(false);
|
||||
expect(hasSqliteSessionLifecycleAffectingChange(["src/agents/model-auth.ts"])).toBe(false);
|
||||
expect(hasSqliteSessionLifecycleAffectingChange(["extensions/discord/src/index.ts"])).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange([
|
||||
"src/config/sessions/session-registry-maintenance.test.ts",
|
||||
]),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange(["src/infra/definitely-deleted-module.ts"]),
|
||||
).toBe(false);
|
||||
expect(
|
||||
hasSqliteSessionLifecycleAffectingChange([
|
||||
"src/agents/embedded-agent-runner/run/deleted-session-runtime.ts",
|
||||
]),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("fails safe to the full plan for broad changes", () => {
|
||||
expect(createChangedNodeTestShards(["package.json"])).toBeNull();
|
||||
});
|
||||
|
||||
@@ -248,19 +248,33 @@ function runCiManifestFixture(options: {
|
||||
? `throw new Error("planner import failure");\n`
|
||||
: `
|
||||
export const createChangedNodeTestShards = (changedPaths) =>
|
||||
changedPaths.includes("src/focused.ts")
|
||||
changedPaths.includes("src/focused.ts") ||
|
||||
changedPaths.includes("test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts")
|
||||
? [{
|
||||
checkName: "changed-node-plan",
|
||||
configs: [],
|
||||
requiresDist: false,
|
||||
runner: "ubuntu-24.04",
|
||||
shardName: "changed-node-plan",
|
||||
targets: ["src/focused.test.ts"],
|
||||
targets: changedPaths.includes("src/focused.ts")
|
||||
? ["src/focused.test.ts"]
|
||||
: ["test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts"],
|
||||
}]
|
||||
: null;
|
||||
export const hasBuildArtifactAffectingChange = (changedPaths) =>
|
||||
!changedPaths.includes("test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts");
|
||||
export const hasSqliteSessionLifecycleAffectingChange = (changedPaths) =>
|
||||
changedPaths.includes("src/sqlite-session-owner.ts") ||
|
||||
changedPaths.includes("test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts");
|
||||
`,
|
||||
"utf8",
|
||||
);
|
||||
const sqliteLifecycleProof = path.join(
|
||||
root,
|
||||
"test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts",
|
||||
);
|
||||
mkdirSync(path.dirname(sqliteLifecycleProof), { recursive: true });
|
||||
writeFileSync(sqliteLifecycleProof, "export {};\n");
|
||||
writeFileSync(
|
||||
path.join(scriptsDir, "channel-contract-test-plan.mts"),
|
||||
`export const createChannelContractTestShards = () => [{ checkName: "channel-contracts" }];\n`,
|
||||
@@ -2866,6 +2880,7 @@ NODE
|
||||
"control-ui-i18n",
|
||||
"native-i18n",
|
||||
"qa-smoke-ci-profile",
|
||||
"sqlite-session-lifecycle",
|
||||
]);
|
||||
const hostedRetryJobs = new Set(["checks-ui-e2e", "checks-ui-e2e-real-gateway"]);
|
||||
for (const { jobName, stepWith } of stickyConsumers) {
|
||||
@@ -5151,6 +5166,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
expect(current.outputs.run_native_i18n).toBe("true");
|
||||
expect(current.outputs.run_openclawkit_tests).toBe("true");
|
||||
expect(current.outputs.run_qa_smoke_ci).toBe("true");
|
||||
expect(current.outputs.run_sqlite_session_lifecycle).toBe("true");
|
||||
expect(current.outputs.run_channel_contracts_shards).toBe("true");
|
||||
expect(current.outputs.run_protocol_event_coverage).toBe("true");
|
||||
expect(current.outputs.run_format_check).toBe("true");
|
||||
@@ -5233,6 +5249,25 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
}),
|
||||
]);
|
||||
expect(changedPullRequest.outputs.run_checks_node_core_dist).toBe("true");
|
||||
expect(changedPullRequest.outputs.run_sqlite_session_lifecycle).toBe("false");
|
||||
|
||||
const sqliteLifecyclePullRequest = runCiManifestFixture({
|
||||
bundledPlanner: true,
|
||||
changedPaths: ["src/sqlite-session-owner.ts"],
|
||||
eventName: "pull_request",
|
||||
});
|
||||
expect(sqliteLifecyclePullRequest.status, sqliteLifecyclePullRequest.output).toBe(0);
|
||||
expect(sqliteLifecyclePullRequest.outputs.run_sqlite_session_lifecycle).toBe("true");
|
||||
expect(sqliteLifecyclePullRequest.outputs.run_build_artifacts).toBe("true");
|
||||
|
||||
const sqliteLifecycleTestPullRequest = runCiManifestFixture({
|
||||
bundledPlanner: true,
|
||||
changedPaths: ["test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts"],
|
||||
eventName: "pull_request",
|
||||
});
|
||||
expect(sqliteLifecycleTestPullRequest.status, sqliteLifecycleTestPullRequest.output).toBe(0);
|
||||
expect(sqliteLifecycleTestPullRequest.outputs.run_sqlite_session_lifecycle).toBe("true");
|
||||
expect(sqliteLifecycleTestPullRequest.outputs.run_build_artifacts).toBe("true");
|
||||
|
||||
const plannerImportFailure = runCiManifestFixture({
|
||||
bundledPlanner: true,
|
||||
@@ -5821,18 +5856,40 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
expect(proofStep.run).toContain("Selected target predates");
|
||||
});
|
||||
|
||||
it("scopes cold-runner watchdog headroom to the SQLite flip proof", () => {
|
||||
it("runs the scoped SQLite lifecycle proof against the exact built artifact", () => {
|
||||
const workflow = readCiWorkflow();
|
||||
const additionalJob = workflow.jobs["check-additional-shard"];
|
||||
const runStep = additionalJob.steps.find(
|
||||
const additionalRunStep = additionalJob.steps.find(
|
||||
(step: WorkflowStep) => step.name === "Run additional check shard",
|
||||
);
|
||||
|
||||
expect(runStep.run).toContain("sqlite-session-flip-proof)");
|
||||
expect(runStep.run).toContain(
|
||||
'run_check "sqlite sessions/transcripts flip proof" env OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=660000 node scripts/run-vitest.mjs run',
|
||||
const lifecycleJob = workflow.jobs["sqlite-session-lifecycle"];
|
||||
const downloadStep = lifecycleJob.steps.find(
|
||||
(step: WorkflowStep) => step.name === "Download exact-run built runtime",
|
||||
);
|
||||
expect(runStep.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBeUndefined();
|
||||
const extractStep = lifecycleJob.steps.find(
|
||||
(step: WorkflowStep) => step.name === "Extract built runtime",
|
||||
);
|
||||
const proofStep = lifecycleJob.steps.find(
|
||||
(step: WorkflowStep) => step.name === "Verify SQLite session lifecycle",
|
||||
);
|
||||
|
||||
expect(additionalJob.strategy.matrix.include).not.toContainEqual(
|
||||
expect.objectContaining({ group: "sqlite-session-flip-proof" }),
|
||||
);
|
||||
expect(additionalRunStep.run).not.toContain("sqlite-session-flip-proof)");
|
||||
expect(lifecycleJob.needs).toEqual(["preflight", "build-artifacts"]);
|
||||
expect(lifecycleJob.if).toContain(
|
||||
"needs.preflight.outputs.run_sqlite_session_lifecycle == 'true'",
|
||||
);
|
||||
expect(downloadStep.uses).toBe(DOWNLOAD_ARTIFACT_V8);
|
||||
expect(downloadStep.with.name).toBe("dist-runtime-build");
|
||||
expect(extractStep.run).toContain("dist-runtime-build.tar.zst");
|
||||
expect(proofStep.env.OPENCLAW_E2E_USE_PREBUILT_DIST).toBe("1");
|
||||
expect(proofStep.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe("660000");
|
||||
expect(proofStep.run).toContain(
|
||||
"test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts",
|
||||
);
|
||||
expect(workflow.jobs["ci-gate"].needs).toContain("sqlite-session-lifecycle");
|
||||
});
|
||||
|
||||
it("restores the dist build cache before building and saves only cache misses", () => {
|
||||
@@ -6058,6 +6115,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
|
||||
const selectedJobs = [
|
||||
"pnpm-store-warmup",
|
||||
"build-artifacts",
|
||||
"sqlite-session-lifecycle",
|
||||
"native-i18n",
|
||||
"checks-ui",
|
||||
"checks-ui-e2e",
|
||||
|
||||
@@ -61,6 +61,14 @@ describe("vitest E2E global setup", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses an exact-run prebuilt dist without rebuilding it", async () => {
|
||||
const runCommand = vi.fn<SetupCommandRunner>();
|
||||
|
||||
await runE2eGlobalSetup(runCommand, { OPENCLAW_E2E_USE_PREBUILT_DIST: "1" });
|
||||
|
||||
expect(runCommand).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
posixIt("forwards output and SIGTERM through the runner process group", async () => {
|
||||
const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-e2e-setup-group-"));
|
||||
const fixturePath = path.join(fixtureDir, "build-fixture.mjs");
|
||||
|
||||
@@ -28,19 +28,25 @@ export function runE2eSetupCommand(args: string[], env: NodeJS.ProcessEnv): Prom
|
||||
|
||||
export async function runE2eGlobalSetup(
|
||||
runCommand: SetupCommandRunner = runE2eSetupCommand,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<void> {
|
||||
// Exact-run CI artifact consumers already have the complete built surface.
|
||||
// Rebuilding here would discard that provenance and duplicate the slow step.
|
||||
if (env.OPENCLAW_E2E_USE_PREBUILT_DIST === "1") {
|
||||
return;
|
||||
}
|
||||
const commands = [
|
||||
{
|
||||
args: ["scripts/run-node.mjs", "--version"],
|
||||
env: {
|
||||
...process.env,
|
||||
...env,
|
||||
OPENCLAW_BUILD_PRIVATE_QA: "1",
|
||||
OPENCLAW_RUN_NODE_SKIP_DTS_BUILD: "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
args: ["--import", "tsx", "scripts/tsdown-build.mts", "--config", "tsdown.ai.config.ts"],
|
||||
env: process.env,
|
||||
env,
|
||||
},
|
||||
];
|
||||
for (const { args, env } of commands) {
|
||||
|
||||
Reference in New Issue
Block a user