fix(ci): keep Crabbox dependencies intact after pnpm dlx (#124423)

* fix(ci): isolate Crabbox pnpm dlx state

* fix(ci): clarify hydrated modules errors
This commit is contained in:
Peter Steinberger
2026-08-15 22:13:26 -07:00
committed by GitHub
parent eae415b621
commit 6335e358f3
4 changed files with 27 additions and 13 deletions
+7 -4
View File
@@ -86,6 +86,7 @@ jobs:
echo "PNPM_HOME=$PNPM_HOME"
echo "PNPM_CONFIG_STORE_DIR=$PNPM_CONFIG_STORE_DIR"
echo "PNPM_CONFIG_MODULES_DIR=$PNPM_CONFIG_MODULES_DIR"
echo "CRABBOX_PNPM_MODULES_DIR=$PNPM_CONFIG_MODULES_DIR"
echo "PNPM_CONFIG_PACKAGE_IMPORT_METHOD=${PNPM_CONFIG_PACKAGE_IMPORT_METHOD:-}"
echo "PNPM_CONFIG_VIRTUAL_STORE_DIR=$PNPM_CONFIG_VIRTUAL_STORE_DIR"
} >> "$GITHUB_ENV"
@@ -388,7 +389,9 @@ jobs:
fi
}
{
for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE XDG_CACHE_HOME COREPACK_HOME NODE_BIN OPENCLAW_CRABBOX_DOCKER_AVAILABLE PNPM_HOME PNPM_CONFIG_CHILD_CONCURRENCY PNPM_CONFIG_MODULES_DIR PNPM_CONFIG_NETWORK_CONCURRENCY PNPM_CONFIG_PACKAGE_IMPORT_METHOD PNPM_CONFIG_STORE_DIR PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN PNPM_CONFIG_VIRTUAL_STORE_DIR PATH; do
# Keep workspace paths out of PNPM_CONFIG_* in the reusable shell. pnpm dlx owns a
# separate project and would otherwise overwrite this workspace's current lockfile.
for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE XDG_CACHE_HOME COREPACK_HOME NODE_BIN OPENCLAW_CRABBOX_DOCKER_AVAILABLE CRABBOX_PNPM_MODULES_DIR PNPM_HOME PNPM_CONFIG_CHILD_CONCURRENCY PNPM_CONFIG_NETWORK_CONCURRENCY PNPM_CONFIG_PACKAGE_IMPORT_METHOD PNPM_CONFIG_STORE_DIR PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN PATH; do
write_export "$key"
done
} > "${env_file}.tmp"
@@ -514,6 +517,7 @@ jobs:
"PNPM_HOME=$env:PNPM_HOME"
"PNPM_CONFIG_STORE_DIR=$env:PNPM_CONFIG_STORE_DIR"
"PNPM_CONFIG_MODULES_DIR=$env:PNPM_CONFIG_MODULES_DIR"
"CRABBOX_PNPM_MODULES_DIR=$env:PNPM_CONFIG_MODULES_DIR"
"PNPM_CONFIG_VIRTUAL_STORE_DIR=$env:PNPM_CONFIG_VIRTUAL_STORE_DIR"
"PNPM_CONFIG_CHILD_CONCURRENCY=$env:PNPM_CONFIG_CHILD_CONCURRENCY"
"PNPM_CONFIG_NETWORK_CONCURRENCY=$env:PNPM_CONFIG_NETWORK_CONCURRENCY"
@@ -614,10 +618,9 @@ jobs:
"GITHUB_REF", "GITHUB_REF_NAME", "GITHUB_SHA", "GITHUB_EVENT_NAME",
"GITHUB_ACTOR", "RUNNER_OS", "RUNNER_ARCH", "RUNNER_TEMP",
"RUNNER_TOOL_CACHE", "XDG_CACHE_HOME", "COREPACK_HOME", "NODE_BIN",
"PNPM_HOME", "PNPM_CONFIG_CHILD_CONCURRENCY", "PNPM_CONFIG_MODULES_DIR",
"PNPM_HOME", "CRABBOX_PNPM_MODULES_DIR", "PNPM_CONFIG_CHILD_CONCURRENCY",
"PNPM_CONFIG_NETWORK_CONCURRENCY", "PNPM_CONFIG_STORE_DIR",
"PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN", "PNPM_CONFIG_VIRTUAL_STORE_DIR",
"PNPM_CONFIG_SIDE_EFFECTS_CACHE", "PATH"
"PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN", "PNPM_CONFIG_SIDE_EFFECTS_CACHE", "PATH"
)
$envLines = foreach ($key in $keys) {
$value = [Environment]::GetEnvironmentVariable($key)
+3 -3
View File
@@ -2643,9 +2643,9 @@ function isHydratedNativeWindowsProvider(providerName: string) {
function remoteWindowsHydratedNodeModulesBootstrap() {
return [
"$openclawModulesDir = $env:PNPM_CONFIG_MODULES_DIR",
"$openclawModulesDir = if ($env:CRABBOX_PNPM_MODULES_DIR) { $env:CRABBOX_PNPM_MODULES_DIR } else { $env:PNPM_CONFIG_MODULES_DIR }",
"if ($openclawModulesDir) {",
'if (-not (Test-Path $openclawModulesDir)) { throw "PNPM_CONFIG_MODULES_DIR does not exist: $openclawModulesDir" }',
'if (-not (Test-Path $openclawModulesDir)) { throw "hydrated pnpm modules directory does not exist: $openclawModulesDir" }',
'$openclawWorkspaceModules = Join-Path (Get-Location).Path "node_modules"',
'$openclawSelfModules = Join-Path $openclawModulesDir "node_modules"',
'if (-not (Test-Path $openclawSelfModules)) { cmd /c mklink /J "$openclawSelfModules" "$openclawModulesDir" | Out-Host; if ($LASTEXITCODE -ne 0) { throw "failed to link hydrated pnpm node_modules" } }',
@@ -2657,7 +2657,7 @@ function remoteWindowsHydratedNodeModulesBootstrap() {
function remotePosixHydratedNodeModulesBootstrap() {
// Knip and other non-pnpm tools walk node_modules, while hydrated boxes keep it external.
// Without this link, dead-code scans silently lose consumer edges and report false positives.
return 'if [ -n "${PNPM_CONFIG_MODULES_DIR:-}" ] && [ -d "$PNPM_CONFIG_MODULES_DIR" ] && [ ! -e node_modules ]; then ln -s "$PNPM_CONFIG_MODULES_DIR" node_modules; fi;';
return 'openclaw_modules_dir="${CRABBOX_PNPM_MODULES_DIR:-${PNPM_CONFIG_MODULES_DIR:-}}"; if [ -n "$openclaw_modules_dir" ] && [ -d "$openclaw_modules_dir" ] && [ ! -e node_modules ]; then ln -s "$openclaw_modules_dir" node_modules; fi;';
}
function injectRemoteWindowsHydratedNodeModulesBootstrap(
+6 -3
View File
@@ -583,7 +583,10 @@ function runSuccessfulNativeWindows(
function expectHydratedWindowsShell(run: ParsedWrapperRun, command: string): void {
expect(run.output.args).toContain("--shell");
expect(run.remoteCommand).toContain("$openclawModulesDir = $env:PNPM_CONFIG_MODULES_DIR");
expect(run.remoteCommand).toContain(
"$env:CRABBOX_PNPM_MODULES_DIR) { $env:CRABBOX_PNPM_MODULES_DIR } else { $env:PNPM_CONFIG_MODULES_DIR }",
);
expect(run.remoteCommand).toContain("hydrated pnpm modules directory does not exist");
expect(run.remoteCommand).toContain('mklink /J "$openclawSelfModules" "$openclawModulesDir"');
expect(run.remoteCommand).toContain(
'mklink /J "$openclawWorkspaceModules" "$openclawModulesDir"',
@@ -592,7 +595,7 @@ function expectHydratedWindowsShell(run: ParsedWrapperRun, command: string): voi
}
const remotePosixHydratedModulesBootstrap =
'if [ -n "${PNPM_CONFIG_MODULES_DIR:-}" ] && [ -d "$PNPM_CONFIG_MODULES_DIR" ] && [ ! -e node_modules ]; then ln -s "$PNPM_CONFIG_MODULES_DIR" node_modules; fi;';
'openclaw_modules_dir="${CRABBOX_PNPM_MODULES_DIR:-${PNPM_CONFIG_MODULES_DIR:-}}"; if [ -n "$openclaw_modules_dir" ] && [ -d "$openclaw_modules_dir" ] && [ ! -e node_modules ]; then ln -s "$openclaw_modules_dir" node_modules; fi;';
function expectHydratedPosixShell(
run: Pick<ParsedWrapperRun, "output" | "remoteCommand">,
@@ -3033,7 +3036,7 @@ describe("scripts/crabbox-wrapper", () => {
"test",
]);
expect(output.args).toContain("--shell");
expect(remoteCommand).toContain("$openclawModulesDir = $env:PNPM_CONFIG_MODULES_DIR");
expect(remoteCommand).toContain("$env:CRABBOX_PNPM_MODULES_DIR");
expect(remoteCommand).toContain("pnpm --filter '@openclaw/discord' test");
});
@@ -1563,6 +1563,7 @@ describe("package acceptance workflow", () => {
);
expect(hydratePnpm.run).toContain('echo "PNPM_CONFIG_STORE_DIR=$PNPM_CONFIG_STORE_DIR"');
expect(hydratePnpm.run).toContain('echo "PNPM_CONFIG_MODULES_DIR=$PNPM_CONFIG_MODULES_DIR"');
expect(hydratePnpm.run).toContain('echo "CRABBOX_PNPM_MODULES_DIR=$PNPM_CONFIG_MODULES_DIR"');
expect(hydratePnpm.run).toContain(
'echo "PNPM_CONFIG_PACKAGE_IMPORT_METHOD=${PNPM_CONFIG_PACKAGE_IMPORT_METHOD:-}"',
);
@@ -1647,7 +1648,10 @@ describe("package acceptance workflow", () => {
const markCrabboxReady = workflowStep(hydrate, "Mark Crabbox ready").run;
expect(markCrabboxReady).toContain("COREPACK_HOME");
expect(markCrabboxReady).toContain("OPENCLAW_CRABBOX_DOCKER_AVAILABLE");
expect(markCrabboxReady).toContain("CRABBOX_PNPM_MODULES_DIR");
expect(markCrabboxReady).toContain("PNPM_CONFIG_PACKAGE_IMPORT_METHOD");
expect(markCrabboxReady).not.toContain("PNPM_CONFIG_MODULES_DIR");
expect(markCrabboxReady).not.toContain("PNPM_CONFIG_VIRTUAL_STORE_DIR");
expect(workflowStep(hydrate, "Hydrate provider env helper").env).toBeUndefined();
expect(hydrateWindowsDaemon.if).toBe("${{ inputs.crabbox_job == 'hydrate-windows-daemon' }}");
@@ -1705,9 +1709,13 @@ describe("package acceptance workflow", () => {
);
expect(hydrateWindowsFetch.run).toContain('"+refs/heads/main:refs/remotes/origin/main"');
expect(workflowStep(hydrateWindowsDaemon, "Mark Crabbox ready").shell).toBe("powershell");
expect(workflowStep(hydrateWindowsDaemon, "Mark Crabbox ready").run).toContain('"NODE_BIN"');
expect(workflowStep(hydrateWindowsDaemon, "Mark Crabbox ready").run).toContain('"PNPM_HOME"');
expect(workflowStep(hydrateWindowsDaemon, "Mark Crabbox ready").run).toContain('"PATH"');
const markWindowsCrabboxReady = workflowStep(hydrateWindowsDaemon, "Mark Crabbox ready").run;
expect(markWindowsCrabboxReady).toContain('"NODE_BIN"');
expect(markWindowsCrabboxReady).toContain('"PNPM_HOME"');
expect(markWindowsCrabboxReady).toContain('"CRABBOX_PNPM_MODULES_DIR"');
expect(markWindowsCrabboxReady).not.toContain('"PNPM_CONFIG_MODULES_DIR"');
expect(markWindowsCrabboxReady).not.toContain('"PNPM_CONFIG_VIRTUAL_STORE_DIR"');
expect(markWindowsCrabboxReady).toContain('"PATH"');
expect(workflowText).toContain("OPENCLAW_CRABBOX_HYDRATE_DOWNLOAD_TIMEOUT_SECONDS:-300");
expect(workflowText).toContain("OPENCLAW_CRABBOX_HYDRATE_DOWNLOAD_RETRIES:-3");
expect(workflowText).toContain("--retry-all-errors");