From 7fb748462ed65c90aee9ac9743e2f90f6c26decf Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Thu, 4 Jun 2026 15:43:12 -0700 Subject: [PATCH] fix(ci): classify live installer docker lanes --- scripts/check-docker-e2e-boundaries.mjs | 2 ++ scripts/lib/docker-e2e-plan.mjs | 2 +- scripts/lib/docker-e2e-scenarios.mjs | 14 ++++++++---- scripts/test-install-sh-e2e-docker.sh | 29 ++++++++++++++++++++++++ test/scripts/docker-build-helper.test.ts | 8 +++++++ test/scripts/docker-e2e-plan.test.ts | 25 ++++++++++++++++---- 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/scripts/check-docker-e2e-boundaries.mjs b/scripts/check-docker-e2e-boundaries.mjs index 077b3cf5e81f..f58e3177843d 100644 --- a/scripts/check-docker-e2e-boundaries.mjs +++ b/scripts/check-docker-e2e-boundaries.mjs @@ -15,6 +15,8 @@ const packageScripts = new Set(Object.keys(packageJson.scripts ?? {})); // These lanes prove package-installed surfaces against live auth, so they // intentionally need both live credentials and a package-backed image. const livePackageBackedLanes = new Set([ + "install-e2e-anthropic", + "install-e2e-openai", "live-codex-npm-plugin", "live-mcp-code-mode-gateway", "live-plugin-tool", diff --git a/scripts/lib/docker-e2e-plan.mjs b/scripts/lib/docker-e2e-plan.mjs index 683ff43696fa..2d929d5231a8 100644 --- a/scripts/lib/docker-e2e-plan.mjs +++ b/scripts/lib/docker-e2e-plan.mjs @@ -459,7 +459,7 @@ export function resolveDockerE2ePlan(options) { const configuredLanes = selectedLanes ? selectedLanes : releaseLanes - ? releaseLanes + ? applyLiveMode(releaseLanes, options.liveMode) : options.liveMode === "only" ? applyLiveMode([...retriedMainLanes, ...retriedTailLanes], options.liveMode) : applyLiveMode(retriedMainLanes, options.liveMode); diff --git a/scripts/lib/docker-e2e-scenarios.mjs b/scripts/lib/docker-e2e-scenarios.mjs index 884690747d63..3084b1a0e106 100644 --- a/scripts/lib/docker-e2e-scenarios.mjs +++ b/scripts/lib/docker-e2e-scenarios.mjs @@ -694,11 +694,14 @@ const releasePathBundledChannelLanes = [ ]; const releasePathPackageInstallOpenAiLanes = [ - npmLane( + liveLane( "install-e2e-openai", "OPENCLAW_INSTALL_TAG=beta OPENCLAW_E2E_MODELS=openai OPENCLAW_INSTALL_E2E_IMAGE=openclaw-install-e2e-openai:local OPENCLAW_INSTALL_E2E_AGENT_TOOL_SMOKE=0 OPENCLAW_INSTALL_E2E_OPENAI_MODEL=openai/gpt-5.4-mini OPENCLAW_INSTALL_E2E_AGENT_TURN_TIMEOUT_SECONDS=120 OPENCLAW_INSTALL_E2E_OPENAI_PROVIDER_TIMEOUT_SECONDS=120 pnpm test:install:e2e", { - resources: ["service"], + e2eImageKind: "bare", + needsLiveImage: false, + provider: "openai", + resources: ["npm", "service"], timeoutMs: 15 * 60 * 1000, weight: 3, }, @@ -714,11 +717,14 @@ const releasePathPackageInstallOpenAiLanes = [ ]; const releasePathPackageInstallAnthropicLanes = [ - npmLane( + liveLane( "install-e2e-anthropic", "OPENCLAW_INSTALL_TAG=beta OPENCLAW_E2E_MODELS=anthropic OPENCLAW_INSTALL_E2E_IMAGE=openclaw-install-e2e-anthropic:local pnpm test:install:e2e", { - resources: ["service"], + e2eImageKind: "bare", + needsLiveImage: false, + provider: "claude", + resources: ["npm", "service"], weight: 3, }, ), diff --git a/scripts/test-install-sh-e2e-docker.sh b/scripts/test-install-sh-e2e-docker.sh index b34285462972..7de7e53cd739 100755 --- a/scripts/test-install-sh-e2e-docker.sh +++ b/scripts/test-install-sh-e2e-docker.sh @@ -7,12 +7,40 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-container.sh" IMAGE_NAME="${OPENCLAW_INSTALL_E2E_IMAGE:-openclaw-install-e2e:local}" INSTALL_URL="${OPENCLAW_INSTALL_URL:-https://openclaw.bot/install.sh}" DOCKER_COMMAND_TIMEOUT="${DOCKER_COMMAND_TIMEOUT:-${OPENCLAW_INSTALL_E2E_DOCKER_TIMEOUT:-2700s}}" +PROFILE_FILE="${OPENCLAW_INSTALL_E2E_PROFILE_FILE:-${OPENCLAW_PROFILE_FILE:-${OPENCLAW_TESTBOX_PROFILE_FILE:-$HOME/.openclaw-testbox-live.profile}}}" OPENAI_API_KEY="${OPENAI_API_KEY:-}" ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}" ANTHROPIC_API_TOKEN="${ANTHROPIC_API_TOKEN:-}" OPENCLAW_E2E_MODELS="${OPENCLAW_E2E_MODELS:-}" +if [ ! -f "$PROFILE_FILE" ] && [ -f "$HOME/.profile" ]; then + PROFILE_FILE="$HOME/.profile" +fi + +PROFILE_STATUS="none" + +read_profile_env_value() { + local key="$1" + ( + set +u + # shellcheck disable=SC1090 + source "$PROFILE_FILE" >/dev/null + printf '%s' "${!key:-}" + ) +} + +for key in OPENAI_API_KEY ANTHROPIC_API_KEY ANTHROPIC_API_TOKEN; do + if [ -f "$PROFILE_FILE" ] && [ -r "$PROFILE_FILE" ] && [ -z "${!key:-}" ]; then + printf -v "$key" '%s' "$(read_profile_env_value "$key")" + PROFILE_STATUS="$PROFILE_FILE" + fi + if [[ "${!key:-}" == "undefined" || "${!key:-}" == "null" ]]; then + printf -v "$key" '%s' "" + fi + export "$key" +done + echo "==> Build image: $IMAGE_NAME" docker_build_run install-e2e-build \ -t "$IMAGE_NAME" \ @@ -20,6 +48,7 @@ docker_build_run install-e2e-build \ "$ROOT_DIR/scripts/docker" echo "==> Run E2E installer test" +echo "Profile file: $PROFILE_STATUS" docker_e2e_docker_run_cmd run --rm \ -e OPENCLAW_INSTALL_URL="$INSTALL_URL" \ -e OPENCLAW_INSTALL_TAG="${OPENCLAW_INSTALL_TAG:-latest}" \ diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index 9c0d43573d66..8e7cd7176faf 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -2051,6 +2051,14 @@ output="$(run_logged_print_heartbeat plugins-run 08 bash -c 'printf "captured co expect(wrapper).toContain("OPENCLAW_INSTALL_E2E_OPENAI_MODEL"); expect(wrapper).toContain("OPENCLAW_INSTALL_E2E_OPENAI_PROVIDER_TIMEOUT_SECONDS"); expect(wrapper).toContain("OPENCLAW_INSTALL_E2E_AGENT_TURN_TIMEOUT_SECONDS:-300"); + expect(wrapper).toContain("OPENCLAW_INSTALL_E2E_PROFILE_FILE"); + expect(wrapper).toContain("OPENCLAW_PROFILE_FILE"); + expect(wrapper).toContain("OPENCLAW_TESTBOX_PROFILE_FILE"); + expect(wrapper).toContain("read_profile_env_value"); + expect(wrapper).toContain("source \"$PROFILE_FILE\""); + expect(wrapper).not.toContain("set -a"); + expect(wrapper).toContain("export \"$key\""); + expect(wrapper).toContain("Profile file: $PROFILE_STATUS"); expect(runner).toContain("OPENCLAW_INSTALL_E2E_OPENAI_MODEL"); expect(runner).toContain("OPENCLAW_INSTALL_E2E_OPENAI_PROVIDER_TIMEOUT_SECONDS"); expect(runner).toContain( diff --git a/test/scripts/docker-e2e-plan.test.ts b/test/scripts/docker-e2e-plan.test.ts index f3c3f802bb4f..6549f50299ca 100644 --- a/test/scripts/docker-e2e-plan.test.ts +++ b/test/scripts/docker-e2e-plan.test.ts @@ -179,6 +179,23 @@ describe("scripts/lib/docker-e2e-plan", () => { expect(plan.lanes.map((lane) => lane.name)).toEqual(["live-plugin-tool"]); }); + it("keeps provider-backed install E2E lanes out of non-live package chunks", () => { + const plan = planFor({ + includeOpenWebUI: true, + liveMode: "skip", + profile: RELEASE_PATH_PROFILE, + releaseChunk: "package-update", + }); + + const laneNames = plan.lanes.map((lane) => lane.name); + expect(laneNames).not.toContain("install-e2e-openai"); + expect(laneNames).not.toContain("openai-chat-tools"); + expect(laneNames).not.toContain("live-codex-npm-plugin"); + expect(laneNames).not.toContain("install-e2e-anthropic"); + expect(laneNames).toContain("codex-on-demand"); + expect(laneNames).toContain("update-channel-switch"); + }); + it("splits release-path package and plugin chunks across shorter CI jobs", () => { const core = planFor({ includeOpenWebUI: true, @@ -920,9 +937,9 @@ describe("scripts/lib/docker-e2e-plan", () => { command: "OPENCLAW_INSTALL_TAG=beta OPENCLAW_E2E_MODELS=openai OPENCLAW_INSTALL_E2E_IMAGE=openclaw-install-e2e-openai:local OPENCLAW_INSTALL_E2E_AGENT_TOOL_SMOKE=0 OPENCLAW_INSTALL_E2E_OPENAI_MODEL=openai/gpt-5.4-mini OPENCLAW_INSTALL_E2E_AGENT_TURN_TIMEOUT_SECONDS=120 OPENCLAW_INSTALL_E2E_OPENAI_PROVIDER_TIMEOUT_SECONDS=120 pnpm test:install:e2e", imageKind: "bare", - live: false, + live: true, name: "install-e2e-openai", - resources: ["docker", "npm", "service"], + resources: ["docker", "live", "live:openai", "npm", "service"], timeoutMs: 900_000, weight: 3, }, @@ -930,9 +947,9 @@ describe("scripts/lib/docker-e2e-plan", () => { command: "OPENCLAW_INSTALL_TAG=beta OPENCLAW_E2E_MODELS=anthropic OPENCLAW_INSTALL_E2E_IMAGE=openclaw-install-e2e-anthropic:local pnpm test:install:e2e", imageKind: "bare", - live: false, + live: true, name: "install-e2e-anthropic", - resources: ["docker", "npm", "service"], + resources: ["docker", "live", "live:claude", "npm", "service"], weight: 3, }, ]);