mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(tooling): centralize positive env integers (#113277)
This commit is contained in:
@@ -5,32 +5,18 @@ import { spawnSync } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { readPositiveEnvInt } from "./lib/numeric-options.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const entryCandidates = ["dist/entry.js", "dist/entry.mjs"];
|
||||
const startupMetadataPath = "dist/cli-startup-metadata.json";
|
||||
const DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1000;
|
||||
|
||||
function positiveEnvInt(name, env, fallback) {
|
||||
const raw = env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the CLI startup build timeout from environment.
|
||||
*/
|
||||
export function resolveCliStartupBuildTimeoutMs(env = process.env) {
|
||||
return positiveEnvInt("OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS", env, DEFAULT_BUILD_TIMEOUT_MS);
|
||||
return readPositiveEnvInt("OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS", env, DEFAULT_BUILD_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,30 +9,16 @@ import {
|
||||
collectBundledPluginBuildEntries,
|
||||
NON_PACKAGED_BUNDLED_PLUGIN_DIRS,
|
||||
} from "./lib/bundled-plugin-build-entries.mjs";
|
||||
import { readPositiveEnvInt } from "./lib/numeric-options.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1000;
|
||||
|
||||
function positiveEnvInt(name, env, fallback) {
|
||||
const raw = env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the extension memory build timeout from environment.
|
||||
*/
|
||||
export function resolveExtensionMemoryBuildTimeoutMs(env = process.env) {
|
||||
return positiveEnvInt(
|
||||
return readPositiveEnvInt(
|
||||
"OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS",
|
||||
env,
|
||||
DEFAULT_BUILD_TIMEOUT_MS,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Npm Verify Exec script supports OpenClaw repository automation.
|
||||
import { execFileSync, type ExecFileSyncOptionsWithStringEncoding } from "node:child_process";
|
||||
import { readPositiveEnvInt } from "./numeric-options.mjs";
|
||||
|
||||
export type NpmVerifyCommandInvocation = {
|
||||
command: string;
|
||||
@@ -14,21 +15,6 @@ type NpmVerifyExecOptions = ExecFileSyncOptionsWithStringEncoding & {
|
||||
const DEFAULT_NPM_VERIFY_COMMAND_TIMEOUT_MS = 5 * 60 * 1000;
|
||||
const DEFAULT_NPM_VERIFY_COMMAND_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
||||
|
||||
function positiveEnvInt(name: string, fallback: number): number {
|
||||
const raw = process.env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/u.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function runNpmVerifyCommand(
|
||||
invocation: NpmVerifyCommandInvocation,
|
||||
cwd: string,
|
||||
@@ -36,11 +22,16 @@ export function runNpmVerifyCommand(
|
||||
): string {
|
||||
const timeoutMs =
|
||||
options.timeoutMs ??
|
||||
positiveEnvInt("OPENCLAW_NPM_VERIFY_COMMAND_TIMEOUT_MS", DEFAULT_NPM_VERIFY_COMMAND_TIMEOUT_MS);
|
||||
readPositiveEnvInt(
|
||||
"OPENCLAW_NPM_VERIFY_COMMAND_TIMEOUT_MS",
|
||||
process.env,
|
||||
DEFAULT_NPM_VERIFY_COMMAND_TIMEOUT_MS,
|
||||
);
|
||||
const maxBuffer =
|
||||
options.maxBufferBytes ??
|
||||
positiveEnvInt(
|
||||
readPositiveEnvInt(
|
||||
"OPENCLAW_NPM_VERIFY_COMMAND_MAX_BUFFER_BYTES",
|
||||
process.env,
|
||||
DEFAULT_NPM_VERIFY_COMMAND_MAX_BUFFER_BYTES,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export function parsePositiveInt(raw: string, label: string): number;
|
||||
export function readPositiveEnvInt(name: string, env: NodeJS.ProcessEnv, fallback: number): number;
|
||||
export function parseNonNegativeInt(raw: string, label: string): number;
|
||||
export function parsePositiveNumber(raw: string, label: string): number;
|
||||
|
||||
@@ -12,6 +12,22 @@ export function parsePositiveInt(raw, label) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Read a safe positive integer from an environment variable. */
|
||||
export function readPositiveEnvInt(name, env, fallback) {
|
||||
const raw = env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/u.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Parse a safe non-negative integer option. */
|
||||
export function parseNonNegativeInt(raw, label) {
|
||||
const text = String(raw).trim();
|
||||
|
||||
@@ -6,6 +6,7 @@ import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { resolveNpmDistTagMirrorAuth as resolveNpmDistTagMirrorAuthBase } from "./lib/npm-publish-plan.mjs";
|
||||
import { readPositiveEnvInt } from "./lib/numeric-options.mjs";
|
||||
import {
|
||||
LOCAL_BUILD_METADATA_DIST_PATHS,
|
||||
PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
|
||||
@@ -280,25 +281,10 @@ export function parseReleaseTagVersion(version: string): ParsedReleaseTag | null
|
||||
return null;
|
||||
}
|
||||
|
||||
function positiveEnvInt(name: string, env: NodeJS.ProcessEnv, fallback: number): number {
|
||||
const raw = env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/u.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function resolveNpmReleaseCheckCommandTimeoutMs(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): number {
|
||||
return positiveEnvInt(
|
||||
return readPositiveEnvInt(
|
||||
"OPENCLAW_NPM_RELEASE_CHECK_COMMAND_TIMEOUT_MS",
|
||||
env,
|
||||
DEFAULT_RELEASE_CHECK_COMMAND_TIMEOUT_MS,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
|
||||
import { basename, delimiter, join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { formatErrorMessage } from "../src/infra/errors.ts";
|
||||
import { readPositiveEnvInt } from "./lib/numeric-options.mjs";
|
||||
import { writePackageDistInventoryForPublish } from "./lib/package-dist-inventory.ts";
|
||||
import { preparePackageChangelog } from "./package-changelog.mjs";
|
||||
import { createPnpmRunnerSpawnSpec } from "./pnpm-runner.mjs";
|
||||
@@ -175,23 +176,8 @@ function ensurePreparedArtifacts(): void {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function positiveEnvInt(name: string, env: NodeJS.ProcessEnv, fallback: number): number {
|
||||
const raw = env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/u.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function resolvePrepackCommandTimeoutMs(env: NodeJS.ProcessEnv = process.env): number {
|
||||
return positiveEnvInt(
|
||||
return readPositiveEnvInt(
|
||||
"OPENCLAW_PREPACK_COMMAND_TIMEOUT_MS",
|
||||
env,
|
||||
DEFAULT_PREPACK_COMMAND_TIMEOUT_MS,
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
listBundledPluginPackArtifacts,
|
||||
} from "./lib/bundled-plugin-build-entries.mjs";
|
||||
import { collectPackUnpackedSizeErrors as collectNpmPackUnpackedSizeErrors } from "./lib/npm-pack-budget.mjs";
|
||||
import { readPositiveEnvInt } from "./lib/numeric-options.mjs";
|
||||
import {
|
||||
isLegacyPluginDependencyInstallStagePath,
|
||||
LOCAL_BUILD_METADATA_DIST_PATHS,
|
||||
@@ -201,21 +202,6 @@ const PACKED_PLUGIN_SDK_TYPESCRIPT_SMOKE_FIXTURE = resolve(
|
||||
"scripts/fixtures/packed-plugin-sdk-type-smoke.ts",
|
||||
);
|
||||
|
||||
function positiveEnvInt(name: string, fallback: number): number {
|
||||
const raw = process.env[name]?.trim();
|
||||
if (raw === undefined || raw === "") {
|
||||
return fallback;
|
||||
}
|
||||
if (!/^[1-9]\d*$/u.test(raw)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`invalid ${name}: ${raw}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function runReleaseCheckCommand(
|
||||
invocation: ReleaseCheckCommandInvocation,
|
||||
options: {
|
||||
@@ -235,16 +221,18 @@ export function runReleaseCheckCommand(
|
||||
killSignal: "SIGKILL",
|
||||
maxBuffer:
|
||||
options.maxBuffer ??
|
||||
positiveEnvInt(
|
||||
readPositiveEnvInt(
|
||||
"OPENCLAW_RELEASE_CHECK_COMMAND_MAX_BUFFER_BYTES",
|
||||
process.env,
|
||||
DEFAULT_RELEASE_CHECK_COMMAND_MAX_BUFFER_BYTES,
|
||||
),
|
||||
shell: invocation.shell ?? options.shell,
|
||||
stdio: options.stdio,
|
||||
timeout:
|
||||
options.timeoutMs ??
|
||||
positiveEnvInt(
|
||||
readPositiveEnvInt(
|
||||
"OPENCLAW_RELEASE_CHECK_COMMAND_TIMEOUT_MS",
|
||||
process.env,
|
||||
DEFAULT_RELEASE_CHECK_COMMAND_TIMEOUT_MS,
|
||||
),
|
||||
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
||||
|
||||
@@ -1360,6 +1360,8 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([
|
||||
],
|
||||
],
|
||||
["scripts/lib/npm-verify-exec.ts", ["test/scripts/npm-verify-exec.test.ts"]],
|
||||
["scripts/lib/numeric-options.mjs", ["test/scripts/numeric-options.test.ts"]],
|
||||
["scripts/lib/numeric-options.d.mts", ["test/scripts/numeric-options.test.ts"]],
|
||||
["scripts/lib/openclaw-test-state.mjs", ["test/scripts/openclaw-test-state.test.ts"]],
|
||||
[
|
||||
"scripts/lib/workspace-bootstrap-smoke.mjs",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { readPositiveEnvInt } from "../../scripts/lib/numeric-options.mjs";
|
||||
|
||||
describe("readPositiveEnvInt", () => {
|
||||
it("uses the fallback for missing or blank values", () => {
|
||||
expect(readPositiveEnvInt("LIMIT", {}, 42)).toBe(42);
|
||||
expect(readPositiveEnvInt("LIMIT", { LIMIT: " " }, 42)).toBe(42);
|
||||
});
|
||||
|
||||
it("reads strict positive safe integers", () => {
|
||||
expect(readPositiveEnvInt("LIMIT", { LIMIT: " 123 " }, 42)).toBe(123);
|
||||
});
|
||||
|
||||
it.each(["0", "-1", "1.5", "1e3", "0x10", "9007199254740992"])(
|
||||
"rejects invalid value %s",
|
||||
(raw) => {
|
||||
expect(() => readPositiveEnvInt("LIMIT", { LIMIT: raw }, 42)).toThrow(
|
||||
`invalid LIMIT: ${raw}`,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user