diff --git a/.github/workflows/install-smoke.yml b/.github/workflows/install-smoke.yml index f3615414b8b..4d1d3816ce4 100644 --- a/.github/workflows/install-smoke.yml +++ b/.github/workflows/install-smoke.yml @@ -217,6 +217,7 @@ jobs: OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT: ${{ github.event_name == 'pull_request' && '1' || '0' }} OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL: "1" OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS: "1" + OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE: latest OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE: openclaw-dockerfile-smoke:local OPENCLAW_INSTALL_SMOKE_UPDATE_SKIP_LOCAL_BUILD: "1" run: bash scripts/test-install-sh-docker.sh diff --git a/docs/help/testing.md b/docs/help/testing.md index ac362313616..2011436927c 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -977,7 +977,7 @@ The live-model Docker runners also bind-mount only the needed CLI auth homes (or - Onboarding wizard (TTY, full scaffolding): `pnpm test:docker:onboard` (script: `scripts/e2e/onboard-docker.sh`) - Npm tarball onboarding/channel/agent smoke: `pnpm test:docker:npm-onboard-channel-agent` installs the packed OpenClaw tarball globally in Docker, configures OpenAI via env-ref onboarding plus Telegram by default, verifies enabling the plugin installs its runtime deps on demand, runs doctor, and runs one mocked OpenAI agent turn. Reuse a prebuilt tarball with `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host rebuild with `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`, or switch channel with `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`. - Bun global install smoke: `bash scripts/e2e/bun-global-install-smoke.sh` packs the current tree, installs it with `bun install -g` in an isolated home, and verifies `openclaw infer image providers --json` returns bundled image providers instead of hanging. Reuse a prebuilt tarball with `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host build with `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0`, or copy `dist/` from a built Docker image with `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local`. -- Installer Docker smoke: `bash scripts/test-install-sh-docker.sh` shares one npm cache across its root, update, and direct-npm containers. Non-root installer checks keep an isolated npm cache so root-owned cache entries do not mask user-local install behavior. Set `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` to reuse the root/update/direct-npm cache across local reruns. +- Installer Docker smoke: `bash scripts/test-install-sh-docker.sh` shares one npm cache across its root, update, and direct-npm containers. Update smoke defaults to npm `latest` as the stable baseline before upgrading to the candidate tarball. Non-root installer checks keep an isolated npm cache so root-owned cache entries do not mask user-local install behavior. Set `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` to reuse the root/update/direct-npm cache across local reruns. - Install Smoke CI skips the duplicate direct-npm global update with `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`; run the script locally without that env when direct `npm install -g` coverage is needed. - Gateway networking (two containers, WS auth + health): `pnpm test:docker:gateway-network` (script: `scripts/e2e/gateway-network-docker.sh`) - OpenAI Responses web_search minimal reasoning regression: `pnpm test:docker:openai-web-search-minimal` (script: `scripts/e2e/openai-web-search-minimal-docker.sh`) runs a mocked OpenAI server through Gateway, verifies `web_search` raises `reasoning.effort` from `minimal` to `low`, then forces the provider schema reject and checks the raw detail appears in Gateway logs. diff --git a/scripts/docker/install-sh-smoke/run.sh b/scripts/docker/install-sh-smoke/run.sh index f7ecfb1004c..8265a2f763e 100755 --- a/scripts/docker/install-sh-smoke/run.sh +++ b/scripts/docker/install-sh-smoke/run.sh @@ -9,7 +9,7 @@ DEFAULT_PACKAGE="openclaw" PACKAGE_NAME="${OPENCLAW_INSTALL_PACKAGE:-$DEFAULT_PACKAGE}" FRESH_VERSION="${OPENCLAW_INSTALL_FRESH_VERSION:-}" FRESH_TAG_URL="${OPENCLAW_INSTALL_FRESH_TAG_URL:-}" -UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_UPDATE_BASELINE:-2026.4.10}" +UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_UPDATE_BASELINE:-latest}" UPDATE_BASELINE_TAG_URL="${OPENCLAW_INSTALL_UPDATE_BASELINE_TAG_URL:-}" UPDATE_EXPECT_VERSION="${OPENCLAW_INSTALL_UPDATE_EXPECT_VERSION:-}" UPDATE_TAG_URL="${OPENCLAW_INSTALL_UPDATE_TAG_URL:-}" @@ -124,6 +124,20 @@ npm_install_global() { install -g "$@" } +resolve_update_baseline_version() { + if [[ -n "$UPDATE_BASELINE_TAG_URL" ]]; then + return + fi + + local resolved_version + resolved_version="$(quiet_npm view "${PACKAGE_NAME}@${UPDATE_BASELINE_VERSION}" version 2>/dev/null || true)" + if [[ -z "$resolved_version" ]]; then + echo "ERROR: failed to resolve ${PACKAGE_NAME}@${UPDATE_BASELINE_VERSION}" >&2 + return 1 + fi + UPDATE_BASELINE_VERSION="$resolved_version" +} + run_install_smoke() { if [[ -n "$FRESH_VERSION" && -n "$FRESH_TAG_URL" ]]; then echo "package=$PACKAGE_NAME latest=$FRESH_VERSION source=$FRESH_TAG_URL" @@ -216,6 +230,8 @@ run_update_smoke() { return 1 fi + resolve_update_baseline_version + echo "package=$PACKAGE_NAME baseline=$UPDATE_BASELINE_VERSION target=$UPDATE_EXPECT_VERSION" echo "==> Install baseline release" if [[ -n "$UPDATE_BASELINE_TAG_URL" ]]; then @@ -339,6 +355,8 @@ run_npm_global_smoke() { return 1 fi + resolve_update_baseline_version + echo "package=$PACKAGE_NAME baseline=$UPDATE_BASELINE_VERSION target=$UPDATE_EXPECT_VERSION" echo "==> Direct npm global install candidate" npm_install_global "direct npm global install candidate" "$UPDATE_TAG_URL" diff --git a/scripts/test-install-sh-docker.sh b/scripts/test-install-sh-docker.sh index dd1ce687671..71fe31cf11b 100755 --- a/scripts/test-install-sh-docker.sh +++ b/scripts/test-install-sh-docker.sh @@ -148,7 +148,7 @@ SKIP_SMOKE_IMAGE_BUILD="${OPENCLAW_INSTALL_SMOKE_SKIP_IMAGE_BUILD:-0}" SKIP_NONROOT_IMAGE_BUILD="${OPENCLAW_INSTALL_NONROOT_SKIP_IMAGE_BUILD:-0}" SKIP_UPDATE="${OPENCLAW_INSTALL_SMOKE_SKIP_UPDATE:-0}" SKIP_NPM_GLOBAL="${OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL:-0}" -UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE:-2026.4.10}" +UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE:-latest}" UPDATE_PACKAGE_SPEC="${OPENCLAW_INSTALL_SMOKE_UPDATE_PACKAGE_SPEC:-}" UPDATE_DIST_IMAGE="${OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE:-}" UPDATE_SKIP_LOCAL_BUILD="${OPENCLAW_INSTALL_SMOKE_UPDATE_SKIP_LOCAL_BUILD:-0}" @@ -292,6 +292,17 @@ if (!last || typeof last.filename !== "string" || last.filename.length === 0) { process.exit(1); } process.stdout.write(last.filename); +' "$baseline_pack_json_file" + )" + UPDATE_BASELINE_VERSION="$( + node -e ' +const raw = require("node:fs").readFileSync(process.argv[1], "utf8") || "[]"; +const parsed = JSON.parse(raw); +const last = Array.isArray(parsed) ? parsed.at(-1) : null; +if (!last || typeof last.version !== "string" || last.version.length === 0) { + process.exit(1); +} +process.stdout.write(last.version); ' "$baseline_pack_json_file" )" print_pack_audit "baseline" "$baseline_pack_json_file" diff --git a/test/scripts/test-install-sh-docker.test.ts b/test/scripts/test-install-sh-docker.test.ts index bb854559014..226ccc7ca42 100644 --- a/test/scripts/test-install-sh-docker.test.ts +++ b/test/scripts/test-install-sh-docker.test.ts @@ -29,6 +29,24 @@ describe("test-install-sh-docker", () => { ); }); + it("uses npm latest as the update baseline and resolves it to the concrete packed version", () => { + const script = readFileSync(SCRIPT_PATH, "utf8"); + const runner = readFileSync(SMOKE_RUNNER_PATH, "utf8"); + const workflow = readFileSync(INSTALL_SMOKE_WORKFLOW_PATH, "utf8"); + + expect(script).toContain( + 'UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE:-latest}"', + ); + expect(script).toContain('quiet_npm pack "${PACKAGE_NAME}@${UPDATE_BASELINE_VERSION}"'); + expect(script).toContain('UPDATE_BASELINE_VERSION="$('); + expect(runner).toContain( + 'UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_UPDATE_BASELINE:-latest}"', + ); + expect(runner).toContain("resolve_update_baseline_version"); + expect(runner).toContain('quiet_npm view "${PACKAGE_NAME}@${UPDATE_BASELINE_VERSION}" version'); + expect(workflow).toContain("OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE: latest"); + }); + it("can reuse dist from the already-built root Docker smoke image", () => { const script = readFileSync(SCRIPT_PATH, "utf8");