patchrelay 0.32.1 → 0.32.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build-info.json
CHANGED
|
@@ -59,6 +59,17 @@ function buildPrStatusSummary(issue, issueContext) {
|
|
|
59
59
|
else if (checkState) {
|
|
60
60
|
summary.push(checkState);
|
|
61
61
|
}
|
|
62
|
+
if (issue.prChecksSummary?.total) {
|
|
63
|
+
if (issue.prChecksSummary.failed > 0) {
|
|
64
|
+
summary.push(`${issue.prChecksSummary.failed}/${issue.prChecksSummary.total} checks failing`);
|
|
65
|
+
}
|
|
66
|
+
else if (issue.prChecksSummary.pending > 0) {
|
|
67
|
+
summary.push(`${issue.prChecksSummary.completed}/${issue.prChecksSummary.total} checks settled`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
summary.push(`${issue.prChecksSummary.passed}/${issue.prChecksSummary.total} checks passed`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
62
73
|
if (reviewState) {
|
|
63
74
|
summary.push(`review ${reviewState}`);
|
|
64
75
|
}
|
|
@@ -86,22 +97,31 @@ function resolvePrimaryBlocker(issue, issueContext) {
|
|
|
86
97
|
color: "yellow",
|
|
87
98
|
};
|
|
88
99
|
}
|
|
89
|
-
if (issue.prCheckStatus === "failed") {
|
|
90
|
-
const
|
|
100
|
+
if (issue.prCheckStatus === "failed" || issue.prCheckStatus === "failure") {
|
|
101
|
+
const failedChecks = issue.prChecksSummary?.failedNames ?? [];
|
|
102
|
+
const failedCheck = issueContext?.latestFailureCheckName
|
|
103
|
+
?? issue.latestFailureCheckName
|
|
104
|
+
?? (failedChecks.length > 0 ? failedChecks.slice(0, 2).join(", ") : undefined);
|
|
91
105
|
return {
|
|
92
106
|
text: failedCheck ? `Blocked by failed check: ${failedCheck}` : "Blocked by failed PR checks",
|
|
93
107
|
color: "red",
|
|
94
108
|
};
|
|
95
109
|
}
|
|
110
|
+
if (issue.prCheckStatus === "pending" || issue.prCheckStatus === "in_progress" || issue.prCheckStatus === "queued") {
|
|
111
|
+
return { text: "Waiting for PR checks to finish", color: "yellow" };
|
|
112
|
+
}
|
|
96
113
|
if (issue.prReviewState === "changes_requested") {
|
|
97
114
|
return { text: "Blocked by requested review changes", color: "yellow" };
|
|
98
115
|
}
|
|
99
|
-
if (issue.
|
|
100
|
-
return { text: "Blocked
|
|
116
|
+
if (issue.factoryState === "repairing_queue") {
|
|
117
|
+
return { text: "Blocked by merge queue refresh failure", color: "yellow" };
|
|
101
118
|
}
|
|
102
119
|
if (issue.factoryState === "awaiting_queue") {
|
|
103
120
|
return { text: "Waiting in merge queue", color: "yellow" };
|
|
104
121
|
}
|
|
122
|
+
if (issue.prNumber !== undefined && !issue.prReviewState && issue.factoryState !== "done") {
|
|
123
|
+
return { text: "Blocked pending review approval", color: "yellow" };
|
|
124
|
+
}
|
|
105
125
|
return null;
|
|
106
126
|
}
|
|
107
127
|
function ElapsedTime({ startedAt }) {
|
|
@@ -4,15 +4,15 @@ import { Box, Text, useStdout } from "ink";
|
|
|
4
4
|
import { IssueRow } from "./IssueRow.js";
|
|
5
5
|
import { StatusBar } from "./StatusBar.js";
|
|
6
6
|
import { HelpBar } from "./HelpBar.js";
|
|
7
|
-
|
|
8
|
-
const FIXED_COLS = 40;
|
|
7
|
+
const FIXED_COLS = 8;
|
|
9
8
|
const CHROME_ROWS = 4;
|
|
9
|
+
const ISSUE_ROW_HEIGHT = 4;
|
|
10
10
|
export function IssueListView({ issues, allIssues, selectedIndex, connected, lastServerMessageAt, filter, totalCount, frozen, }) {
|
|
11
11
|
const { stdout } = useStdout();
|
|
12
12
|
const cols = stdout?.columns ?? 80;
|
|
13
13
|
const rows = stdout?.rows ?? 24;
|
|
14
14
|
const titleWidth = Math.max(0, cols - FIXED_COLS);
|
|
15
|
-
const maxVisible = Math.max(1, rows - CHROME_ROWS);
|
|
15
|
+
const maxVisible = Math.max(1, Math.floor((rows - CHROME_ROWS) / ISSUE_ROW_HEIGHT));
|
|
16
16
|
// Periodic refresh for elapsed times
|
|
17
17
|
const [, tick] = useReducer((c) => c + 1, 0);
|
|
18
18
|
useEffect(() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { summarizeIssueStatusNote } from "./issue-status-note.js";
|
|
4
|
+
import { progressBar, relativeTime, truncate } from "./format-utils.js";
|
|
4
5
|
const STATE_COLORS = {
|
|
5
6
|
blocked: "yellow",
|
|
6
7
|
ready: "blueBright",
|
|
@@ -20,16 +21,16 @@ const STATE_SHORT = {
|
|
|
20
21
|
blocked: "blocked",
|
|
21
22
|
ready: "ready",
|
|
22
23
|
delegated: "delegated",
|
|
23
|
-
implementing: "
|
|
24
|
+
implementing: "implementing",
|
|
24
25
|
pr_open: "pr open",
|
|
25
|
-
changes_requested: "review
|
|
26
|
-
repairing_ci: "
|
|
27
|
-
awaiting_queue: "
|
|
28
|
-
repairing_queue: "merge
|
|
26
|
+
changes_requested: "review changes",
|
|
27
|
+
repairing_ci: "repairing checks",
|
|
28
|
+
awaiting_queue: "queued for merge",
|
|
29
|
+
repairing_queue: "repairing merge queue",
|
|
29
30
|
done: "done",
|
|
30
31
|
failed: "failed",
|
|
31
32
|
escalated: "escalated",
|
|
32
|
-
awaiting_input: "
|
|
33
|
+
awaiting_input: "awaiting input",
|
|
33
34
|
};
|
|
34
35
|
const STATUS_SHORT = {
|
|
35
36
|
running: "\u25b8",
|
|
@@ -40,115 +41,220 @@ const STATUS_SHORT = {
|
|
|
40
41
|
function stateColor(state) {
|
|
41
42
|
return STATE_COLORS[state] ?? "white";
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
const TERMINAL_STATES = new Set(["done", "failed", "escalated", "awaiting_input"]);
|
|
45
|
+
function formatStatus(issue) {
|
|
46
|
+
const effectiveState = issue.blockedByCount > 0 && !issue.activeRunType
|
|
47
|
+
? "blocked"
|
|
48
|
+
: issue.readyForExecution && !issue.activeRunType
|
|
49
|
+
? "ready"
|
|
50
|
+
: issue.factoryState;
|
|
51
|
+
const state = STATE_SHORT[effectiveState] ?? effectiveState;
|
|
52
|
+
// Terminal states: just the label, no run symbol
|
|
53
|
+
if (TERMINAL_STATES.has(issue.factoryState))
|
|
54
|
+
return state;
|
|
55
|
+
// Active/in-progress: show run status symbol
|
|
56
|
+
const status = issue.activeRunType ? "running" : issue.latestRunStatus;
|
|
57
|
+
const statusSym = status ? (STATUS_SHORT[status] ?? "") : "";
|
|
58
|
+
if (statusSym)
|
|
59
|
+
return `${state} ${statusSym}`;
|
|
60
|
+
return state;
|
|
57
61
|
}
|
|
58
|
-
function
|
|
62
|
+
function buildStatusChips(issue) {
|
|
63
|
+
const effectiveState = issue.blockedByCount > 0 && !issue.activeRunType
|
|
64
|
+
? "blocked"
|
|
65
|
+
: issue.readyForExecution && !issue.activeRunType
|
|
66
|
+
? "ready"
|
|
67
|
+
: issue.factoryState;
|
|
68
|
+
const chips = [{
|
|
69
|
+
text: `${stateIcon(effectiveState)} ${STATE_SHORT[effectiveState] ?? effectiveState}`,
|
|
70
|
+
color: stateColor(effectiveState),
|
|
71
|
+
}];
|
|
72
|
+
if (issue.prNumber !== undefined) {
|
|
73
|
+
chips.push({ text: `PR #${issue.prNumber}`, color: "cyan" });
|
|
74
|
+
}
|
|
75
|
+
const reviewChip = buildReviewChip(issue.prReviewState);
|
|
76
|
+
if (reviewChip)
|
|
77
|
+
chips.push(reviewChip);
|
|
78
|
+
const checkChip = buildCheckChip(issue.prCheckStatus);
|
|
79
|
+
if (checkChip)
|
|
80
|
+
chips.push(checkChip);
|
|
81
|
+
const checksProgressChip = buildChecksProgressChip(issue);
|
|
82
|
+
if (checksProgressChip)
|
|
83
|
+
chips.push(checksProgressChip);
|
|
84
|
+
const mergeChip = buildMergeChip(issue);
|
|
85
|
+
if (mergeChip)
|
|
86
|
+
chips.push(mergeChip);
|
|
87
|
+
if (issue.blockedByCount > 0) {
|
|
88
|
+
chips.push({
|
|
89
|
+
text: `blocked by ${issue.blockedByKeys.join(", ")}`,
|
|
90
|
+
color: "yellow",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return chips;
|
|
94
|
+
}
|
|
95
|
+
function stateIcon(state) {
|
|
96
|
+
switch (state) {
|
|
97
|
+
case "implementing":
|
|
98
|
+
case "repairing_ci":
|
|
99
|
+
case "repairing_queue":
|
|
100
|
+
return "\u25b8";
|
|
101
|
+
case "awaiting_queue":
|
|
102
|
+
return "\u25a4";
|
|
103
|
+
case "done":
|
|
104
|
+
return "\u2713";
|
|
105
|
+
case "failed":
|
|
106
|
+
case "escalated":
|
|
107
|
+
return "\u2717";
|
|
108
|
+
case "blocked":
|
|
109
|
+
return "!";
|
|
110
|
+
case "ready":
|
|
111
|
+
return "+";
|
|
112
|
+
default:
|
|
113
|
+
return "\u2022";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function buildReviewChip(reviewState) {
|
|
59
117
|
switch (reviewState) {
|
|
60
118
|
case "approved":
|
|
61
|
-
return "
|
|
119
|
+
return { text: "\u2713 review approved", color: "green" };
|
|
62
120
|
case "changes_requested":
|
|
63
|
-
return "
|
|
121
|
+
return { text: "\u2717 changes requested", color: "yellow" };
|
|
64
122
|
case "commented":
|
|
65
|
-
return "
|
|
123
|
+
return { text: "\u2022 review commented", color: "yellow" };
|
|
66
124
|
case "dismissed":
|
|
67
|
-
return "
|
|
125
|
+
return { text: "\u2013 review dismissed", color: "yellow" };
|
|
68
126
|
default:
|
|
69
127
|
return null;
|
|
70
128
|
}
|
|
71
129
|
}
|
|
72
|
-
function
|
|
130
|
+
function buildCheckChip(checkState) {
|
|
73
131
|
switch (checkState) {
|
|
74
132
|
case "passed":
|
|
75
133
|
case "success":
|
|
76
|
-
return "
|
|
134
|
+
return { text: "\u2713 checks passed", color: "green" };
|
|
77
135
|
case "failed":
|
|
78
136
|
case "failure":
|
|
79
|
-
return "
|
|
137
|
+
return { text: "\u2717 checks failed", color: "red" };
|
|
80
138
|
case "pending":
|
|
81
139
|
case "in_progress":
|
|
82
140
|
case "queued":
|
|
83
|
-
return "
|
|
141
|
+
return { text: "\u25cf checks running", color: "yellow" };
|
|
84
142
|
default:
|
|
85
143
|
return null;
|
|
86
144
|
}
|
|
87
145
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
146
|
+
function buildChecksProgressChip(issue) {
|
|
147
|
+
const summary = issue.prChecksSummary;
|
|
148
|
+
if (!summary || summary.total <= 0)
|
|
149
|
+
return null;
|
|
150
|
+
const text = summary.failed > 0
|
|
151
|
+
? `checks ${summary.failed}/${summary.total} failed`
|
|
152
|
+
: summary.pending > 0
|
|
153
|
+
? `checks ${summary.completed}/${summary.total} settled`
|
|
154
|
+
: `checks ${summary.passed}/${summary.total} passed`;
|
|
155
|
+
const color = summary.failed > 0 ? "red" : summary.pending > 0 ? "yellow" : "green";
|
|
156
|
+
return { text, color };
|
|
157
|
+
}
|
|
158
|
+
function buildMergeChip(issue) {
|
|
159
|
+
if (issue.prNumber === undefined)
|
|
90
160
|
return null;
|
|
91
161
|
switch (issue.factoryState) {
|
|
92
162
|
case "awaiting_queue":
|
|
93
|
-
return "
|
|
163
|
+
return { text: "\u25a4 queued for merge", color: "cyan" };
|
|
94
164
|
case "repairing_queue":
|
|
95
|
-
return "
|
|
165
|
+
return { text: "! merge queue repair", color: "yellow" };
|
|
96
166
|
case "done":
|
|
97
|
-
return "merged";
|
|
167
|
+
return { text: "\u2713 merged", color: "green" };
|
|
98
168
|
case "pr_open":
|
|
99
|
-
if (issue.prReviewState === "approved" && issue.prCheckStatus === "passed")
|
|
100
|
-
return "ready";
|
|
101
|
-
|
|
169
|
+
if (issue.prReviewState === "approved" && issue.prCheckStatus === "passed") {
|
|
170
|
+
return { text: "\u2713 merge ready", color: "green" };
|
|
171
|
+
}
|
|
172
|
+
return { text: "\u2022 PR open", color: "cyan" };
|
|
102
173
|
default:
|
|
103
174
|
return null;
|
|
104
175
|
}
|
|
105
176
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
return
|
|
125
|
-
|
|
177
|
+
function buildPrimaryBlocker(issue) {
|
|
178
|
+
if (issue.blockedByCount > 0) {
|
|
179
|
+
return {
|
|
180
|
+
text: `Waiting on ${issue.blockedByKeys.join(", ")}`,
|
|
181
|
+
color: "yellow",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (issue.prCheckStatus === "failed" || issue.prCheckStatus === "failure") {
|
|
185
|
+
const failedChecks = issue.prChecksSummary?.failedNames ?? [];
|
|
186
|
+
const failedCheck = issue.latestFailureCheckName
|
|
187
|
+
?? (failedChecks.length > 0 ? failedChecks.slice(0, 2).join(", ") : undefined)
|
|
188
|
+
?? "PR checks";
|
|
189
|
+
return {
|
|
190
|
+
text: `${failedCheck} failed`,
|
|
191
|
+
color: "red",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (issue.prCheckStatus === "pending" || issue.prCheckStatus === "in_progress" || issue.prCheckStatus === "queued") {
|
|
195
|
+
return {
|
|
196
|
+
text: "Waiting for PR checks to finish",
|
|
197
|
+
color: "yellow",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (issue.prReviewState === "changes_requested") {
|
|
201
|
+
return {
|
|
202
|
+
text: "Review changes requested",
|
|
203
|
+
color: "yellow",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (issue.factoryState === "repairing_queue") {
|
|
207
|
+
return {
|
|
208
|
+
text: "Merge queue reported a branch refresh failure",
|
|
209
|
+
color: "yellow",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (issue.factoryState === "awaiting_queue") {
|
|
213
|
+
return {
|
|
214
|
+
text: "Waiting for merge queue turn",
|
|
215
|
+
color: "yellow",
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (issue.prNumber !== undefined && !issue.prReviewState && issue.factoryState !== "done") {
|
|
219
|
+
return {
|
|
220
|
+
text: "Waiting for review approval",
|
|
221
|
+
color: "yellow",
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
126
225
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
226
|
+
function buildPipelineProgress(issue) {
|
|
227
|
+
switch (issue.factoryState) {
|
|
228
|
+
case "delegated":
|
|
229
|
+
return { current: 1, total: 4, label: "delegated" };
|
|
230
|
+
case "implementing":
|
|
231
|
+
return { current: 1, total: 4, label: "implementing" };
|
|
232
|
+
case "pr_open":
|
|
233
|
+
case "changes_requested":
|
|
234
|
+
case "repairing_ci":
|
|
235
|
+
return { current: 2, total: 4, label: "pr checks" };
|
|
236
|
+
case "awaiting_queue":
|
|
237
|
+
case "repairing_queue":
|
|
238
|
+
return { current: 3, total: 4, label: "merge queue" };
|
|
239
|
+
case "done":
|
|
240
|
+
return { current: 4, total: 4, label: "merged" };
|
|
241
|
+
case "failed":
|
|
242
|
+
case "escalated":
|
|
243
|
+
case "awaiting_input":
|
|
244
|
+
return { current: 4, total: 4, label: "stopped" };
|
|
245
|
+
default:
|
|
246
|
+
return { current: 1, total: 4, label: "queued" };
|
|
247
|
+
}
|
|
144
248
|
}
|
|
145
249
|
export function IssueRow({ issue, selected, titleWidth }) {
|
|
146
250
|
const key = issue.issueKey ?? issue.projectId;
|
|
147
|
-
const status = formatStatus(issue);
|
|
148
|
-
const pr = formatPr(issue);
|
|
149
251
|
const ago = relativeTime(issue.updatedAt);
|
|
150
|
-
const tw = titleWidth ??
|
|
252
|
+
const tw = titleWidth ?? 40;
|
|
151
253
|
const title = issue.title ? truncate(issue.title, tw) : "";
|
|
152
254
|
const detail = selected ? summarizeIssueStatusNote(issue.statusNote) : undefined;
|
|
153
|
-
|
|
255
|
+
const status = formatStatus(issue);
|
|
256
|
+
const chips = buildStatusChips(issue);
|
|
257
|
+
const blocker = buildPrimaryBlocker(issue);
|
|
258
|
+
const pipeline = buildPipelineProgress(issue);
|
|
259
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: detail ? 1 : 0, children: [_jsxs(Box, { children: [_jsx(Text, { color: selected ? "blueBright" : "white", bold: selected, children: selected ? "\u25b8" : " " }), _jsx(Text, { bold: true, children: ` ${key}` }), _jsx(Text, { dimColor: true, children: ` ${ago}` }), _jsx(Text, { dimColor: true, children: ` ${status}` })] }), _jsx(Box, { paddingLeft: 2, flexWrap: "wrap", children: title ? _jsx(Text, { children: title }) : null }), _jsx(Box, { paddingLeft: 2, flexWrap: "wrap", children: chips.map((chip, index) => (_jsx(Box, { marginRight: 1, children: _jsxs(Text, { color: chip.color, children: ["[", chip.text, "]"] }) }, `${key}-chip-${index}`))) }), _jsxs(Box, { paddingLeft: 2, gap: 1, children: [_jsx(Text, { dimColor: true, children: progressBar(pipeline.current, pipeline.total, 8) }), _jsx(Text, { dimColor: true, children: pipeline.label }), blocker ? (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "|" }), _jsx(Text, { color: blocker.color, children: blocker.text })] })) : null] }), detail ? (_jsx(Box, { paddingLeft: 4, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: detail }) })) : null] }));
|
|
154
260
|
}
|
package/dist/service.js
CHANGED
|
@@ -35,6 +35,53 @@ function extractStatusNote(summaryJson, reportJson) {
|
|
|
35
35
|
}
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
|
+
export function parseCiSnapshotSummary(snapshotJson) {
|
|
39
|
+
if (!snapshotJson)
|
|
40
|
+
return undefined;
|
|
41
|
+
try {
|
|
42
|
+
const snapshot = JSON.parse(snapshotJson);
|
|
43
|
+
const rawChecks = Array.isArray(snapshot.checks) ? snapshot.checks : [];
|
|
44
|
+
const checks = collapseEffectiveChecks(rawChecks);
|
|
45
|
+
if (checks.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
let passed = 0;
|
|
48
|
+
let failed = 0;
|
|
49
|
+
let pending = 0;
|
|
50
|
+
const failedNames = [];
|
|
51
|
+
for (const check of checks) {
|
|
52
|
+
if (check.status === "success")
|
|
53
|
+
passed++;
|
|
54
|
+
else if (check.status === "failure") {
|
|
55
|
+
failed++;
|
|
56
|
+
failedNames.push(check.name);
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
pending++;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
total: checks.length,
|
|
63
|
+
completed: passed + failed,
|
|
64
|
+
passed,
|
|
65
|
+
failed,
|
|
66
|
+
pending,
|
|
67
|
+
overall: snapshot.gateCheckStatus,
|
|
68
|
+
...(failedNames.length > 0 ? { failedNames } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function collapseEffectiveChecks(checks) {
|
|
76
|
+
const effective = new Map();
|
|
77
|
+
for (const check of checks) {
|
|
78
|
+
const name = typeof check?.name === "string" ? check.name.trim() : "";
|
|
79
|
+
if (!name || effective.has(name))
|
|
80
|
+
continue;
|
|
81
|
+
effective.set(name, check);
|
|
82
|
+
}
|
|
83
|
+
return [...effective.values()];
|
|
84
|
+
}
|
|
38
85
|
export class PatchRelayService {
|
|
39
86
|
config;
|
|
40
87
|
db;
|
|
@@ -221,6 +268,7 @@ export class PatchRelayService {
|
|
|
221
268
|
i.current_linear_state, i.factory_state, i.updated_at,
|
|
222
269
|
i.pending_run_type,
|
|
223
270
|
i.pr_number, i.pr_review_state, i.pr_check_status,
|
|
271
|
+
i.last_github_ci_snapshot_json,
|
|
224
272
|
i.last_github_failure_source,
|
|
225
273
|
i.last_github_failure_head_sha,
|
|
226
274
|
i.last_github_failure_check_name,
|
|
@@ -267,6 +315,7 @@ export class PatchRelayService {
|
|
|
267
315
|
.all();
|
|
268
316
|
return rows.map((row) => {
|
|
269
317
|
const failureContext = parseGitHubFailureContext(typeof row.last_github_failure_context_json === "string" ? row.last_github_failure_context_json : undefined);
|
|
318
|
+
const prChecksSummary = parseCiSnapshotSummary(typeof row.last_github_ci_snapshot_json === "string" ? row.last_github_ci_snapshot_json : undefined);
|
|
270
319
|
const statusNote = extractStatusNote(typeof row.latest_run_summary_json === "string" ? row.latest_run_summary_json : undefined, typeof row.latest_run_report_json === "string" ? row.latest_run_report_json : undefined);
|
|
271
320
|
const blockedByKeys = parseStringArray(typeof row.blocked_by_keys_json === "string" ? row.blocked_by_keys_json : undefined);
|
|
272
321
|
const blockedByCount = Number(row.blocked_by_count ?? 0);
|
|
@@ -299,6 +348,7 @@ export class PatchRelayService {
|
|
|
299
348
|
...(row.pr_number !== null ? { prNumber: Number(row.pr_number) } : {}),
|
|
300
349
|
...(row.pr_review_state !== null ? { prReviewState: String(row.pr_review_state) } : {}),
|
|
301
350
|
...(row.pr_check_status !== null ? { prCheckStatus: String(row.pr_check_status) } : {}),
|
|
351
|
+
...(prChecksSummary ? { prChecksSummary } : {}),
|
|
302
352
|
...(row.last_github_failure_source !== null ? { latestFailureSource: String(row.last_github_failure_source) } : {}),
|
|
303
353
|
...(row.last_github_failure_head_sha !== null ? { latestFailureHeadSha: String(row.last_github_failure_head_sha) } : {}),
|
|
304
354
|
...(row.last_github_failure_check_name !== null ? { latestFailureCheckName: String(row.last_github_failure_check_name) } : {}),
|