fix: report apply-patch partial failures

This commit is contained in:
Codex
2026-05-30 04:05:52 +00:00
parent b2435d406b
commit 531d435777
7 changed files with 172 additions and 37 deletions
+47 -3
View File
@@ -102,24 +102,33 @@ function applyPatchFixture(args: string[], patch: string, files: Record<string,
}
}
async function applyPatchV2FixtureAttempt(patch: string, files: Record<string, string>): Promise<{ stdout: string; files: Record<string, string>; commands: string[]; error: unknown | null }> {
async function applyPatchV2FixtureAttempt(patch: string, files: Record<string, string>, options: { stderrOutput?: boolean } = {}): Promise<{ stdout: string; stderr: string; exitCode: number | null; files: Record<string, string>; commands: string[]; error: unknown | null }> {
const state = new Map(Object.entries(files));
const pendingWrites = new Map<string, string>();
const commands: string[] = [];
const stdin = new PassThrough();
stdin.end(patch);
let stdout = "";
let stderr = "";
const stdoutSink = new Writable({
write(chunk, _encoding, callback) {
stdout += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
callback();
},
});
const stderrSink = new Writable({
write(chunk, _encoding, callback) {
stderr += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
callback();
},
});
let error: unknown | null = null;
let exitCode: number | null = null;
try {
await runApplyPatchV2({
exitCode = await runApplyPatchV2({
stdin,
stdout: stdoutSink,
...(options.stderrOutput === true ? { stderr: stderrSink } : {}),
executor: {
async run(command, input) {
const operation = command[4] ?? "";
@@ -199,7 +208,7 @@ async function applyPatchV2FixtureAttempt(patch: string, files: Record<string, s
} catch (caught) {
error = caught;
}
return { stdout, files: Object.fromEntries(state), commands, error };
return { stdout, stderr, exitCode, files: Object.fromEntries(state), commands, error };
}
async function applyPatchV2ActualShellFixtureAttempt(
@@ -734,6 +743,41 @@ export async function runSshArgvGuidanceContract(): Promise<JsonRecord> {
failedCompoundV2.error,
);
const failedCompoundVisibleV2 = await applyPatchV2FixtureAttempt([
"*** Begin Patch",
"*** Update File: first.txt",
"@@",
"-old first",
"+new first",
"*** Update File: second.txt",
"@@",
"-missing second",
"+new second",
"*** Update File: third.txt",
"@@",
"-old third",
"+new third",
"*** End Patch",
"",
].join("\n"), {
"first.txt": "old first\n",
"second.txt": "old second\n",
"third.txt": "old third\n",
}, { stderrOutput: true });
assertCondition(failedCompoundVisibleV2.exitCode === 1 && failedCompoundVisibleV2.error === null, "v2 CLI path should return non-zero instead of throwing when stderr is provided", failedCompoundVisibleV2);
assertCondition(failedCompoundVisibleV2.stdout === "", "v2 failed CLI path should keep Codex-style empty stdout", failedCompoundVisibleV2);
assertCondition(
failedCompoundVisibleV2.stderr.includes("failed to find expected lines")
&& failedCompoundVisibleV2.stderr.includes("Applied before failure:")
&& failedCompoundVisibleV2.stderr.includes("M first.txt")
&& failedCompoundVisibleV2.stderr.includes("Failed:")
&& failedCompoundVisibleV2.stderr.includes("hunk 2 update second.txt")
&& failedCompoundVisibleV2.stderr.includes("Pending after failure:")
&& failedCompoundVisibleV2.stderr.includes("hunk 3 update third.txt"),
"v2 failed CLI path should print Codex-style stderr plus per-file applied/failed/pending summary",
failedCompoundVisibleV2.stderr,
);
const addBeforeFailedUpdateV2 = await applyPatchV2FixtureAttempt([
"*** Begin Patch",
"*** Add File: hwpod",