mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
fix(release): stabilize slow live release gates
This commit is contained in:
@@ -147,6 +147,33 @@ function parseUpgradeSurvivorScenarios(raw) {
|
||||
];
|
||||
}
|
||||
|
||||
function parsePublishedReleaseVersion(spec) {
|
||||
const match = /^openclaw@([0-9]{4})\.([0-9]+)\.([0-9]+)/u.exec(String(spec ?? ""));
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
year: Number(match[1]),
|
||||
month: Number(match[2]),
|
||||
day: Number(match[3]),
|
||||
};
|
||||
}
|
||||
|
||||
function comparePublishedReleaseVersion(a, b) {
|
||||
return a.year - b.year || a.month - b.month || a.day - b.day;
|
||||
}
|
||||
|
||||
function supportsUpgradeSurvivorPluginDependencyCleanup(baselineSpec) {
|
||||
if (!baselineSpec) {
|
||||
return true;
|
||||
}
|
||||
const version = parsePublishedReleaseVersion(baselineSpec);
|
||||
if (!version) {
|
||||
return true;
|
||||
}
|
||||
return comparePublishedReleaseVersion(version, { year: 2026, month: 4, day: 23 }) >= 0;
|
||||
}
|
||||
|
||||
function expandUpgradeSurvivorBaselineLanes(poolLanes, rawBaselineSpecs, rawScenarios = "") {
|
||||
const baselineSpecs = parseUpgradeSurvivorBaselineSpecs(rawBaselineSpecs);
|
||||
const scenarios = parseUpgradeSurvivorScenarios(rawScenarios);
|
||||
@@ -160,30 +187,38 @@ function expandUpgradeSurvivorBaselineLanes(poolLanes, rawBaselineSpecs, rawScen
|
||||
const matrixBaselines = baselineSpecs.length > 0 ? baselineSpecs : [undefined];
|
||||
const matrixScenarios = scenarios.length > 0 ? scenarios : [undefined];
|
||||
return matrixBaselines.flatMap((baselineSpec) =>
|
||||
matrixScenarios.map((scenario) => {
|
||||
const suffixParts = [
|
||||
baselineSpec ? sanitizeLaneNameSuffix(baselineSpec) : "",
|
||||
scenario && scenario !== "base" ? sanitizeLaneNameSuffix(scenario) : "",
|
||||
].filter(Boolean);
|
||||
const suffix = suffixParts.join("-");
|
||||
const name = suffix ? `${poolLane.name}-${suffix}` : poolLane.name;
|
||||
const commandPrefix = [
|
||||
`OPENCLAW_UPGRADE_SURVIVOR_ARTIFACT_DIR="$PWD/.artifacts/upgrade-survivor/${name}"`,
|
||||
baselineSpec ? `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=${shellQuote(baselineSpec)}` : "",
|
||||
scenario ? `OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=${shellQuote(scenario)}` : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
return Object.assign({}, poolLane, {
|
||||
cacheKey: poolLane.cacheKey
|
||||
? suffix
|
||||
? `${poolLane.cacheKey}-${suffix}`
|
||||
: poolLane.cacheKey
|
||||
: name,
|
||||
command: commandPrefix ? `${commandPrefix} ${poolLane.command}` : poolLane.command,
|
||||
name,
|
||||
});
|
||||
}),
|
||||
matrixScenarios
|
||||
.filter(
|
||||
(scenario) =>
|
||||
scenario !== "plugin-deps-cleanup" ||
|
||||
supportsUpgradeSurvivorPluginDependencyCleanup(baselineSpec),
|
||||
)
|
||||
.map((scenario) => {
|
||||
const suffixParts = [
|
||||
baselineSpec ? sanitizeLaneNameSuffix(baselineSpec) : "",
|
||||
scenario && scenario !== "base" ? sanitizeLaneNameSuffix(scenario) : "",
|
||||
].filter(Boolean);
|
||||
const suffix = suffixParts.join("-");
|
||||
const name = suffix ? `${poolLane.name}-${suffix}` : poolLane.name;
|
||||
const commandPrefix = [
|
||||
`OPENCLAW_UPGRADE_SURVIVOR_ARTIFACT_DIR="$PWD/.artifacts/upgrade-survivor/${name}"`,
|
||||
baselineSpec
|
||||
? `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=${shellQuote(baselineSpec)}`
|
||||
: "",
|
||||
scenario ? `OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=${shellQuote(scenario)}` : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
return Object.assign({}, poolLane, {
|
||||
cacheKey: poolLane.cacheKey
|
||||
? suffix
|
||||
? `${poolLane.cacheKey}-${suffix}`
|
||||
: poolLane.cacheKey
|
||||
: name,
|
||||
command: commandPrefix ? `${commandPrefix} ${poolLane.command}` : poolLane.command,
|
||||
name,
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ const SUPPORTED_SUITES = new Set([
|
||||
"dev-update",
|
||||
]);
|
||||
|
||||
export const CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS = parsePositiveIntegerEnv(
|
||||
"OPENCLAW_CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS",
|
||||
1200,
|
||||
);
|
||||
|
||||
const providerConfig = {
|
||||
openai: {
|
||||
extensionId: "openai",
|
||||
@@ -41,7 +46,7 @@ const providerConfig = {
|
||||
authChoice: "openai-api-key",
|
||||
model: "openai/gpt-5.4",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
timeoutSeconds: 600,
|
||||
timeoutSeconds: CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS,
|
||||
},
|
||||
anthropic: {
|
||||
extensionId: "anthropic",
|
||||
@@ -112,7 +117,6 @@ export const CROSS_OS_GATEWAY_STATUS_COMMAND_TIMEOUT_MS =
|
||||
CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS + 45_000;
|
||||
export const CROSS_OS_GATEWAY_READY_TIMEOUT_MS = 3 * 60_000;
|
||||
export const CROSS_OS_WINDOWS_GATEWAY_READY_TIMEOUT_MS = 5 * 60_000;
|
||||
export const CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS = 600;
|
||||
export const CROSS_OS_RELEASE_SMOKE_TOOLS_PROFILE = "minimal";
|
||||
|
||||
if (isMainModule()) {
|
||||
@@ -151,6 +155,18 @@ export function parseArgs(argv) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parsePositiveIntegerEnv(name, fallback) {
|
||||
const raw = process.env[name]?.trim();
|
||||
if (!raw) {
|
||||
return fallback;
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value) || value <= 0) {
|
||||
throw new Error(`${name} must be a positive integer. Got: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function looksLikeReleaseVersionRef(ref) {
|
||||
const trimmed = normalizeRequestedRef(ref);
|
||||
return /^v?[0-9]{4}\.[0-9]+\.[0-9]+(?:-(?:[1-9][0-9]*)|[-.](?:beta|rc)[-.]?[0-9]+)?$/iu.test(
|
||||
|
||||
@@ -56,12 +56,27 @@ const DEFAULT_MODEL =
|
||||
// The cron/MCP live probe now tolerates more cancelled tool-call retries in CI,
|
||||
// so the outer test budget needs enough headroom to finish those retries.
|
||||
const CLI_BACKEND_LIVE_TIMEOUT_MS = 20 * 60_000;
|
||||
const CLI_BACKEND_REQUEST_TIMEOUT_MS = 600_000;
|
||||
const CLI_BACKEND_REQUEST_TIMEOUT_MS = parsePositiveIntegerEnv(
|
||||
"OPENCLAW_LIVE_CLI_BACKEND_REQUEST_TIMEOUT_MS",
|
||||
15 * 60_000,
|
||||
);
|
||||
const CLI_BACKEND_AGENT_TIMEOUT_SECONDS = Math.max(
|
||||
1,
|
||||
Math.ceil(CLI_BACKEND_REQUEST_TIMEOUT_MS / 1000) - 10,
|
||||
);
|
||||
|
||||
function parsePositiveIntegerEnv(name: string, fallback: number): number {
|
||||
const raw = process.env[name]?.trim();
|
||||
if (!raw) {
|
||||
return fallback;
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value) || value <= 0) {
|
||||
throw new Error(`${name} must be a positive integer. Got: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function logCliBackendLiveStep(step: string, details?: Record<string, unknown>): void {
|
||||
if (!CLI_DEBUG) {
|
||||
return;
|
||||
|
||||
@@ -358,6 +358,28 @@ describe("scripts/lib/docker-e2e-plan", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("skips plugin dependency cleanup for baselines without packaged plugin dirs", () => {
|
||||
const plan = planFor({
|
||||
selectedLaneNames: ["published-upgrade-survivor"],
|
||||
upgradeSurvivorBaselines: "2026.4.29 2026.3.13",
|
||||
upgradeSurvivorScenarios: "reported-issues",
|
||||
});
|
||||
|
||||
expect(plan.lanes.map((lane) => lane.name)).toEqual([
|
||||
"published-upgrade-survivor-2026.4.29",
|
||||
"published-upgrade-survivor-2026.4.29-feishu-channel",
|
||||
"published-upgrade-survivor-2026.4.29-bootstrap-persona",
|
||||
"published-upgrade-survivor-2026.4.29-plugin-deps-cleanup",
|
||||
"published-upgrade-survivor-2026.4.29-tilde-log-path",
|
||||
"published-upgrade-survivor-2026.4.29-versioned-runtime-deps",
|
||||
"published-upgrade-survivor-2026.3.13",
|
||||
"published-upgrade-survivor-2026.3.13-feishu-channel",
|
||||
"published-upgrade-survivor-2026.3.13-bootstrap-persona",
|
||||
"published-upgrade-survivor-2026.3.13-tilde-log-path",
|
||||
"published-upgrade-survivor-2026.3.13-versioned-runtime-deps",
|
||||
]);
|
||||
});
|
||||
|
||||
it("expands update migration across baselines and cleanup scenarios", () => {
|
||||
const plan = planFor({
|
||||
selectedLaneNames: ["update-migration"],
|
||||
|
||||
Reference in New Issue
Block a user