diff --git a/.github/actions/setup-node-env/action.yml b/.github/actions/setup-node-env/action.yml index a75eba6c656..4a48ee20e97 100644 --- a/.github/actions/setup-node-env/action.yml +++ b/.github/actions/setup-node-env/action.yml @@ -101,7 +101,23 @@ runs: if [ -n "$LOCKFILE_FLAG" ]; then install_args+=("$LOCKFILE_FLAG") fi + append_pnpm_option_arg() { + local env_name="$1" + local option_name="$2" + local value="${!env_name-}" + if [ -n "$value" ]; then + install_args+=("--${option_name}=${value}") + fi + } + append_pnpm_option_arg PNPM_CONFIG_CHILD_CONCURRENCY child-concurrency + append_pnpm_option_arg PNPM_CONFIG_MODULES_DIR modules-dir + append_pnpm_option_arg PNPM_CONFIG_NETWORK_CONCURRENCY network-concurrency + append_pnpm_option_arg PNPM_CONFIG_VIRTUAL_STORE_DIR virtual-store-dir pnpm "${install_args[@]}" || pnpm "${install_args[@]}" + if [ -n "${PNPM_CONFIG_MODULES_DIR:-}" ]; then + rm -rf node_modules + ln -s "$PNPM_CONFIG_MODULES_DIR" node_modules + fi - name: Save pnpm store cache if: inputs.install-deps == 'true' && steps.pnpm-cache.outputs.cache-enabled == 'true' && steps.pnpm-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/crabbox-hydrate.yml b/.github/workflows/crabbox-hydrate.yml index 6eba2b9d082..d449f9a2cb2 100644 --- a/.github/workflows/crabbox-hydrate.yml +++ b/.github/workflows/crabbox-hydrate.yml @@ -31,6 +31,10 @@ permissions: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + PNPM_CONFIG_CHILD_CONCURRENCY: "1" + PNPM_CONFIG_MODULES_DIR: "/tmp/openclaw-pnpm-node-modules" + PNPM_CONFIG_NETWORK_CONCURRENCY: "1" + PNPM_CONFIG_VIRTUAL_STORE_DIR: "/tmp/openclaw-pnpm-virtual-store" jobs: hydrate: @@ -85,8 +89,23 @@ jobs: sudo chmod 666 /var/run/docker.sock fi + if ! docker buildx version >/dev/null 2>&1; then + arch="$(uname -m)" + case "$arch" in + aarch64|arm64) buildx_arch=arm64 ;; + x86_64|amd64) buildx_arch=amd64 ;; + *) echo "unsupported buildx arch: $arch" >&2; exit 2 ;; + esac + buildx_version="${DOCKER_BUILDX_VERSION:-v0.15.1}" + mkdir -p "$HOME/.docker/cli-plugins" + curl -fsSL \ + "https://github.com/docker/buildx/releases/download/${buildx_version}/buildx-${buildx_version}.linux-${buildx_arch}" \ + -o "$HOME/.docker/cli-plugins/docker-buildx" + chmod 0755 "$HOME/.docker/cli-plugins/docker-buildx" + fi + docker version - docker buildx version || true + docker buildx version docker compose version || true - name: Hydrate provider env helper diff --git a/scripts/crabbox-wrapper.mjs b/scripts/crabbox-wrapper.mjs index 95589fb23e2..91bc47f75cb 100755 --- a/scripts/crabbox-wrapper.mjs +++ b/scripts/crabbox-wrapper.mjs @@ -241,6 +241,26 @@ function optionValue(commandArgs, name) { return ""; } +function hasOption(commandArgs, name) { + commandArgs = crabboxOptionArgs(commandArgs); + const shortName = name.replace(/^--/u, "-"); + for (const arg of commandArgs) { + if ( + arg === name || + arg === shortName || + arg.startsWith(`${name}=`) || + arg.startsWith(`${shortName}=`) + ) { + return true; + } + } + return false; +} + +function isLocalContainerProvider(providerName) { + return ["local-container", "docker", "container", "local-docker"].includes(providerName); +} + function runCommandArgs(commandArgs) { const { start } = runCommandBounds(commandArgs); return start >= 0 ? commandArgs.slice(start) : []; @@ -410,9 +430,33 @@ if (args[0] === "run" && provider === "aws" && runtimeEntrypoint) { ); } +const childEnv = { ...process.env }; +if ( + isLocalContainerProvider(provider) && + !childEnv.CRABBOX_LOCAL_CONTAINER_DOCKER_SOCKET && + !hasOption(args, "--local-container-docker-socket") +) { + childEnv.CRABBOX_LOCAL_CONTAINER_DOCKER_SOCKET = "1"; + console.error( + "[crabbox] provider=docker enabling host Docker socket pass-through for OpenClaw Docker tests", + ); +} +if ( + isLocalContainerProvider(provider) && + process.platform !== "win32" && + !childEnv.CRABBOX_LOCAL_CONTAINER_WORK_ROOT && + !hasOption(args, "--local-container-work-root") +) { + childEnv.CRABBOX_LOCAL_CONTAINER_WORK_ROOT = "/tmp/openclaw-crabbox-docker-work"; + console.error( + "[crabbox] provider=docker using short host-visible work root for OpenClaw Docker tests", + ); +} + const child = spawn(binary, args, { cwd: repoRoot, stdio: "inherit", + env: childEnv, }); child.on("exit", (code, signal) => { diff --git a/scripts/lib/docker-build.sh b/scripts/lib/docker-build.sh index 910db2a7337..38230dd9241 100644 --- a/scripts/lib/docker-build.sh +++ b/scripts/lib/docker-build.sh @@ -21,7 +21,7 @@ docker_build_on_missing_enabled() { docker_build_command() { local build_cmd=(docker build) - if [ "${OPENCLAW_DOCKER_BUILD_USE_BUILDX:-0}" = "1" ]; then + if [ "${OPENCLAW_DOCKER_BUILD_USE_BUILDX:-0}" = "1" ] || docker_build_args_need_buildx "$@"; then build_cmd=(docker buildx build --load) if [ -n "${OPENCLAW_DOCKER_BUILD_CACHE_FROM:-}" ]; then build_cmd+=(--cache-from "${OPENCLAW_DOCKER_BUILD_CACHE_FROM}") @@ -34,6 +34,17 @@ docker_build_command() { printf '%s\0' env DOCKER_BUILDKIT=1 "${build_cmd[@]}" "$@" } +docker_build_args_need_buildx() { + for arg in "$@"; do + case "$arg" in + --build-context | --build-context=*) + return 0 + ;; + esac + done + return 1 +} + docker_build_transient_failure() { local log_file="$1" grep -Eqi \