fix(e2e): clean package docker artifacts on setup failure

This commit is contained in:
Vincent Koc
2026-05-26 11:00:58 +02:00
parent 0e733795f4
commit 90bcec9fa4
14 changed files with 107 additions and 11 deletions

View File

@@ -7,6 +7,11 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$ROOT_DIR/scripts/lib/docker-e2e-image.sh"
source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-doctor-install-switch-e2e" OPENCLAW_DOCTOR_INSTALL_SWITCH_E2E_IMAGE)"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz doctor-switch "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
# Bare lanes mount the package artifact instead of baking app sources into the image.
docker_e2e_package_mount_args "$PACKAGE_TGZ"

View File

@@ -26,6 +26,10 @@ ARTIFACT_DIR="${OPENCLAW_MULTI_NODE_ARTIFACT_DIR:-$ROOT_DIR/.artifacts/multi-nod
mkdir -p "$ARTIFACT_DIR"
chmod -R a+rwX "$ARTIFACT_DIR" || true
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
# Build the bare e2e image and prepare the package tarball.
docker_e2e_build_or_reuse "$IMAGE_NAME" multi-node-update "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR" "bare" "${OPENCLAW_SKIP_DOCKER_BUILD:-0}"

View File

@@ -8,6 +8,11 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-plugin-lifecycle-matrix-e2e" OPENCLAW_PLUGIN_LIFECYCLE_MATRIX_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_PLUGIN_LIFECYCLE_MATRIX_E2E_SKIP_BUILD:-0}"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz plugin-lifecycle-matrix "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"

View File

@@ -9,6 +9,11 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-plugin-update-e2e" OPENCLAW_PLUGIN_UPDATE_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_PLUGIN_UPDATE_E2E_SKIP_BUILD:-0}"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz plugin-update "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
# Bare lanes mount the package artifact instead of baking app sources into the image.
docker_e2e_package_mount_args "$PACKAGE_TGZ"

View File

@@ -8,6 +8,15 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-release-media-memory-e2e" OPENCLAW_RELEASE_MEDIA_MEMORY_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_RELEASE_MEDIA_MEMORY_E2E_SKIP_BUILD:-0}"
run_log=""
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz release-media-memory "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"
@@ -22,9 +31,7 @@ if ! docker_e2e_run_with_harness \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
-i "$IMAGE_NAME" bash scripts/e2e/lib/release-media-memory/scenario.sh >"$run_log" 2>&1; then
docker_e2e_print_log "$run_log"
rm -f "$run_log"
exit 1
fi
rm -f "$run_log"
echo "Release media memory Docker E2E passed."

View File

@@ -8,6 +8,15 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-release-plugin-marketplace-e2e" OPENCLAW_RELEASE_PLUGIN_MARKETPLACE_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_RELEASE_PLUGIN_MARKETPLACE_E2E_SKIP_BUILD:-0}"
run_log=""
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz release-plugin-marketplace "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"
@@ -22,9 +31,7 @@ if ! docker_e2e_run_with_harness \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
-i "$IMAGE_NAME" bash scripts/e2e/lib/release-plugin-marketplace/scenario.sh >"$run_log" 2>&1; then
docker_e2e_print_log "$run_log"
rm -f "$run_log"
exit 1
fi
rm -f "$run_log"
echo "Release plugin marketplace Docker E2E passed."

View File

@@ -8,6 +8,15 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-release-typed-onboarding-e2e" OPENCLAW_RELEASE_TYPED_ONBOARDING_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_RELEASE_TYPED_ONBOARDING_E2E_SKIP_BUILD:-0}"
run_log=""
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz release-typed-onboarding "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"
@@ -22,9 +31,7 @@ if ! docker_e2e_run_with_harness \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
-i "$IMAGE_NAME" bash scripts/e2e/lib/release-typed-onboarding/scenario.sh >"$run_log" 2>&1; then
docker_e2e_print_log "$run_log"
rm -f "$run_log"
exit 1
fi
rm -f "$run_log"
echo "Release typed onboarding Docker E2E passed."

View File

@@ -8,6 +8,15 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-release-upgrade-user-journey-e2e" OPENCLAW_RELEASE_UPGRADE_USER_JOURNEY_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_RELEASE_UPGRADE_USER_JOURNEY_E2E_SKIP_BUILD:-0}"
run_log=""
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz release-upgrade-user-journey "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"
@@ -23,9 +32,7 @@ if ! docker_e2e_run_with_harness \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
-i "$IMAGE_NAME" bash scripts/e2e/lib/release-upgrade-user-journey/scenario.sh >"$run_log" 2>&1; then
docker_e2e_print_log "$run_log"
rm -f "$run_log"
exit 1
fi
rm -f "$run_log"
echo "Release upgrade user journey Docker E2E passed."

