fix: render gh preflight as table

This commit is contained in:
Codex
2026-06-21 15:44:08 +00:00
parent 92cd1cadf4
commit 1be65819d7
2 changed files with 73 additions and 1 deletions
+5
View File
@@ -290,6 +290,11 @@ async function main(): Promise<void> {
if (top === "gh") {
const result = await runGhCommand(args.slice(1));
const ok = (result as { ok?: unknown }).ok !== false;
if (isRenderedCliResult(result)) {
emitText(result.renderedText, result.command || commandName);
if (!ok) process.exitCode = 1;
return;
}
emitJson(commandName, result, ok);
if (!ok) process.exitCode = 1;
return;
+68 -1
View File
@@ -5230,7 +5230,7 @@ async function prPreflight(repo: string, number: number, commandName: "preflight
const metadataSummary = prMetadataSummary(metadata);
const statusChecks = statusRollupSummary(repo, number, metadata.statusCheckRollup, includeRaw);
const closeout = prCloseoutSummary(summary, metadataSummary, statusChecks);
return {
const result: GitHubCommandResult = {
ok: true,
command: commandName,
canonicalCommand: `bun scripts/cli.ts gh pr preflight ${number} --repo ${repo}`,
@@ -5251,6 +5251,73 @@ async function prPreflight(repo: string, number: number, commandName: "preflight
policy,
...(includeRaw ? { raw: { authStatus: auth, pullRequest, closeoutMetadata: metadataSummary } } : {}),
};
if (includeRaw) return result;
return {
...result,
contentType: "text/plain",
renderedText: renderPrPreflightTable(result),
};
}
function renderPrPreflightTable(result: GitHubCommandResult): string {
const pullRequest = isRecord(result.pullRequest) ? result.pullRequest : {};
const mergeability = isRecord(result.mergeability) ? result.mergeability : {};
const statusChecks = isRecord(result.statusChecks) ? result.statusChecks : {};
const counts = isRecord(statusChecks.counts) ? statusChecks.counts : {};
const policy = isRecord(result.policy) ? result.policy : {};
const blockers = Array.isArray(mergeability.blockers) ? mergeability.blockers.map(String) : [];
const pending = Array.isArray(mergeability.pending) ? mergeability.pending.map(String) : [];
const conclusion = ghText(mergeability.conclusion);
const rows = [[
`#${ghText(result.number)}`,
ghText(pullRequest.stateDetail ?? pullRequest.state),
ghText(mergeability.mergeable),
ghText(mergeability.mergeStateStatus),
`${ghText(statusChecks.totalContexts)} total ${ghText(counts.success)} ok ${ghText(counts.failure)} fail ${ghText(counts.pending)} pending`,
conclusion,
]];
const lines = [
`gh pr preflight (${conclusion})`,
"",
ghTable(["PR", "STATE", "MERGEABLE", "MERGE_STATE", "CHECKS", "CONCLUSION"], rows),
"",
"Summary:",
` repo=${ghText(result.repo)} title=${ghShort(ghText(pullRequest.title), 96)}`,
` head=${ghText(isRecord(pullRequest.head) ? pullRequest.head.ref : null)} base=${ghText(isRecord(pullRequest.base) ? pullRequest.base.ref : null)}`,
` blockers=${blockers.length === 0 ? "-" : blockers.join(",")} pending=${pending.length === 0 ? "-" : pending.join(",")}`,
"",
"Next:",
];
const mergeCommand = ghText(policy.mergeCommand);
if (mergeability.readyForCommanderMerge === true && mergeCommand !== "-") {
lines.push(` ${mergeCommand}`);
}
lines.push(` bun scripts/cli.ts gh pr preflight ${ghText(result.number)} --repo ${ghText(result.repo)} --full`);
lines.push("", "Disclosure:");
lines.push(" default view is a bounded table; use --full or --raw for structured PR/check metadata.");
return lines.join("\n");
}
function ghTable(headers: string[], rows: string[][]): string {
const normalizedRows = rows.map((row) => headers.map((_, index) => row[index] ?? ""));
const widths = headers.map((header, index) => Math.max(header.length, ...normalizedRows.map((row) => row[index].length)));
return [
headers.map((header, index) => header.padEnd(widths[index])).join(" ").trimEnd(),
...normalizedRows.map((row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ").trimEnd()),
].join("\n");
}
function ghText(value: unknown): string {
if (value === null || value === undefined || value === "") return "-";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
return JSON.stringify(value);
}
function ghShort(value: string, maxLength: number): string {
if (value.length <= maxLength) return value;
if (maxLength <= 1) return value.slice(0, maxLength);
return `${value.slice(0, maxLength - 1)}~`;
}
function repoSummary(repo: GitHubRepository): Record<string, unknown> {