mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:50:42 +00:00
test: add update migration package gate
This commit is contained in:
@@ -6,6 +6,7 @@ const SCENARIOS = new Set([
|
||||
"base",
|
||||
"feishu-channel",
|
||||
"bootstrap-persona",
|
||||
"plugin-deps-cleanup",
|
||||
"tilde-log-path",
|
||||
"versioned-runtime-deps",
|
||||
]);
|
||||
|
||||
@@ -53,6 +53,7 @@ BASELINE_INSTALL_LOG="$ARTIFACT_ROOT/baseline-install.log"
|
||||
UPDATE_JSON="$ARTIFACT_ROOT/update.json"
|
||||
UPDATE_ERR="$ARTIFACT_ROOT/update.err"
|
||||
DOCTOR_LOG="$ARTIFACT_ROOT/doctor.log"
|
||||
BASELINE_DOCTOR_LOG="$ARTIFACT_ROOT/baseline-doctor.log"
|
||||
GATEWAY_LOG="$ARTIFACT_ROOT/gateway.log"
|
||||
HEALTHZ_JSON="$ARTIFACT_ROOT/healthz.json"
|
||||
READYZ_JSON="$ARTIFACT_ROOT/readyz.json"
|
||||
@@ -260,6 +261,123 @@ legacy_runtime_deps_symlink_source() {
|
||||
"$plugin"
|
||||
}
|
||||
|
||||
plugin_deps_cleanup_enabled() {
|
||||
[ "$SCENARIO" = "plugin-deps-cleanup" ]
|
||||
}
|
||||
|
||||
plugin_deps_cleanup_plugins() {
|
||||
printf '%s\n' "${OPENCLAW_UPGRADE_SURVIVOR_PLUGIN_DEPS_CLEANUP_PLUGINS:-discord telegram}"
|
||||
}
|
||||
|
||||
legacy_plugin_dependency_probe_paths() {
|
||||
local plugin="$1"
|
||||
local plugin_dir
|
||||
plugin_dir="$(package_root)/dist/extensions/$plugin"
|
||||
printf '%s\n' \
|
||||
"$plugin_dir/node_modules" \
|
||||
"$plugin_dir/.openclaw-runtime-deps.json" \
|
||||
"$plugin_dir/.openclaw-runtime-deps-stamp.json" \
|
||||
"$plugin_dir/.openclaw-runtime-deps-copy-upgrade-survivor" \
|
||||
"$plugin_dir/.openclaw-install-stage-upgrade-survivor" \
|
||||
"$plugin_dir/.openclaw-pnpm-store" \
|
||||
"$(package_root)/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor" \
|
||||
"$OPENCLAW_STATE_DIR/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor" \
|
||||
"$OPENCLAW_STATE_DIR/plugin-runtime-deps/$plugin-upgrade-survivor"
|
||||
}
|
||||
|
||||
install_baseline_plugin_dependencies() {
|
||||
plugin_deps_cleanup_enabled || return 0
|
||||
echo "Running baseline doctor to install configured plugin dependencies before update."
|
||||
if ! openclaw doctor --fix --non-interactive >"$BASELINE_DOCTOR_LOG" 2>&1; then
|
||||
echo "baseline openclaw doctor failed while preparing plugin dependency cleanup scenario" >&2
|
||||
cat "$BASELINE_DOCTOR_LOG" >&2 || true
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
seed_legacy_plugin_dependency_debris() {
|
||||
plugin_deps_cleanup_enabled || return 0
|
||||
|
||||
local found=0
|
||||
local plugin
|
||||
for plugin in $(plugin_deps_cleanup_plugins); do
|
||||
local plugin_dir
|
||||
plugin_dir="$(package_root)/dist/extensions/$plugin"
|
||||
if [ ! -d "$plugin_dir" ]; then
|
||||
continue
|
||||
fi
|
||||
found=1
|
||||
mkdir -p \
|
||||
"$plugin_dir/node_modules/openclaw-upgrade-survivor-dep" \
|
||||
"$plugin_dir/.openclaw-runtime-deps-copy-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep" \
|
||||
"$plugin_dir/.openclaw-install-stage-upgrade-survivor" \
|
||||
"$plugin_dir/.openclaw-pnpm-store" \
|
||||
"$(package_root)/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep" \
|
||||
"$OPENCLAW_STATE_DIR/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep" \
|
||||
"$OPENCLAW_STATE_DIR/plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep"
|
||||
printf '{"name":"openclaw-upgrade-survivor-dep","version":"0.0.0"}\n' \
|
||||
>"$plugin_dir/node_modules/openclaw-upgrade-survivor-dep/package.json"
|
||||
printf '{"plugin":"%s","scenario":"plugin-deps-cleanup"}\n' "$plugin" \
|
||||
>"$plugin_dir/.openclaw-runtime-deps.json"
|
||||
printf '{"plugin":"%s","scenario":"plugin-deps-cleanup","stale":true}\n' "$plugin" \
|
||||
>"$plugin_dir/.openclaw-runtime-deps-stamp.json"
|
||||
printf '{"name":"openclaw-upgrade-survivor-dep","version":"0.0.0"}\n' \
|
||||
>"$plugin_dir/.openclaw-runtime-deps-copy-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep/package.json"
|
||||
printf '{"name":"openclaw-upgrade-survivor-dep","version":"0.0.0"}\n' \
|
||||
>"$(package_root)/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep/package.json"
|
||||
printf '{"name":"openclaw-upgrade-survivor-dep","version":"0.0.0"}\n' \
|
||||
>"$OPENCLAW_STATE_DIR/.local/bundled-plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep/package.json"
|
||||
printf '{"name":"openclaw-upgrade-survivor-dep","version":"0.0.0"}\n' \
|
||||
>"$OPENCLAW_STATE_DIR/plugin-runtime-deps/$plugin-upgrade-survivor/node_modules/openclaw-upgrade-survivor-dep/package.json"
|
||||
echo "Seeded legacy plugin dependency debris for configured plugin: $plugin"
|
||||
done
|
||||
|
||||
if [ "$found" -ne 1 ]; then
|
||||
echo "plugin-deps-cleanup scenario could not find a packaged Discord or Telegram plugin directory" >&2
|
||||
find "$(package_root)/dist" -maxdepth 3 -type d 2>/dev/null >&2 || true
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_legacy_plugin_dependency_debris_present() {
|
||||
plugin_deps_cleanup_enabled || return 0
|
||||
|
||||
local found=0
|
||||
local plugin
|
||||
for plugin in $(plugin_deps_cleanup_plugins); do
|
||||
local probe
|
||||
while IFS= read -r probe; do
|
||||
if [ -e "$probe" ] || [ -L "$probe" ]; then
|
||||
found=1
|
||||
fi
|
||||
done < <(legacy_plugin_dependency_probe_paths "$plugin")
|
||||
done
|
||||
if [ "$found" -ne 1 ]; then
|
||||
echo "plugin-deps-cleanup scenario did not create legacy plugin dependency debris" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_legacy_plugin_dependency_debris_cleaned() {
|
||||
plugin_deps_cleanup_enabled || return 0
|
||||
|
||||
local remaining=0
|
||||
local plugin
|
||||
for plugin in $(plugin_deps_cleanup_plugins); do
|
||||
local probe
|
||||
while IFS= read -r probe; do
|
||||
if [ -e "$probe" ] || [ -L "$probe" ]; then
|
||||
echo "legacy plugin dependency debris survived update/doctor: $probe" >&2
|
||||
remaining=1
|
||||
fi
|
||||
done < <(legacy_plugin_dependency_probe_paths "$plugin")
|
||||
done
|
||||
if [ "$remaining" -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
echo "Legacy plugin dependency debris cleaned for configured plugin dependencies."
|
||||
}
|
||||
|
||||
seed_legacy_runtime_deps_symlink() {
|
||||
local plugin
|
||||
plugin="$(legacy_runtime_deps_symlink_plugin)" || {
|
||||
@@ -532,11 +650,16 @@ phase install-baseline install_baseline
|
||||
phase seed-state seed_state
|
||||
phase apply-baseline-config-recipe apply_baseline_config_recipe
|
||||
phase validate-baseline-config validate_baseline_config
|
||||
phase install-baseline-plugin-dependencies install_baseline_plugin_dependencies
|
||||
phase seed-legacy-plugin-dependency-debris seed_legacy_plugin_dependency_debris
|
||||
phase assert-legacy-plugin-dependency-debris assert_legacy_plugin_dependency_debris_present
|
||||
phase assert-baseline assert_baseline_state
|
||||
phase seed-legacy-runtime-deps-symlink seed_legacy_runtime_deps_symlink
|
||||
phase resolve-candidate resolve_candidate_version
|
||||
phase update-candidate update_candidate
|
||||
phase assert-legacy-plugin-dependency-debris-before-doctor assert_legacy_plugin_dependency_debris_present
|
||||
phase doctor run_doctor
|
||||
phase assert-legacy-plugin-dependency-debris-cleaned assert_legacy_plugin_dependency_debris_cleaned
|
||||
phase assert-legacy-runtime-deps-symlink-repaired assert_legacy_runtime_deps_symlink_repaired
|
||||
phase validate-post-doctor-config validate_post_doctor_config
|
||||
phase assert-survival assert_survival
|
||||
|
||||
@@ -73,6 +73,7 @@ export const UPGRADE_SURVIVOR_SCENARIOS = [
|
||||
"base",
|
||||
"feishu-channel",
|
||||
"bootstrap-persona",
|
||||
"plugin-deps-cleanup",
|
||||
"tilde-log-path",
|
||||
"versioned-runtime-deps",
|
||||
];
|
||||
@@ -153,7 +154,7 @@ export function expandUpgradeSurvivorBaselineLanes(poolLanes, rawBaselineSpecs,
|
||||
return poolLanes;
|
||||
}
|
||||
return poolLanes.flatMap((poolLane) => {
|
||||
if (poolLane.name !== "published-upgrade-survivor") {
|
||||
if (poolLane.name !== "published-upgrade-survivor" && poolLane.name !== "update-migration") {
|
||||
return [poolLane];
|
||||
}
|
||||
const matrixBaselines = baselineSpecs.length > 0 ? baselineSpecs : [undefined];
|
||||
|
||||
@@ -222,6 +222,11 @@ export const mainLanes = [
|
||||
weight: 3,
|
||||
},
|
||||
),
|
||||
npmLane("update-migration", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:update-migration", {
|
||||
stateScenario: "upgrade-survivor",
|
||||
timeoutMs: 30 * 60 * 1000,
|
||||
weight: 3,
|
||||
}),
|
||||
lane("plugins", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:plugins", {
|
||||
resources: ["npm", "service"],
|
||||
stateScenario: "empty",
|
||||
|
||||
@@ -50,6 +50,29 @@ function stableVersionFromTag(tagName) {
|
||||
return version;
|
||||
}
|
||||
|
||||
function parseStableVersion(version) {
|
||||
const match = /^([0-9]{4})\.([0-9]+)\.([0-9]+)(?:-([0-9]+))?$/u.exec(String(version ?? ""));
|
||||
if (!match) {
|
||||
return undefined;
|
||||
}
|
||||
return match.slice(1).map((part) => Number.parseInt(part ?? "0", 10));
|
||||
}
|
||||
|
||||
function compareStableVersions(left, right) {
|
||||
const leftParts = parseStableVersion(left);
|
||||
const rightParts = parseStableVersion(right);
|
||||
if (!leftParts || !rightParts) {
|
||||
throw new Error(`cannot compare release versions: ${left} ${right}`);
|
||||
}
|
||||
for (let index = 0; index < Math.max(leftParts.length, rightParts.length); index += 1) {
|
||||
const delta = (leftParts[index] ?? 0) - (rightParts[index] ?? 0);
|
||||
if (delta !== 0) {
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function npmPublishedVersion(version, publishedVersions) {
|
||||
if (!version || !publishedVersions) {
|
||||
return version;
|
||||
@@ -105,6 +128,20 @@ export function resolveReleaseHistory(args) {
|
||||
return dedupeSpecs(versions);
|
||||
}
|
||||
|
||||
export function resolveAllSince(args, minimumVersion) {
|
||||
const releasesJson = args.get("releases-json");
|
||||
if (!releasesJson) {
|
||||
throw new Error("--releases-json is required when requested baselines include all-since-*");
|
||||
}
|
||||
const publishedVersions = readPublishedVersions(args.get("npm-versions-json"));
|
||||
const releases = readStableReleases(releasesJson, publishedVersions);
|
||||
return dedupeSpecs(
|
||||
releases
|
||||
.map((release) => release.version)
|
||||
.filter((version) => compareStableVersions(version, minimumVersion) >= 0),
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveBaselines(args) {
|
||||
const requested = args.get("requested") ?? "";
|
||||
const fallback = args.get("fallback") ?? "openclaw@latest";
|
||||
@@ -117,6 +154,12 @@ export function resolveBaselines(args) {
|
||||
for (const token of requestedTokens) {
|
||||
if (token === "release-history") {
|
||||
resolved.push(...resolveReleaseHistory(args));
|
||||
} else if (token.startsWith("all-since-")) {
|
||||
const minimumVersion = token.slice("all-since-".length);
|
||||
if (!parseStableVersion(minimumVersion)) {
|
||||
throw new Error(`invalid all-since baseline token: ${token}`);
|
||||
}
|
||||
resolved.push(...resolveAllSince(args, minimumVersion));
|
||||
} else {
|
||||
exactTokens.push(token);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user