openclaw/scripts/lib/merge-head-diff-base.mjs
Peter Steinberger 4ee565c6d2
perf(ci): remove repeated setup and balance complete test workloads (#134038)
* perf(ci): reduce Windows test setup and worker time

* perf(anthropic): defer auth loading until hook execution

* perf(test): narrow selected config startup work

* fix(ci): bound compiler memory on constrained lint runners

* test(ci): prepare media fixture input capabilities

* perf(test): scope selected unit configuration discovery

* fix(ci): release cancelled runs and route hybrid control jobs

* fix(ci): resolve merge bases before Testbox preparation

* fix(ci): align gateway recovery validation with runtime contracts

* perf(ci): avoid rename blob fetches during docs classification

* test(ci): consolidate Testbox base preparation coverage

* perf(ci): account for tooling work and shared build prerequisites

* fix(ci): declare serial plugin config worker ownership

* perf(ci): overlap independent performance Git lifecycle fixtures

* perf(ci): partition the complete plugin catch-all with native sharding

* perf(ci): reuse compiled session workers

* perf(test): compare complete SQLite snapshots natively

* test(ci): reuse race-safe process cleanup in report fixtures

* fix(ci): preserve the trusted PR helper closure

* test(ci): derive PR fixtures from the trusted helper closure

* perf(ci): reuse matching checkout for harness actions

* fix(ci): replace retained harness files during index export

* perf(ci): restore exact caches on hybrid runners

* fix(ci): include pnpm metadata in dependency archives

* test(ci): own direct compiler checkpoints in dist fixtures

* perf(ci): balance Windows projects by selected test costs

* perf(ci): seed UI transforms and scope tooling prerequisites

Keep package timeout observations joined across PID discovery, and test planner measurements against stable fixtures while preserving actual runtime-build singleton costs.

* docs(ci): drop the note for the already-landed Telegram type fix

* perf(ci): reuse preflight checkout and route hybrid macOS

* test(ci): wait for command readiness before timeout proof
2026-08-31 13:32:32 -07:00

111 lines
2.9 KiB
JavaScript

// Resolves the diff base for merge commits when first-parent comparison is requested.
import { execFileSync } from "node:child_process";
import { pathToFileURL } from "node:url";
import { requireOptionArgument } from "./arg-utils.runtime.mjs";
const DEFAULT_GIT_OUTPUT_MAX_BUFFER = 16 * 1024 * 1024;
/**
* Resolve the git base ref to use when diffing a merge head.
* @param {{base: string, head?: string, cwd?: string, maxBuffer?: number, preferFirstParent?: boolean}} params
* @returns {string}
*/
export function resolveMergeHeadDiffBase({
base,
head = "HEAD",
cwd = process.cwd(),
maxBuffer = DEFAULT_GIT_OUTPUT_MAX_BUFFER,
preferFirstParent = false,
}) {
if (!base) {
return "";
}
if (!preferFirstParent) {
return base;
}
const parents = listCommitParents({ ref: head, cwd, maxBuffer });
if (parents.length < 2) {
return base;
}
// The merge parent is authoritative. Resolving a stale base in a partial
// clone can fetch unrelated history even when its result is discarded.
return resolveCommit({ ref: parents[0], cwd, maxBuffer }) || base;
}
/**
* @param {{ref: string, cwd: string, maxBuffer: number}} params
* @returns {string[]}
*/
function listCommitParents({ ref, cwd, maxBuffer }) {
try {
const output = execFileSync("git", ["rev-list", "--parents", "-n", "1", ref], {
cwd,
stdio: ["ignore", "pipe", "ignore"],
encoding: "utf8",
maxBuffer,
}).trim();
return output.split(/\s+/u).slice(1);
} catch {
return [];
}
}
/**
* @param {{ref: string, cwd: string, maxBuffer: number}} params
* @returns {string}
*/
function resolveCommit({ ref, cwd, maxBuffer }) {
try {
return execFileSync("git", ["rev-parse", "--verify", `${ref}^{commit}`], {
cwd,
stdio: ["ignore", "pipe", "ignore"],
encoding: "utf8",
maxBuffer,
}).trim();
} catch {
return "";
}
}
/**
* @internal Directly tested script implementation detail.
* @param {readonly string[]} argv
* @returns {{base: string, head: string, preferFirstParent: boolean}}
*/
export function parseArgs(argv) {
const args = {
base: "",
head: "HEAD",
preferFirstParent: false,
};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--base") {
args.base = requireOptionArgument(argv, index, "--base");
index += 1;
continue;
}
if (arg === "--head") {
args.head = requireOptionArgument(argv, index, "--head");
index += 1;
continue;
}
if (arg === "--prefer-first-parent") {
args.preferFirstParent = true;
}
}
return args;
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const args = parseArgs(process.argv.slice(2));
process.stdout.write(
`${resolveMergeHeadDiffBase({
base: args.base,
head: args.head,
preferFirstParent: args.preferFirstParent,
})}\n`,
);
}