mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(ci): preserve cross-os candidate fallbacks
This commit is contained in:
@@ -699,49 +699,87 @@ async function prepareCandidate(params) {
|
||||
sourceDir: params.sourceDir,
|
||||
logPath: join(params.logsDir, "pnpm-pack-dry-run.log"),
|
||||
});
|
||||
logPhase("prepare", "package-candidate");
|
||||
const packResult = await runCommand(
|
||||
process.execPath,
|
||||
[
|
||||
join(params.sourceDir, "scripts", "package-openclaw-for-docker.mjs"),
|
||||
"--skip-build",
|
||||
"--source-dir",
|
||||
params.sourceDir,
|
||||
"--output-dir",
|
||||
packDir,
|
||||
],
|
||||
{
|
||||
cwd: params.sourceDir,
|
||||
logPath: join(params.logsDir, "package-candidate.log"),
|
||||
timeoutMs: 15 * 60 * 1000,
|
||||
},
|
||||
);
|
||||
const packOutputLines = packResult.stdout.trim().split(/\r?\n/u).filter(Boolean);
|
||||
const packedTarball = resolvePackDestinationTarball(
|
||||
packOutputLines.at(-1),
|
||||
const packCommand = resolvePackageCandidatePackCommand(params.sourceDir, packDir);
|
||||
logPhase("prepare", packCommand.phase);
|
||||
const packResult = await runCommand(packCommand.command, packCommand.args, {
|
||||
cwd: params.sourceDir,
|
||||
logPath: join(params.logsDir, packCommand.logFileName),
|
||||
timeoutMs: 15 * 60 * 1000,
|
||||
});
|
||||
const packedCandidate = resolvePackedCandidateFromOutput({
|
||||
output: packResult.stdout,
|
||||
packDir,
|
||||
"package-openclaw-for-docker",
|
||||
);
|
||||
writeFileSync(
|
||||
packJsonPath,
|
||||
`${JSON.stringify(
|
||||
{
|
||||
filename: packedTarball.fileName,
|
||||
path: packedTarball.path,
|
||||
version: packageJson.version,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
packageJson,
|
||||
packCommand,
|
||||
});
|
||||
writeFileSync(packJsonPath, packedCandidate.packJson, "utf8");
|
||||
|
||||
return {
|
||||
sourceDir: params.sourceDir,
|
||||
sourceSha,
|
||||
candidateVersion: String(packageJson.version ?? "").trim(),
|
||||
candidateTgz: packedTarball.path,
|
||||
candidateFileName: packedTarball.fileName,
|
||||
candidateVersion: packedCandidate.version,
|
||||
candidateTgz: packedCandidate.path,
|
||||
candidateFileName: packedCandidate.fileName,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePackageCandidatePackCommand(sourceDir, packDir) {
|
||||
const packageHelper = join(sourceDir, "scripts", "package-openclaw-for-docker.mjs");
|
||||
if (existsSync(packageHelper)) {
|
||||
return {
|
||||
args: [packageHelper, "--skip-build", "--source-dir", sourceDir, "--output-dir", packDir],
|
||||
command: process.execPath,
|
||||
kind: "docker-helper",
|
||||
logFileName: "package-candidate.log",
|
||||
phase: "package-candidate",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
args: ["pack", "--config.ignore-scripts=true", "--json", "--pack-destination", packDir],
|
||||
command: pnpmCommand(),
|
||||
kind: "pnpm-pack",
|
||||
logFileName: "pnpm-pack.log",
|
||||
phase: "pnpm-pack",
|
||||
};
|
||||
}
|
||||
|
||||
function resolvePackedCandidateFromOutput(params) {
|
||||
if (params.packCommand.kind === "docker-helper") {
|
||||
const packOutputLines = params.output.trim().split(/\r?\n/u).filter(Boolean);
|
||||
const packedTarball = resolvePackDestinationTarball(
|
||||
packOutputLines.at(-1),
|
||||
params.packDir,
|
||||
"package-openclaw-for-docker",
|
||||
);
|
||||
return {
|
||||
fileName: packedTarball.fileName,
|
||||
packJson: `${JSON.stringify(
|
||||
{
|
||||
filename: packedTarball.fileName,
|
||||
path: packedTarball.path,
|
||||
version: params.packageJson.version,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
path: packedTarball.path,
|
||||
version: String(params.packageJson.version ?? "").trim(),
|
||||
};
|
||||
}
|
||||
|
||||
const parsedPack = JSON.parse(params.output);
|
||||
const lastPack = Array.isArray(parsedPack) ? parsedPack.at(-1) : parsedPack;
|
||||
const packedTarball = resolvePackDestinationTarball(
|
||||
lastPack?.filename,
|
||||
params.packDir,
|
||||
"pnpm pack",
|
||||
);
|
||||
return {
|
||||
fileName: packedTarball.fileName,
|
||||
packJson: params.output,
|
||||
path: packedTarball.path,
|
||||
version: String(lastPack?.version ?? params.packageJson.version ?? "").trim(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2973,7 +3011,9 @@ export function appendLatestNpmDebugLogTail(
|
||||
env = process.env,
|
||||
platform = process.platform,
|
||||
) {
|
||||
const candidates = resolveNpmDebugLogDirs(homeDir, env, platform).flatMap(findNpmDebugLogs);
|
||||
const candidates = resolveNpmDebugLogDirs(homeDir, env, platform)
|
||||
.flatMap(findNpmDebugLogs)
|
||||
.toSorted((left, right) => left.mtimeMs - right.mtimeMs);
|
||||
const latest = candidates.at(-1);
|
||||
if (!latest) {
|
||||
return "";
|
||||
@@ -2993,8 +3033,16 @@ export function appendLatestNpmDebugLogTail(
|
||||
}
|
||||
|
||||
export function resolveNpmDebugLogDirs(homeDir, env = process.env, platform = process.platform) {
|
||||
const configuredLogsDir = String(env.npm_config_logs_dir ?? env.NPM_CONFIG_LOGS_DIR ?? "").trim();
|
||||
const configuredCache = String(env.npm_config_cache ?? env.NPM_CONFIG_CACHE ?? "").trim();
|
||||
const configuredLogsDir = resolveNpmConfiguredPath(
|
||||
homeDir,
|
||||
env.npm_config_logs_dir ?? env.NPM_CONFIG_LOGS_DIR,
|
||||
platform,
|
||||
);
|
||||
const configuredCache = resolveNpmConfiguredPath(
|
||||
homeDir,
|
||||
env.npm_config_cache ?? env.NPM_CONFIG_CACHE,
|
||||
platform,
|
||||
);
|
||||
const localAppData = String(env.LOCALAPPDATA ?? "").trim();
|
||||
const logDirs = [
|
||||
configuredLogsDir,
|
||||
@@ -3005,6 +3053,14 @@ export function resolveNpmDebugLogDirs(homeDir, env = process.env, platform = pr
|
||||
return [...new Set(logDirs)];
|
||||
}
|
||||
|
||||
function resolveNpmConfiguredPath(homeDir, value, platform) {
|
||||
const raw = String(value ?? "").trim();
|
||||
if (!raw) {
|
||||
return "";
|
||||
}
|
||||
return platform === "win32" ? pathWin32.resolve(homeDir, raw) : resolve(homeDir, raw);
|
||||
}
|
||||
|
||||
function normalizeNpmCacheLogDir(logDir) {
|
||||
return logDir.endsWith("/_logs") || logDir.endsWith("\\_logs") ? logDir : join(logDir, "_logs");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
realpathSync,
|
||||
rmSync,
|
||||
symlinkSync,
|
||||
utimesSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { createConnection as createNetConnection, createServer as createNetServer } from "node:net";
|
||||
@@ -77,6 +78,7 @@ import {
|
||||
resolveNpmPackTarballFileName,
|
||||
resolveNpmDebugLogDirs,
|
||||
resolvePackDestinationTarball,
|
||||
resolvePackageCandidatePackCommand,
|
||||
resolveProviderConfig,
|
||||
resolveDevUpdateVerificationRef,
|
||||
resolveInstalledPrefixDirFromCliPath,
|
||||
@@ -660,6 +662,33 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("falls back to pnpm pack for historical refs without the Docker package helper", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "openclaw-cross-os-pack-command-"));
|
||||
try {
|
||||
const packDir = join(dir, "out");
|
||||
const fallback = resolvePackageCandidatePackCommand(dir, packDir);
|
||||
|
||||
expect(fallback).toMatchObject({
|
||||
args: ["pack", "--config.ignore-scripts=true", "--json", "--pack-destination", packDir],
|
||||
command: process.platform === "win32" ? "pnpm.cmd" : "pnpm",
|
||||
kind: "pnpm-pack",
|
||||
});
|
||||
|
||||
const helperPath = join(dir, "scripts", "package-openclaw-for-docker.mjs");
|
||||
mkdirSync(dirname(helperPath), { recursive: true });
|
||||
writeFileSync(helperPath, "export {};\n");
|
||||
const helper = resolvePackageCandidatePackCommand(dir, packDir);
|
||||
|
||||
expect(helper).toMatchObject({
|
||||
args: [helperPath, "--skip-build", "--source-dir", dir, "--output-dir", packDir],
|
||||
command: process.execPath,
|
||||
kind: "docker-helper",
|
||||
});
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps the Windows packaged-upgrade fallback install out of npm lifecycle scripts", () => {
|
||||
const source = readFileSync("scripts/openclaw-cross-os-release-checks.ts", "utf8");
|
||||
const fallbackInstallSource = source.slice(
|
||||
@@ -1365,6 +1394,16 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
|
||||
const logsDir = join(dir, "custom-logs");
|
||||
const logPath = join(dir, "install.log");
|
||||
mkdirSync(logsDir, { recursive: true });
|
||||
mkdirSync(join(homeDir, ".npm", "_logs"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(homeDir, ".npm", "_logs", "2026-07-05T00_00_00_000Z-debug-0.log"),
|
||||
"old fallback log\n",
|
||||
);
|
||||
utimesSync(
|
||||
join(homeDir, ".npm", "_logs", "2026-07-05T00_00_00_000Z-debug-0.log"),
|
||||
new Date("2020-01-01T00:00:00Z"),
|
||||
new Date("2020-01-01T00:00:00Z"),
|
||||
);
|
||||
writeFileSync(join(logsDir, "2026-07-05T00_00_00_000Z-debug-0.log"), "custom log\n");
|
||||
writeFileSync(logPath, "install failed\n");
|
||||
|
||||
@@ -1378,6 +1417,26 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("resolves relative npm log config from the install working directory", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "openclaw-cross-os-npm-relative-logs-"));
|
||||
try {
|
||||
const homeDir = join(dir, "home");
|
||||
const logsDir = join(homeDir, "relative-logs");
|
||||
const cacheLogsDir = join(homeDir, "relative-cache", "_logs");
|
||||
mkdirSync(logsDir, { recursive: true });
|
||||
mkdirSync(cacheLogsDir, { recursive: true });
|
||||
|
||||
expect(resolveNpmDebugLogDirs(homeDir, { npm_config_logs_dir: "relative-logs" })).toContain(
|
||||
logsDir,
|
||||
);
|
||||
expect(resolveNpmDebugLogDirs(homeDir, { npm_config_cache: "relative-cache" })).toContain(
|
||||
cacheLogsDir,
|
||||
);
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("kills timed-out command process groups", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user