164 lines
5.5 KiB
TypeScript
164 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import type { TaskPR } from "@/lib/types/github";
|
|
import {
|
|
getMergeQueueSummaryDetail,
|
|
getMergeQueueSummaryStatus,
|
|
hasActiveMergeQueueEntry,
|
|
} from "./pr-merge-queue-status";
|
|
import {
|
|
ChangeRequestTaskStatusSummary,
|
|
type ChangeRequestTaskStatusSummaryData,
|
|
type ChangeRequestTaskSummaryRow,
|
|
type ChangeRequestTaskSummaryRowKind,
|
|
type ChangeRequestTaskSummaryStatus,
|
|
type ChangeRequestTaskSummaryTone,
|
|
} from "@/components/integrations/change-request-task-status-summary";
|
|
import {
|
|
getCurrentWorkflowAttention,
|
|
isWorkflowApprovalRequired,
|
|
workflowAttentionWorkflowNames,
|
|
} from "./pr-workflow-attention";
|
|
|
|
export type PRTaskSummaryRowKind = ChangeRequestTaskSummaryRowKind;
|
|
export type PRTaskSummaryTone = ChangeRequestTaskSummaryTone;
|
|
export type PRTaskSummaryStatus = ChangeRequestTaskSummaryStatus;
|
|
export type PRTaskSummaryRow = ChangeRequestTaskSummaryRow;
|
|
export type PRTaskStatusSummaryData = ChangeRequestTaskStatusSummaryData;
|
|
|
|
function rawRow(kind: PRTaskSummaryRowKind, rawValue: string): PRTaskSummaryRow {
|
|
return { kind, status: "raw", tone: "muted", rawValue };
|
|
}
|
|
|
|
function deriveStateRow(state: string): PRTaskSummaryRow | null {
|
|
if (!state || state === "open") return null;
|
|
if (state === "merged") return { kind: "state", status: "merged", tone: "merged" };
|
|
if (state === "closed") return { kind: "state", status: "closed", tone: "danger" };
|
|
return rawRow("state", state);
|
|
}
|
|
|
|
function deriveReviewRow(reviewState: string): PRTaskSummaryRow | null {
|
|
if (!reviewState) return null;
|
|
if (reviewState === "approved") {
|
|
return { kind: "review", status: "approved", tone: "success" };
|
|
}
|
|
if (reviewState === "changes_requested") {
|
|
return { kind: "review", status: "changes_requested", tone: "danger" };
|
|
}
|
|
if (reviewState === "pending") {
|
|
return { kind: "review", status: "pending_review", tone: "info" };
|
|
}
|
|
return rawRow("review", reviewState);
|
|
}
|
|
|
|
function workflowAttentionRow(pr: TaskPR): PRTaskSummaryRow | null {
|
|
const attention = getCurrentWorkflowAttention(pr);
|
|
if (!attention) return null;
|
|
if (attention.state === "unknown") {
|
|
return {
|
|
kind: "ci",
|
|
id: "workflow-attention",
|
|
status: "workflow_unavailable",
|
|
tone: "muted",
|
|
};
|
|
}
|
|
if (attention.state !== "approval_required" && attention.state !== "action_required") {
|
|
return null;
|
|
}
|
|
const names = workflowAttentionWorkflowNames(attention);
|
|
return {
|
|
kind: "ci",
|
|
id: "workflow-attention",
|
|
status: isWorkflowApprovalRequired(attention) ? "awaiting_approval" : "workflow_attention",
|
|
tone: "warning",
|
|
...(names
|
|
? {
|
|
detail: {
|
|
key: "github:workflowAttentionWorkflows",
|
|
values: { names },
|
|
},
|
|
}
|
|
: {}),
|
|
};
|
|
}
|
|
|
|
function deriveCIRows(pr: TaskPR): PRTaskSummaryRow[] {
|
|
const attentionRow = workflowAttentionRow(pr);
|
|
const attentionExplainsUnstable =
|
|
attentionRow?.status === "awaiting_approval" || attentionRow?.status === "workflow_attention";
|
|
const rows: PRTaskSummaryRow[] = [];
|
|
if (pr.checks_state === "success") rows.push({ kind: "ci", status: "passed", tone: "success" });
|
|
else if (pr.checks_state === "failure") {
|
|
rows.push({ kind: "ci", status: "failed", tone: "danger" });
|
|
} else if (pr.checks_state === "pending") {
|
|
rows.push({ kind: "ci", status: "in_progress", tone: "warning" });
|
|
} else if (
|
|
pr.checks_state === "unstable" ||
|
|
(pr.mergeable_state === "unstable" && !attentionExplainsUnstable)
|
|
) {
|
|
if (!attentionExplainsUnstable) {
|
|
rows.push({ kind: "ci", status: "checks_not_successful", tone: "warning" });
|
|
}
|
|
} else if (pr.checks_state) rows.push(rawRow("ci", pr.checks_state));
|
|
if (attentionRow) rows.push(attentionRow);
|
|
return rows;
|
|
}
|
|
|
|
function deriveMergeRow(pr: TaskPR, readyToMerge: boolean): PRTaskSummaryRow | null {
|
|
if (pr.state !== "open") return null;
|
|
if (hasActiveMergeQueueEntry(pr)) {
|
|
return {
|
|
kind: "merge",
|
|
status: getMergeQueueSummaryStatus(pr.merge_queue_state),
|
|
tone: "queued",
|
|
detail: getMergeQueueSummaryDetail(
|
|
pr.merge_queue_position,
|
|
pr.merge_queue_estimated_time_to_merge_seconds,
|
|
),
|
|
};
|
|
}
|
|
if (pr.mergeable_state === "draft") {
|
|
return { kind: "merge", status: "draft", tone: "muted" };
|
|
}
|
|
if (readyToMerge) return { kind: "merge", status: "ready", tone: "success" };
|
|
if (!pr.mergeable_state || pr.mergeable_state === "unknown") return null;
|
|
if (pr.mergeable_state === "dirty") {
|
|
return { kind: "merge", status: "conflicts", tone: "danger" };
|
|
}
|
|
if (pr.mergeable_state === "behind") {
|
|
return { kind: "merge", status: "behind", tone: "warning" };
|
|
}
|
|
if (pr.mergeable_state === "blocked") {
|
|
return { kind: "merge", status: "blocked", tone: "muted" };
|
|
}
|
|
if (pr.mergeable_state === "clean") {
|
|
return { kind: "merge", status: "mergeable", tone: "muted" };
|
|
}
|
|
if (pr.mergeable_state === "unstable") return null;
|
|
return rawRow("merge", pr.mergeable_state);
|
|
}
|
|
|
|
export function derivePRTaskStatusSummary(
|
|
pr: TaskPR,
|
|
readyToMerge: boolean,
|
|
): PRTaskStatusSummaryData {
|
|
const rows = [
|
|
deriveStateRow(pr.state),
|
|
deriveReviewRow(pr.review_state),
|
|
...deriveCIRows(pr),
|
|
deriveMergeRow(pr, readyToMerge),
|
|
].filter((row): row is PRTaskSummaryRow => row !== null);
|
|
|
|
const author = pr.author_login.trim();
|
|
return {
|
|
number: pr.pr_number,
|
|
title: pr.pr_title,
|
|
...(author ? { author } : {}),
|
|
rows,
|
|
};
|
|
}
|
|
|
|
export function PRTaskStatusSummary({ summaries }: { summaries: PRTaskStatusSummaryData[] }) {
|
|
return <ChangeRequestTaskStatusSummary summaries={summaries} />;
|
|
}
|