View File

@@ -9,6 +9,15 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-release-user-journey-e2e" OPENCLAW_RELEASE_USER_JOURNEY_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_RELEASE_USER_JOURNEY_E2E_SKIP_BUILD:-0}"
run_log=""
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz release-user-journey "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
docker_e2e_package_mount_args "$PACKAGE_TGZ"
@@ -23,9 +32,7 @@ if ! docker_e2e_run_with_harness \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
-i "$IMAGE_NAME" bash scripts/e2e/lib/release-user-journey/scenario.sh >"$run_log" 2>&1; then
docker_e2e_print_log "$run_log"
rm -f "$run_log"
exit 1
fi
rm -f "$run_log"
echo "Release user journey Docker E2E passed."

View File

@@ -8,6 +8,11 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-image.sh"
source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-skill-install-e2e" OPENCLAW_SKILL_INSTALL_E2E_IMAGE)"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz skill-install "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
OPENCLAW_TEST_STATE_SCRIPT_B64="$(docker_e2e_test_state_shell_b64 skill-install empty)"

View File

@@ -9,6 +9,11 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-update-channel-switch-e2e" OPENCLAW_UPDATE_CHANNEL_SWITCH_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_UPDATE_CHANNEL_SWITCH_E2E_SKIP_BUILD:-0}"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz update-channel-switch "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
# Bare lanes mount the package artifact instead of baking app sources into the image.
docker_e2e_package_mount_args "$PACKAGE_TGZ"

View File

@@ -10,6 +10,11 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-update-corrupt-plugin-e2e" OPENCLAW_UPDATE_CORRUPT_PLUGIN_E2E_IMAGE)"
SKIP_BUILD="${OPENCLAW_UPDATE_CORRUPT_PLUGIN_E2E_SKIP_BUILD:-0}"
cleanup() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup EXIT
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz update-corrupt-plugin "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
# Bare lanes mount the package artifact instead of baking app sources into the image.
docker_e2e_package_mount_args "$PACKAGE_TGZ"

View File

@@ -19,6 +19,10 @@ LANE_ARTIFACT_SUFFIX="${LANE_ARTIFACT_SUFFIX//[^A-Za-z0-9_.-]/_}"
ARTIFACT_DIR="${OPENCLAW_UPGRADE_SURVIVOR_ARTIFACT_DIR:-$ROOT_DIR/.artifacts/upgrade-survivor/$LANE_ARTIFACT_SUFFIX}"
ROOT_MANAGED_VPS="${OPENCLAW_UPGRADE_SURVIVOR_ROOT_MANAGED_VPS:-0}"
DOCKER_RUN_USER_ARGS=()
cleanup_outer() {
docker_e2e_cleanup_package_tgz "${PACKAGE_TGZ:-}"
}
trap cleanup_outer EXIT
if [ "$ROOT_MANAGED_VPS" = "1" ]; then
if [ "${OPENCLAW_UPGRADE_SURVIVOR_PUBLISHED_BASELINE:-0}" != "1" ]; then

View File

@@ -1,5 +1,5 @@
import { execFileSync } from "node:child_process";
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { mkdtempSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
@@ -71,6 +71,14 @@ const CENTRALIZED_BUILD_SCRIPTS = [
"scripts/test-live-build-docker.sh",
] as const;
function packageBackedDockerRunnerPaths(): string[] {
return readdirSync("scripts/e2e")
.filter((entry) => entry.endsWith("-docker.sh"))
.map((entry) => join("scripts/e2e", entry))
.filter((path) => readFileSync(path, "utf8").includes("docker_e2e_prepare_package_tgz"))
.sort();
}
function shellQuote(value: string): string {
return `'${value.replace(/'/gu, `'\\''`)}'`;
}
@@ -432,6 +440,21 @@ test -f "$TMPDIR/docker-cmd-seen"
}
});
it("cleans every prepared Docker package tarball on every runner exit path", () => {
const paths = packageBackedDockerRunnerPaths();
expect(paths.length).toBeGreaterThan(0);
for (const path of paths) {
const runner = readFileSync(path, "utf8");
expect(runner, path).toMatch(
/docker_e2e_cleanup_package_tgz "\$\{PACKAGE_TGZ:-\}"|docker_e2e_cleanup_package_tgz "\$PACKAGE_TGZ"/u,
);
expect(runner, path).toMatch(/trap cleanup(?:_outer)? EXIT/u);
expect(runner, path).not.toContain('rm -f "$run_log"\n exit 1');
}
});
it("runs skill install through the package-cleaning Docker harness", () => {
const runner = readFileSync(SKILL_INSTALL_DOCKER_E2E_PATH, "utf8");