mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix: handle npm min-release-age in installers
Replays #84749 because the contributor fork branch became conflicted and was no longer maintainer-writable. Co-authored-by: TeodoroRodrigo <rodrigoteodoro.90@gmail.com>
This commit is contained in:
committed by
GitHub
parent
6704d0ab27
commit
316d97c938
@@ -1,5 +1,15 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { chmodSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
||||
import {
|
||||
chmodSync,
|
||||
lstatSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
readlinkSync,
|
||||
rmSync,
|
||||
symlinkSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
@@ -23,6 +33,74 @@ function linkRequiredShellTools(bin: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function writeNpmFreshnessConflictFixture(path: string, argsLog: string) {
|
||||
writeFileSync(
|
||||
path,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
"set -euo pipefail",
|
||||
`printf '%s\\n' "$*" >> ${JSON.stringify(argsLog)}`,
|
||||
'if [[ "$1" == "config" && "$2" == "get" && "$3" == "min-release-age" ]]; then',
|
||||
" printf 'null\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'if [[ "$1" == "config" && "$2" == "get" && "$3" == "before" ]]; then',
|
||||
" printf 'Wed May 13 2026 21:25:20 GMT-0300 (Brasilia Standard Time)\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'for arg in "$@"; do',
|
||||
' if [[ "$arg" == --before=* ]]; then',
|
||||
" printf '%s\\n' 'Exit prior to config file resolving' >&2",
|
||||
" printf '%s\\n' 'cause' >&2",
|
||||
" printf '%s\\n' '--min-release-age cannot be provided when using --before' >&2",
|
||||
" exit 64",
|
||||
" fi",
|
||||
"done",
|
||||
'for arg in "$@"; do',
|
||||
' if [[ "$arg" == "--min-release-age=0" ]]; then',
|
||||
" exit 0",
|
||||
" fi",
|
||||
"done",
|
||||
"exit 65",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(path, 0o755);
|
||||
}
|
||||
|
||||
function writeNpmBeforePolicyFixture(path: string, argsLog: string) {
|
||||
writeFileSync(
|
||||
path,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
"set -euo pipefail",
|
||||
`printf '%s\\n' "$*" >> ${JSON.stringify(argsLog)}`,
|
||||
'if [[ "$1" == "config" && "$2" == "get" && "$3" == "min-release-age" ]]; then',
|
||||
" printf 'null\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'if [[ "$1" == "config" && "$2" == "get" && "$3" == "before" ]]; then',
|
||||
" printf 'Wed May 13 2026 21:25:20 GMT-0300 (Brasilia Standard Time)\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'for arg in "$@"; do',
|
||||
' if [[ "$arg" == "--min-release-age=0" ]]; then',
|
||||
" printf '%s\\n' 'min-release-age should not be selected for project-only npmrc' >&2",
|
||||
" exit 64",
|
||||
" fi",
|
||||
"done",
|
||||
'for arg in "$@"; do',
|
||||
' if [[ "$arg" == --before=* ]]; then',
|
||||
" exit 0",
|
||||
" fi",
|
||||
"done",
|
||||
"exit 65",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(path, 0o755);
|
||||
}
|
||||
|
||||
describe("install-cli.sh", () => {
|
||||
const script = readFileSync(SCRIPT_PATH, "utf8");
|
||||
|
||||
@@ -144,12 +222,7 @@ describe("install-cli.sh", () => {
|
||||
linkRequiredShellTools(bin);
|
||||
writeFileSync(
|
||||
fakeApk,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'printf "%s\\n" "$*" >> "$APK_LOG"',
|
||||
"exit 99",
|
||||
"",
|
||||
].join("\n"),
|
||||
["#!/bin/bash", 'printf "%s\\n" "$*" >> "$APK_LOG"', "exit 99", ""].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNode,
|
||||
@@ -166,14 +239,7 @@ describe("install-cli.sh", () => {
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(fakeNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(fakeApk, 0o755);
|
||||
chmodSync(fakeNode, 0o755);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
@@ -233,12 +299,7 @@ describe("install-cli.sh", () => {
|
||||
mkdirSync(nodePrefixBin, { recursive: true });
|
||||
writeFileSync(
|
||||
fakeApk,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'printf "%s\\n" "$*" >> "$APK_LOG"',
|
||||
"exit 99",
|
||||
"",
|
||||
].join("\n"),
|
||||
["#!/bin/bash", 'printf "%s\\n" "$*" >> "$APK_LOG"', "exit 99", ""].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
staleNode,
|
||||
@@ -285,22 +346,8 @@ describe("install-cli.sh", () => {
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
oldNpm,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(oldNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
writeFileSync(fakeNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(fakeApk, 0o755);
|
||||
chmodSync(staleNode, 0o755);
|
||||
chmodSync(oldNode, 0o755);
|
||||
@@ -384,14 +431,7 @@ describe("install-cli.sh", () => {
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(fakeNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(fakeApk, 0o755);
|
||||
chmodSync(fakeNode, 0o755);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
@@ -446,12 +486,7 @@ describe("install-cli.sh", () => {
|
||||
linkRequiredShellTools(bin);
|
||||
writeFileSync(
|
||||
fakeApk,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'printf "%s\\n" "$*" >> "$APK_LOG"',
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
["#!/bin/bash", 'printf "%s\\n" "$*" >> "$APK_LOG"', "exit 0", ""].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNode,
|
||||
@@ -468,14 +503,7 @@ describe("install-cli.sh", () => {
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(fakeNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(fakeApk, 0o755);
|
||||
chmodSync(fakeNode, 0o755);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
@@ -504,7 +532,9 @@ describe("install-cli.sh", () => {
|
||||
|
||||
expect(result.status).toBe(1);
|
||||
expect(readFileSync(apkLog, "utf8")).toContain("add --no-cache nodejs npm");
|
||||
expect(result.stdout).toContain("Alpine Node package must provide Node >= 22.22.0 with node:sqlite");
|
||||
expect(result.stdout).toContain(
|
||||
"Alpine Node package must provide Node >= 22.22.0 with node:sqlite",
|
||||
);
|
||||
expect(result.stdout).toContain("found v22.18.0");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
@@ -513,7 +543,7 @@ describe("install-cli.sh", () => {
|
||||
|
||||
it("clears npm freshness filters for package installs", () => {
|
||||
expect(script).toContain('freshness_flag="--min-release-age=0"');
|
||||
expect(script).toContain('npm_raw_config_has_key "min-release-age"');
|
||||
expect(script).toContain('npm_config_has_raw_key "$(npm_bin)" "min-release-age"');
|
||||
expect(script).toContain('freshness_flag="--before=$(date -u');
|
||||
expect(script).toContain("env -u NPM_CONFIG_BEFORE -u npm_config_before");
|
||||
});
|
||||
@@ -748,4 +778,78 @@ describe("install-cli.sh", () => {
|
||||
expect(result.stdout).toContain("npm installs do not support OpenClaw GitHub source targets");
|
||||
expect(result.stdout).toContain("--install-method git --version main");
|
||||
});
|
||||
|
||||
it("does not emit before args when npmrc min-release-age computes a before cutoff", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-freshness-"));
|
||||
const prefix = join(tmp, "prefix");
|
||||
const home = join(tmp, "home");
|
||||
const nodeBin = join(prefix, "tools/node-v22.22.0/bin");
|
||||
const argsLog = join(tmp, "npm-args.log");
|
||||
mkdirSync(nodeBin, { recursive: true });
|
||||
mkdirSync(home, { recursive: true });
|
||||
writeFileSync(join(home, ".npmrc"), "min-release-age=7\n");
|
||||
writeNpmFreshnessConflictFixture(join(nodeBin, "npm"), argsLog);
|
||||
|
||||
let result: ReturnType<typeof runInstallCliShell> | undefined;
|
||||
let argsOutput = "";
|
||||
try {
|
||||
result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`HOME=${JSON.stringify(home)}`,
|
||||
`OPENCLAW_PREFIX=${JSON.stringify(prefix)}`,
|
||||
"OPENCLAW_VERSION=2026.5.19",
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
"ensure_git() { return 0; }",
|
||||
"install_openclaw",
|
||||
].join("\n"),
|
||||
);
|
||||
argsOutput = readFileSync(argsLog, "utf8");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
expect(result?.status).toBe(0);
|
||||
expect(argsOutput).toContain("--min-release-age=0");
|
||||
expect(argsOutput).not.toContain("--before=");
|
||||
});
|
||||
|
||||
it("ignores project npmrc when choosing global install freshness args", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-global-freshness-"));
|
||||
const prefix = join(tmp, "prefix");
|
||||
const home = join(tmp, "home");
|
||||
const project = join(tmp, "project");
|
||||
const nodeBin = join(prefix, "tools/node-v22.22.0/bin");
|
||||
const argsLog = join(tmp, "npm-args.log");
|
||||
mkdirSync(nodeBin, { recursive: true });
|
||||
mkdirSync(home, { recursive: true });
|
||||
mkdirSync(project, { recursive: true });
|
||||
writeFileSync(join(home, ".npmrc"), "before=2026-01-01T00:00:00.000Z\n");
|
||||
writeFileSync(join(project, ".npmrc"), "min-release-age=7\n");
|
||||
writeNpmBeforePolicyFixture(join(nodeBin, "npm"), argsLog);
|
||||
|
||||
let result: ReturnType<typeof runInstallCliShell> | undefined;
|
||||
let argsOutput = "";
|
||||
try {
|
||||
result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(project)}`,
|
||||
`HOME=${JSON.stringify(home)}`,
|
||||
`OPENCLAW_PREFIX=${JSON.stringify(prefix)}`,
|
||||
"OPENCLAW_VERSION=2026.5.19",
|
||||
`source ${JSON.stringify(process.cwd() + "/" + SCRIPT_PATH)}`,
|
||||
"ensure_git() { return 0; }",
|
||||
"install_openclaw",
|
||||
].join("\n"),
|
||||
);
|
||||
argsOutput = readFileSync(argsLog, "utf8");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
expect(result?.status).toBe(0);
|
||||
expect(argsOutput).toContain("--before=");
|
||||
expect(argsOutput).not.toContain("--min-release-age=0");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user