feat(git): improve PR panel (#207)
This commit is contained in:
committed by
GitHub
parent
614277eaa1
commit
da20c647e2
@@ -4094,26 +4094,70 @@ async function main(options = {}) {
|
||||
return res.json({ connected: true, repo, branch, pr: null, checks: null, canMerge: false });
|
||||
}
|
||||
|
||||
// Checks summary (combined status)
|
||||
// Checks summary: prefer check-runs (Actions), fallback to classic statuses.
|
||||
let checks = null;
|
||||
try {
|
||||
const combined = await octokit.rest.repos.getCombinedStatusForRef({
|
||||
owner: repo.owner,
|
||||
repo: repo.repo,
|
||||
ref: prData.head?.sha,
|
||||
});
|
||||
const statuses = Array.isArray(combined?.data?.statuses) ? combined.data.statuses : [];
|
||||
const counts = { success: 0, failure: 0, pending: 0 };
|
||||
statuses.forEach((s) => {
|
||||
if (s.state === 'success') counts.success += 1;
|
||||
else if (s.state === 'failure' || s.state === 'error') counts.failure += 1;
|
||||
else if (s.state === 'pending') counts.pending += 1;
|
||||
});
|
||||
const total = counts.success + counts.failure + counts.pending;
|
||||
const state = counts.failure > 0 ? 'failure' : (counts.pending > 0 ? 'pending' : (total > 0 ? 'success' : 'unknown'));
|
||||
checks = { state, total, ...counts };
|
||||
} catch {
|
||||
checks = null;
|
||||
const sha = prData.head?.sha;
|
||||
if (sha) {
|
||||
try {
|
||||
const runs = await octokit.rest.checks.listForRef({
|
||||
owner: repo.owner,
|
||||
repo: repo.repo,
|
||||
ref: sha,
|
||||
per_page: 100,
|
||||
});
|
||||
const checkRuns = Array.isArray(runs?.data?.check_runs) ? runs.data.check_runs : [];
|
||||
if (checkRuns.length > 0) {
|
||||
const counts = { success: 0, failure: 0, pending: 0 };
|
||||
for (const run of checkRuns) {
|
||||
const status = run?.status;
|
||||
const conclusion = run?.conclusion;
|
||||
if (status === 'queued' || status === 'in_progress') {
|
||||
counts.pending += 1;
|
||||
continue;
|
||||
}
|
||||
if (!conclusion) {
|
||||
counts.pending += 1;
|
||||
continue;
|
||||
}
|
||||
if (conclusion === 'success' || conclusion === 'neutral' || conclusion === 'skipped') {
|
||||
counts.success += 1;
|
||||
} else {
|
||||
counts.failure += 1;
|
||||
}
|
||||
}
|
||||
const total = counts.success + counts.failure + counts.pending;
|
||||
const state = counts.failure > 0
|
||||
? 'failure'
|
||||
: (counts.pending > 0 ? 'pending' : (total > 0 ? 'success' : 'unknown'));
|
||||
checks = { state, total, ...counts };
|
||||
}
|
||||
} catch {
|
||||
// ignore and fall back
|
||||
}
|
||||
|
||||
if (!checks) {
|
||||
try {
|
||||
const combined = await octokit.rest.repos.getCombinedStatusForRef({
|
||||
owner: repo.owner,
|
||||
repo: repo.repo,
|
||||
ref: sha,
|
||||
});
|
||||
const statuses = Array.isArray(combined?.data?.statuses) ? combined.data.statuses : [];
|
||||
const counts = { success: 0, failure: 0, pending: 0 };
|
||||
statuses.forEach((s) => {
|
||||
if (s.state === 'success') counts.success += 1;
|
||||
else if (s.state === 'failure' || s.state === 'error') counts.failure += 1;
|
||||
else if (s.state === 'pending') counts.pending += 1;
|
||||
});
|
||||
const total = counts.success + counts.failure + counts.pending;
|
||||
const state = counts.failure > 0
|
||||
? 'failure'
|
||||
: (counts.pending > 0 ? 'pending' : (total > 0 ? 'success' : 'unknown'));
|
||||
checks = { state, total, ...counts };
|
||||
} catch {
|
||||
checks = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Permission check (best-effort)
|
||||
@@ -4814,7 +4858,7 @@ async function main(options = {}) {
|
||||
}
|
||||
}
|
||||
if (diffs.length === 0) {
|
||||
return res.status(400).json({ error: 'No diffs available for selected files' });
|
||||
return res.status(400).json({ error: 'No diffs available for base...head' });
|
||||
}
|
||||
|
||||
const diffSummaries = diffs.map(({ path, diff }) => `FILE: ${path}\n${diff}`).join('\n\n');
|
||||
|
||||
@@ -440,11 +440,24 @@ export async function getRangeDiff(directory, { base, head, path, contextLines =
|
||||
throw new Error('base and head are required');
|
||||
}
|
||||
|
||||
// Prefer remote-tracking base ref so merged commits don't reappear
|
||||
// when local base branch is stale (common when user stays on feature branch).
|
||||
let resolvedBase = baseRef;
|
||||
const originCandidate = `refs/remotes/origin/${baseRef}`;
|
||||
try {
|
||||
const verified = await git.raw(['rev-parse', '--verify', originCandidate]);
|
||||
if (verified && verified.trim()) {
|
||||
resolvedBase = `origin/${baseRef}`;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const args = ['diff', '--no-color'];
|
||||
if (typeof contextLines === 'number' && !Number.isNaN(contextLines)) {
|
||||
args.push(`-U${Math.max(0, contextLines)}`);
|
||||
}
|
||||
args.push(`${baseRef}...${headRef}`);
|
||||
args.push(`${resolvedBase}...${headRef}`);
|
||||
if (path) {
|
||||
args.push('--', path);
|
||||
}
|
||||
@@ -459,7 +472,19 @@ export async function getRangeFiles(directory, { base, head } = {}) {
|
||||
if (!baseRef || !headRef) {
|
||||
throw new Error('base and head are required');
|
||||
}
|
||||
const raw = await git.raw(['diff', '--name-only', `${baseRef}...${headRef}`]);
|
||||
|
||||
let resolvedBase = baseRef;
|
||||
const originCandidate = `refs/remotes/origin/${baseRef}`;
|
||||
try {
|
||||
const verified = await git.raw(['rev-parse', '--verify', originCandidate]);
|
||||
if (verified && verified.trim()) {
|
||||
resolvedBase = `origin/${baseRef}`;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const raw = await git.raw(['diff', '--name-only', `${resolvedBase}...${headRef}`]);
|
||||
return String(raw || '')
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
|
||||
Reference in New Issue
Block a user