docs: document release runner scripts

This commit is contained in:
Peter Steinberger
2026-06-04 23:46:55 -04:00
parent 980c91d293
commit 57f8d71c50
18 changed files with 93 additions and 0 deletions

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Dispatches full release validation against a temporary SHA-pinned branch.
import { execFileSync, spawnSync } from "node:child_process";
const WORKFLOW = "full-release-validation.yml";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Starts gateway watch in tmux while preserving useful dev environment state.
import { spawnSync } from "node:child_process";
import process from "node:process";
import { pathToFileURL } from "node:url";
@@ -138,6 +139,9 @@ const resolveGatewayWatchBenchmarkArgs = ({ args = [], env = process.env } = {})
};
};
/**
* Resolves the tmux session name for gateway watch arguments/environment.
*/
export const resolveGatewayWatchTmuxSessionName = ({ args = [], env = process.env } = {}) => {
const profile =
env.OPENCLAW_PROFILE ||
@@ -169,6 +173,9 @@ const resolveColorEnv = (env) => {
return { assignments: [`FORCE_COLOR=${forceColor}`], options: [] };
};
/**
* Builds the shell command executed inside the tmux gateway watch session.
*/
export const buildGatewayWatchTmuxCommand = ({
args = [],
cwd = process.cwd(),
@@ -259,6 +266,9 @@ const setTmuxSessionMetadata = ({ cwd, sessionName, spawnSyncImpl, stderr }) =>
}
};
/**
* Runs the gateway-watch tmux wrapper main flow.
*/
export const runGatewayWatchTmuxMain = (params = {}) => {
const resolvedArgs = resolveGatewayWatchBenchmarkArgs({
args: params.args ?? process.argv.slice(2),

View File

@@ -1,10 +1,14 @@
#!/usr/bin/env node
// Generates release dependency evidence artifacts and summaries.
import { execFileSync } from "node:child_process";
import { appendFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import process from "node:process";
/**
* Dependency evidence reports generated for release artifacts.
*/
export const DEPENDENCY_EVIDENCE_REPORTS = [
{
name: "npm advisory vulnerability gate",
@@ -70,6 +74,9 @@ function runCommand(command, args, { rootDir, execFileSyncImpl = execFileSync })
});
}
/**
* Resolves the release tag when the release ref is a SHA or tag.
*/
export function resolveReleaseTag({ releaseRef, packageVersion }) {
if (/^[0-9a-fA-F]{40}$/u.test(releaseRef)) {
return `v${packageVersion}`;
@@ -77,6 +84,9 @@ export function resolveReleaseTag({ releaseRef, packageVersion }) {
return releaseRef;
}
/**
* Resolves the previous reachable release tag for dependency diffs.
*/
export function resolvePreviousReleaseTag({
rootDir = process.cwd(),
execFileSyncImpl = execFileSync,
@@ -114,6 +124,9 @@ export function resolvePreviousReleaseTag({
);
}
/**
* Creates the dependency evidence manifest payload.
*/
export function createDependencyEvidenceManifest({
generatedAt = new Date().toISOString(),
releaseTag,
@@ -149,6 +162,9 @@ async function readJson(filePath) {
return JSON.parse(await readFile(filePath, "utf8"));
}
/**
* Reads generated reports and collects summary counts.
*/
export async function collectDependencyEvidenceSummaryCounts(evidenceDir) {
const [vulnerability, transitiveRisk, ownershipSurface, dependencyChanges] = await Promise.all([
readJson(reportPath(evidenceDir, "dependency-vulnerability-gate.json")),
@@ -171,6 +187,9 @@ export async function collectDependencyEvidenceSummaryCounts(evidenceDir) {
};
}
/**
* Renders the dependency evidence Markdown summary.
*/
export function renderDependencyEvidenceSummary({ releaseTag, releaseSha, baseRef, counts }) {
return `${[
"# Dependency release evidence",
@@ -199,6 +218,9 @@ export function renderDependencyEvidenceSummary({ releaseTag, releaseSha, baseRe
].join("\n")}\n`;
}
/**
* Renders the GitHub Actions step summary for dependency evidence.
*/
export function renderDependencyEvidenceStepSummary({ evidenceArtifactName, baseRef, counts }) {
return `${[
"### Dependency release evidence",
@@ -267,6 +289,9 @@ function runEvidenceReports({ rootDir, outputDir, baseRef, execFileSyncImpl }) {
);
}
/**
* Generates dependency evidence reports, manifest, and summaries for a release.
*/
export async function generateDependencyReleaseEvidence({
rootDir = process.cwd(),
outputDir,
@@ -402,6 +427,9 @@ function parseArgs(argv) {
return options;
}
/**
* Runs the dependency release evidence generator CLI.
*/
export async function main(argv = process.argv.slice(2)) {
await generateDependencyReleaseEvidence(parseArgs(argv));
return 0;

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Generates Swift constants for the host environment security policy.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Generates Kysely database types from the SQLite schema.
import fs from "node:fs";
import process from "node:process";
import { DatabaseSync } from "node:sqlite";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Generates the plugin inventory documentation page.
import fs from "node:fs";
import path from "node:path";
import process from "node:process";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Applies GHSA patch payloads to advisory branches.
import { execFileSync, spawnSync } from "node:child_process";
import crypto from "node:crypto";
import fs from "node:fs";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Summarizes Kova CI run metadata for diagnostics.
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";

View File

@@ -1,3 +1,4 @@
// Lists production store packages from lockfile data.
import fs from "node:fs";
import path from "node:path";
import { parse } from "yaml";

View File

@@ -1,3 +1,4 @@
// Resolves npm commands from the active Node toolchain, especially on Windows.
import fs from "node:fs";
import path from "node:path";
import { buildCmdExeCommandLine, resolvePathEnvKey } from "./windows-cmd-helpers.mjs";
@@ -41,6 +42,9 @@ function resolveToolchainNpmRunner(params) {
return null;
}
/**
* Resolves a toolchain-local npm invocation for the current platform.
*/
export function resolveNpmRunner(params = {}) {
const execPath = params.execPath ?? process.execPath;
const npmArgs = params.npmArgs ?? [];

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Summarizes OpenClaw performance source fixtures for reports.
import fs from "node:fs";
import path from "node:path";
import process from "node:process";

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Temporarily narrows CHANGELOG.md to packaged release notes for npm tarballs.
import { existsSync } from "node:fs";
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
@@ -18,6 +19,9 @@ const RELEASE_VERSION_PATTERN =
const PRERELEASE_VERSION_PATTERN =
/^([0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*)-(?:alpha|beta)\.[1-9][0-9]*$/u;
/**
* Resolves acceptable changelog headings for a package version.
*/
export function resolvePackageChangelogVersions(packageVersion) {
const match = RELEASE_VERSION_PATTERN.exec(packageVersion);
if (!match) {
@@ -54,6 +58,9 @@ function extractPreamble(lines, firstHeadingIndex) {
return lines.slice(0, firstHeadingIndex).join("\n").trimEnd();
}
/**
* Extracts the current release changelog section for package publishing.
*/
export function extractCurrentPackageChangelog(content, packageVersion) {
const targetVersions = resolvePackageChangelogVersions(packageVersion);
const lines = splitLines(content);
@@ -99,6 +106,9 @@ async function readPackageVersion(cwd) {
return packageJson.version;
}
/**
* Restores the source changelog from a package-changelog backup.
*/
export async function restorePackageChangelog(cwd = process.cwd()) {
const backupPath = path.join(cwd, BACKUP_PATH);
if (!existsSync(backupPath)) {
@@ -132,6 +142,9 @@ export async function restorePackageChangelog(cwd = process.cwd()) {
return true;
}
/**
* Writes packaged changelog content while preserving a restorable backup.
*/
export async function preparePackageChangelog(cwd = process.cwd()) {
await restorePackageChangelog(cwd);
const changelogPath = path.join(cwd, CHANGELOG_PATH);

View File

@@ -1,3 +1,4 @@
// Plans release workflow matrix entries from profile and suite inputs.
const DOCKER_E2E_CHUNKS = [
{
chunk_id: "core",
@@ -162,6 +163,9 @@ function planProfileMatrix(entries, profile, enabled, disabledReason, labelForEn
};
}
/**
* Creates the Docker E2E/live model matrix plan for a release profile.
*/
export function createReleaseWorkflowMatrixPlan(options = {}) {
const releaseProfile = options.releaseProfile ?? "stable";
const dockerE2eEnabled =

View File

@@ -1,3 +1,4 @@
// Plans grouped targeted Docker lane matrix entries.
import { fileURLToPath } from "node:url";
import { parsePositiveInt } from "./lib/numeric-options.mjs";
@@ -23,6 +24,9 @@ function sanitizeLabel(value) {
);
}
/**
* Groups selected Docker lanes and expands sharded upgrade-survivor baselines.
*/
export function planTargetedDockerLaneGroups({
groupSize = 1,
lanes,

View File

@@ -1,3 +1,4 @@
// Builds a prerelease live-ish probe matrix from available credential env vars.
const LIVEISH_INPUTS = Object.freeze([
{
probe: "provider-openai",

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Reports plugin SDK export surface metadata.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

View File

@@ -1,3 +1,4 @@
// Resolves and spawns pnpm commands portably across POSIX and Windows shells.
import { spawn } from "node:child_process";
import { accessSync, closeSync, constants, openSync, readSync, statSync } from "node:fs";
import path from "node:path";
@@ -68,6 +69,9 @@ function isNodeRunnablePnpmExecPath(value) {
return hasScriptShebang(value);
}
/**
* Resolves the command/args needed to invoke pnpm on the current platform.
*/
export function resolvePnpmRunner(params = {}) {
const pnpmArgs = params.pnpmArgs ?? [];
const nodeArgs = params.nodeArgs ?? [];
@@ -126,6 +130,9 @@ export function resolvePnpmRunner(params = {}) {
};
}
/**
* Creates a spawn-ready pnpm invocation with standard options.
*/
export function createPnpmRunnerSpawnSpec(params = {}) {
const runner = resolvePnpmRunner(params);
return {
@@ -142,6 +149,9 @@ export function createPnpmRunnerSpawnSpec(params = {}) {
};
}
/**
* Spawns a pnpm command using the portable runner resolution.
*/
export function spawnPnpmRunner(params = {}) {
const spawnSpec = createPnpmRunnerSpawnSpec(params);
return spawn(spawnSpec.command, spawnSpec.args, spawnSpec.options);

View File

@@ -1,3 +1,4 @@
// Warns during install lifecycle when a package manager other than pnpm is used.
import { pathToFileURL } from "node:url";
const allowedLifecyclePackageManagers = new Set(["pnpm", "npm", "yarn", "bun"]);
@@ -14,6 +15,9 @@ function normalizeLifecyclePackageManagerName(value) {
return allowedLifecyclePackageManagers.has(normalized) ? normalized : null;
}
/**
* Detects the package manager running the current lifecycle script.
*/
export function detectLifecyclePackageManager(env = process.env) {
const userAgent = normalizeEnvValue(env.npm_config_user_agent);
const userAgentMatch = /^([A-Za-z0-9._-]+)\//u.exec(userAgent);
@@ -38,6 +42,9 @@ export function detectLifecyclePackageManager(env = process.env) {
return null;
}
/**
* Builds the warning shown for non-pnpm lifecycle installs.
*/
export function createPackageManagerWarningMessage(packageManager) {
if (!packageManager || packageManager === "pnpm") {
return null;
@@ -50,6 +57,9 @@ export function createPackageManagerWarningMessage(packageManager) {
].join("\n");
}
/**
* Emits the non-pnpm lifecycle warning when needed.
*/
export function warnIfNonPnpmLifecycle(env = process.env, warn = console.warn) {
const message = createPackageManagerWarningMessage(detectLifecyclePackageManager(env));
if (!message) {