Files
adolf/scripts/lib/docker-e2e-image.sh
alvis bedb527145
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Vendor OpenClaw source as Adolf fork baseline
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:36:54 +00:00

199 lines
6.2 KiB
Bash

#!/usr/bin/env bash
#
# Shared Docker E2E image resolver/builder.
# Suite-specific scripts call this to resolve overrides, reuse pulled images, or
# build the runner/functional images with the prepared OpenClaw package tarball.
DOCKER_E2E_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="${ROOT_DIR:-$(cd "$DOCKER_E2E_LIB_DIR/../.." && pwd)}"
source "$DOCKER_E2E_LIB_DIR/docker-e2e-logs.sh"
source "$DOCKER_E2E_LIB_DIR/docker-build.sh"
source "$DOCKER_E2E_LIB_DIR/docker-e2e-package.sh"
source "$DOCKER_E2E_LIB_DIR/docker-e2e-container.sh"
docker_e2e_resolve_image() {
local default_image="$1"
shift
local env_name
for env_name in "$@"; do
local value="${!env_name:-}"
if [ -n "$value" ]; then
printf '%s\n' "$value"
return 0
fi
done
if [ -n "${OPENCLAW_DOCKER_E2E_IMAGE:-}" ]; then
printf '%s\n' "$OPENCLAW_DOCKER_E2E_IMAGE"
return 0
fi
printf '%s\n' "$default_image"
}
docker_e2e_read_nonnegative_decimal_env() {
local name="${1:?missing environment variable name}"
local fallback="${2:?missing fallback value}"
local value="${!name-}"
if [ -z "${!name+x}" ]; then
value="$fallback"
fi
if [[ ! "$value" =~ ^(0|[1-9][0-9]*)(\.[0-9]+)?$ ]]; then
echo "invalid $name: $value" >&2
return 2
fi
local integer_part="${value%%.*}"
local fractional_part=""
if [[ "$value" == *.* ]]; then
fractional_part="${value#*.}"
fi
# These suite knobs are human-authored resource/time ceilings. Reject
# pathological decimal strings before Docker setup instead of failing later.
if [ "${#integer_part}" -gt 9 ] || [ "${#fractional_part}" -gt 6 ]; then
echo "invalid $name: $value" >&2
return 2
fi
printf '%s\n' "$value"
}
docker_e2e_read_tcp_port_env() {
local name="${1:?missing environment variable name}"
local fallback="${2:?missing fallback value}"
local value="${!name-}"
if [ -z "${!name+x}" ]; then
value="$fallback"
fi
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
echo "invalid $name: $value" >&2
return 2
fi
local decimal_value=$((10#$value))
if [ "$decimal_value" -lt 1 ] || [ "$decimal_value" -gt 65535 ]; then
echo "invalid $name: $value" >&2
return 2
fi
printf '%s\n' "$value"
}
docker_e2e_build_or_reuse() {
local image_name="$1"
local label="$2"
local dockerfile="${3:-$ROOT_DIR/scripts/e2e/Dockerfile}"
local context="${4:-$ROOT_DIR}"
local target="${5:-}"
local skip_build="${6:-0}"
if [ -z "$target" ] && [ "$dockerfile" = "$ROOT_DIR/scripts/e2e/Dockerfile" ]; then
# The generic E2E image defaults to the package-installed app image; tests
# that need a clean install runner pass target=bare explicitly.
target="functional"
fi
if [ "${OPENCLAW_SKIP_DOCKER_BUILD:-0}" = "1" ] || [ "$skip_build" = "1" ]; then
echo "Reusing Docker image: $image_name"
if ! docker_e2e_docker_cmd image inspect "$image_name" >/dev/null 2>&1; then
echo "Docker image not found locally; pulling: $image_name"
if docker_e2e_docker_cmd pull "$image_name"; then
return 0
fi
if docker_build_on_missing_enabled; then
echo "Docker image not available; building because OPENCLAW_DOCKER_BUILD_ON_MISSING/OPENCLAW_TESTBOX allows fallback."
else
echo "Docker image not found: $image_name" >&2
echo "Build it first or unset OPENCLAW_SKIP_DOCKER_BUILD." >&2
return 1
fi
else
return 0
fi
fi
echo "Building Docker image: $image_name"
local build_args=()
local package_tgz=""
local package_context=""
local package_pack_dir=""
if [ -n "$target" ]; then
build_args+=(--target "$target")
fi
if [ "$target" = "functional" ]; then
package_tgz="$(docker_e2e_prepare_package_tgz "$label")"
if [ -z "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}" ]; then
package_pack_dir="$(dirname "$package_tgz")"
fi
local context_status=0
package_context="$(docker_e2e_prepare_package_context "$package_tgz")" || context_status="$?"
if [ "$context_status" -ne 0 ]; then
if [ -n "$package_pack_dir" ]; then
rm -rf "$package_pack_dir"
fi
return "$context_status"
fi
# The Dockerfile never sees repo sources as app input; functional installs
# exactly this tarball through a named BuildKit context.
build_args+=(--build-context "openclaw_package=$package_context")
fi
build_args+=(-t "$image_name" -f "$dockerfile" "$context")
local build_status=0
docker_build_run "$label-build" "${build_args[@]}" || build_status="$?"
if [ -n "$package_context" ]; then
rm -rf "$package_context"
fi
if [ -n "$package_pack_dir" ]; then
rm -rf "$package_pack_dir"
fi
return "$build_status"
}
docker_e2e_test_state_shell_b64() {
local label="${1:?missing test-state label}"
local scenario="${2:-empty}"
node "$ROOT_DIR/scripts/lib/openclaw-test-state.mjs" shell \
--label "$label" \
--scenario "$scenario" |
base64 |
tr -d '\n'
}
docker_e2e_test_state_function_b64() {
node "$ROOT_DIR/scripts/lib/openclaw-test-state.mjs" shell-function |
base64 |
tr -d '\n'
}
docker_e2e_sample_stats_until_exit() {
local container_name="${1:?missing container name}"
local docker_pid="${2:?missing docker pid}"
local stats_log="${3:?missing stats log}"
local run_log="${4:?missing run log}"
local label="${5:-Docker E2E}"
local heartbeat_seconds="${6:-30}"
local started_at="$SECONDS"
local last_heartbeat="$SECONDS"
if ! [[ "$heartbeat_seconds" =~ ^[0-9]+$ ]] || [ "$heartbeat_seconds" -lt 1 ]; then
heartbeat_seconds="30"
fi
heartbeat_seconds="$((10#$heartbeat_seconds))"
while kill -0 "$docker_pid" 2>/dev/null; do
if docker_e2e_docker_cmd inspect "$container_name" >/dev/null 2>&1; then
docker_e2e_docker_cmd stats --no-stream --format '{{json .}}' "$container_name" >>"$stats_log" 2>/dev/null || true
fi
if ((SECONDS - last_heartbeat >= heartbeat_seconds)); then
local elapsed_seconds=$((SECONDS - started_at))
local log_bytes="0"
if [ -f "$run_log" ]; then
log_bytes="$(wc -c <"$run_log" 2>/dev/null || echo 0)"
log_bytes="${log_bytes//[[:space:]]/}"
fi
echo "$label still running (${elapsed_seconds}s elapsed, ${log_bytes} log bytes captured)..."
last_heartbeat="$SECONDS"
fi
sleep 2
done
}