merge-steward 0.30.0 → 0.30.1
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.
|
@@ -4,6 +4,19 @@ import { type ResolveCommandRunner } from "../resolve.ts";
|
|
|
4
4
|
import { type PrGitHubOverview } from "./pr-github.ts";
|
|
5
5
|
export type PrStatusKind = "merged" | "merged_outside_queue" | "queued" | "preparing_head" | "validating" | "merging" | "evicted" | "dequeued" | "closed" | "changes_requested" | "checks_failing" | "checks_pending" | "approved_clean" | "not_queued";
|
|
6
6
|
export type PrStatusSource = "queue" | "github";
|
|
7
|
+
/**
|
|
8
|
+
* Live position of an entry among the entries actually still in the queue,
|
|
9
|
+
* ordered the way the reconciler processes them (priority DESC, position
|
|
10
|
+
* ASC). This is what an operator means by "where am I in line" — unlike the
|
|
11
|
+
* raw `position`, which is a lifetime admission counter that only ever
|
|
12
|
+
* grows (every PR ever queued bumps it), so a value like 290 reads as "289
|
|
13
|
+
* ahead" when in reality only a couple of entries are active.
|
|
14
|
+
*/
|
|
15
|
+
export interface QueueActiveRank {
|
|
16
|
+
rank: number;
|
|
17
|
+
activeTotal: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function computeActiveRank(entries: QueueEntry[], target: QueueEntry): QueueActiveRank | undefined;
|
|
7
20
|
export interface PrStatusReport {
|
|
8
21
|
repoId: string;
|
|
9
22
|
repoFullName: string;
|
|
@@ -15,6 +28,7 @@ export interface PrStatusReport {
|
|
|
15
28
|
reason?: string;
|
|
16
29
|
queueEntry?: QueueEntry;
|
|
17
30
|
queueSource?: "service" | "database";
|
|
31
|
+
queueActiveRank?: QueueActiveRank;
|
|
18
32
|
queueRuntime?: QueueRuntimeStatus;
|
|
19
33
|
queueLatestEvent?: QueueEventSummary;
|
|
20
34
|
github?: PrGitHubOverview;
|
|
@@ -32,6 +46,7 @@ export interface BuildReportOptions {
|
|
|
32
46
|
prNumber: number;
|
|
33
47
|
queueEntry?: QueueEntry | undefined;
|
|
34
48
|
queueSource?: "service" | "database" | undefined;
|
|
49
|
+
queueActiveRank?: QueueActiveRank | undefined;
|
|
35
50
|
queueRuntime?: QueueRuntimeStatus | undefined;
|
|
36
51
|
queueLatestEvent?: QueueEventSummary | undefined;
|
|
37
52
|
github?: PrGitHubOverview | undefined;
|
|
@@ -5,6 +5,18 @@ import { defaultResolveRunner, resolvePrNumber, resolveRepo } from "../resolve.j
|
|
|
5
5
|
import { parseIntegerFlag } from "../args.js";
|
|
6
6
|
import { fetchPrGitHubOverview } from "./pr-github.js";
|
|
7
7
|
import { formatRuntimeActivity } from "../../runtime-format.js";
|
|
8
|
+
const TERMINAL_QUEUE_STATUSES = new Set(["merged", "evicted", "dequeued"]);
|
|
9
|
+
export function computeActiveRank(entries, target) {
|
|
10
|
+
if (TERMINAL_QUEUE_STATUSES.has(target.status))
|
|
11
|
+
return undefined;
|
|
12
|
+
const active = entries
|
|
13
|
+
.filter((entry) => !TERMINAL_QUEUE_STATUSES.has(entry.status))
|
|
14
|
+
.sort((a, b) => (b.priority - a.priority) || (a.position - b.position));
|
|
15
|
+
const index = active.findIndex((entry) => entry.id === target.id);
|
|
16
|
+
if (index < 0)
|
|
17
|
+
return undefined;
|
|
18
|
+
return { rank: index + 1, activeTotal: active.length };
|
|
19
|
+
}
|
|
8
20
|
export function classifyQueueEntry(entry) {
|
|
9
21
|
switch (entry.status) {
|
|
10
22
|
case "merged": return "merged";
|
|
@@ -85,11 +97,13 @@ async function loadQueueEntry(config, prNumber) {
|
|
|
85
97
|
if (!entry)
|
|
86
98
|
return { kind: "not_found" };
|
|
87
99
|
const latestEvent = latestEventForPr(snapshot, prNumber);
|
|
100
|
+
const activeRank = computeActiveRank(snapshot.entries, entry);
|
|
88
101
|
return {
|
|
89
102
|
kind: "found",
|
|
90
103
|
entry,
|
|
91
104
|
source: "service",
|
|
92
105
|
runtime: snapshot.runtime,
|
|
106
|
+
...(activeRank ? { activeRank } : {}),
|
|
93
107
|
...(latestEvent ? { latestEvent } : {}),
|
|
94
108
|
};
|
|
95
109
|
}
|
|
@@ -99,7 +113,8 @@ async function loadQueueEntry(config, prNumber) {
|
|
|
99
113
|
}
|
|
100
114
|
const store = new SqliteStore(config.database.path);
|
|
101
115
|
try {
|
|
102
|
-
const
|
|
116
|
+
const all = store.listAll(config.repoId);
|
|
117
|
+
const entries = all.filter((entry) => entry.prNumber === prNumber);
|
|
103
118
|
if (entries.length === 0)
|
|
104
119
|
return { kind: "not_found" };
|
|
105
120
|
entries.sort((left, right) => {
|
|
@@ -109,7 +124,9 @@ async function loadQueueEntry(config, prNumber) {
|
|
|
109
124
|
return leftTerminal - rightTerminal;
|
|
110
125
|
return right.position - left.position;
|
|
111
126
|
});
|
|
112
|
-
|
|
127
|
+
const entry = entries[0];
|
|
128
|
+
const activeRank = computeActiveRank(all, entry);
|
|
129
|
+
return { kind: "found", entry, source: "database", ...(activeRank ? { activeRank } : {}) };
|
|
113
130
|
}
|
|
114
131
|
finally {
|
|
115
132
|
store.close();
|
|
@@ -138,6 +155,7 @@ export function buildPrStatusReport(options) {
|
|
|
138
155
|
exitCode: exitCodeForKind(kind),
|
|
139
156
|
queueEntry: options.queueEntry,
|
|
140
157
|
...(options.queueSource ? { queueSource: options.queueSource } : {}),
|
|
158
|
+
...(options.queueActiveRank ? { queueActiveRank: options.queueActiveRank } : {}),
|
|
141
159
|
...(options.queueRuntime ? { queueRuntime: options.queueRuntime } : {}),
|
|
142
160
|
...(options.queueLatestEvent ? { queueLatestEvent: options.queueLatestEvent } : {}),
|
|
143
161
|
checkedAt,
|
|
@@ -172,7 +190,12 @@ export function formatReportText(report) {
|
|
|
172
190
|
lines.push(`Reason: ${report.reason}`);
|
|
173
191
|
if (report.queueEntry) {
|
|
174
192
|
const entry = report.queueEntry;
|
|
175
|
-
|
|
193
|
+
// Show live rank among active entries — NOT the raw `position`, which is
|
|
194
|
+
// a lifetime admission counter and reads as a huge phantom backlog.
|
|
195
|
+
if (report.queueActiveRank) {
|
|
196
|
+
const { rank, activeTotal } = report.queueActiveRank;
|
|
197
|
+
lines.push(`Queue position: ${rank} of ${activeTotal} active`);
|
|
198
|
+
}
|
|
176
199
|
lines.push(`Branch: ${entry.branch}`);
|
|
177
200
|
lines.push(`Head SHA: ${entry.headSha}`);
|
|
178
201
|
if (entry.waitDetail)
|
|
@@ -260,6 +283,7 @@ export async function handlePrStatus(options) {
|
|
|
260
283
|
prNumber: resolvedPr.prNumber,
|
|
261
284
|
queueEntry: queueResult.entry,
|
|
262
285
|
queueSource: queueResult.source,
|
|
286
|
+
...(queueResult.activeRank ? { queueActiveRank: queueResult.activeRank } : {}),
|
|
263
287
|
...(queueResult.runtime ? { queueRuntime: queueResult.runtime } : {}),
|
|
264
288
|
...(queueResult.latestEvent ? { queueLatestEvent: queueResult.latestEvent } : {}),
|
|
265
289
|
});
|