merge-steward 0.25.0 → 0.26.0
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/db/schema.js +2 -0
- package/dist/db/sqlite-store.js +3 -2
- package/dist/github/pr-client.js +4 -1
- package/dist/service-queue.d.ts +7 -0
- package/dist/service-queue.js +31 -0
- package/dist/types.d.ts +13 -0
- package/package.json +1 -1
package/dist/db/schema.js
CHANGED
|
@@ -76,6 +76,8 @@ export function ensureSchema(connection) {
|
|
|
76
76
|
ensureColumn(connection, "queue_entries", "post_merge_checked_at", "TEXT");
|
|
77
77
|
ensureColumn(connection, "queue_entries", "wait_detail", "TEXT");
|
|
78
78
|
ensureColumn(connection, "queue_entries", "pr_title", "TEXT");
|
|
79
|
+
// Plan §8.4: stack-aware admission ordering needs the PR's base ref.
|
|
80
|
+
ensureColumn(connection, "queue_entries", "base_ref_name", "TEXT");
|
|
79
81
|
// Plan §5.3: cached identity for patch-id-aware updateHead.
|
|
80
82
|
ensureColumn(connection, "queue_entries", "head_patch_id", "TEXT");
|
|
81
83
|
ensureColumn(connection, "queue_entries", "spec_tree_id", "TEXT");
|
package/dist/db/sqlite-store.js
CHANGED
|
@@ -30,6 +30,7 @@ function mapEntry(row) {
|
|
|
30
30
|
postMergeSummary: row.post_merge_summary === null || row.post_merge_summary === undefined ? null : String(row.post_merge_summary),
|
|
31
31
|
postMergeCheckedAt: row.post_merge_checked_at === null || row.post_merge_checked_at === undefined ? null : String(row.post_merge_checked_at),
|
|
32
32
|
prTitle: row.pr_title === null || row.pr_title === undefined ? null : String(row.pr_title),
|
|
33
|
+
baseRefName: row.base_ref_name === null || row.base_ref_name === undefined ? null : String(row.base_ref_name),
|
|
33
34
|
headPatchId: row.head_patch_id === null || row.head_patch_id === undefined ? null : String(row.head_patch_id),
|
|
34
35
|
specTreeId: row.spec_tree_id === null || row.spec_tree_id === undefined ? null : String(row.spec_tree_id),
|
|
35
36
|
enqueuedAt: String(row.enqueued_at),
|
|
@@ -128,9 +129,9 @@ export class SqliteStore {
|
|
|
128
129
|
priority, generation, ci_run_id, ci_retries, retry_attempts,
|
|
129
130
|
max_retries, last_failed_base_sha, issue_key, wait_detail,
|
|
130
131
|
post_merge_status, post_merge_sha, post_merge_summary, post_merge_checked_at,
|
|
131
|
-
pr_title,
|
|
132
|
+
pr_title, base_ref_name,
|
|
132
133
|
enqueued_at, updated_at)
|
|
133
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(entry.id, entry.repoId, entry.prNumber, entry.branch, entry.headSha, entry.baseSha, entry.status, entry.position, entry.priority, entry.generation, entry.ciRunId, entry.ciRetries, entry.retryAttempts, entry.maxRetries, entry.lastFailedBaseSha, entry.issueKey ?? null, entry.waitDetail ?? null, entry.postMergeStatus ?? null, entry.postMergeSha ?? null, entry.postMergeSummary ?? null, entry.postMergeCheckedAt ?? null, entry.prTitle ?? null, entry.enqueuedAt, entry.updatedAt);
|
|
134
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(entry.id, entry.repoId, entry.prNumber, entry.branch, entry.headSha, entry.baseSha, entry.status, entry.position, entry.priority, entry.generation, entry.ciRunId, entry.ciRetries, entry.retryAttempts, entry.maxRetries, entry.lastFailedBaseSha, entry.issueKey ?? null, entry.waitDetail ?? null, entry.postMergeStatus ?? null, entry.postMergeSha ?? null, entry.postMergeSummary ?? null, entry.postMergeCheckedAt ?? null, entry.prTitle ?? null, entry.baseRefName ?? null, entry.enqueuedAt, entry.updatedAt);
|
|
134
135
|
this.writeEvent(entry.id, null, entry.status);
|
|
135
136
|
})();
|
|
136
137
|
}
|
package/dist/github/pr-client.js
CHANGED
|
@@ -24,7 +24,9 @@ export class GitHubPRClient {
|
|
|
24
24
|
const result = await exec("gh", [
|
|
25
25
|
"pr", "view", String(prNumber),
|
|
26
26
|
"--repo", this.repoFullName,
|
|
27
|
-
|
|
27
|
+
// Plan §8.4 change 3a: include baseRefName so the queue can
|
|
28
|
+
// detect stacked PRs at admission time.
|
|
29
|
+
"--json", "number,title,headRefName,headRefOid,baseRefName,reviewDecision,state,mergeStateStatus",
|
|
28
30
|
], { githubRepoFullName: this.repoFullName });
|
|
29
31
|
const data = JSON.parse(result.stdout);
|
|
30
32
|
return {
|
|
@@ -32,6 +34,7 @@ export class GitHubPRClient {
|
|
|
32
34
|
branch: data.headRefName,
|
|
33
35
|
headSha: data.headRefOid,
|
|
34
36
|
...(data.title ? { title: data.title } : {}),
|
|
37
|
+
...(data.baseRefName ? { baseRefName: data.baseRefName } : {}),
|
|
35
38
|
mergeable: data.state === "OPEN",
|
|
36
39
|
mergeStateStatus: data.mergeStateStatus,
|
|
37
40
|
reviewDecision: data.reviewDecision,
|
package/dist/service-queue.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ export declare class MergeStewardQueueCommands {
|
|
|
19
19
|
issueKey?: string;
|
|
20
20
|
priority?: number;
|
|
21
21
|
prTitle?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Plan §8.4: PR's base ref. When this matches another open PR's
|
|
24
|
+
* `branch` (head ref), the entry is stacked and admission orders
|
|
25
|
+
* it immediately behind the parent.
|
|
26
|
+
*/
|
|
27
|
+
baseRefName?: string;
|
|
22
28
|
}): QueueEntry | undefined;
|
|
23
29
|
scanStartupAdmissions(): Promise<void>;
|
|
24
30
|
scanEligibleOpenPrs(): Promise<{
|
|
@@ -34,4 +40,5 @@ export declare class MergeStewardQueueCommands {
|
|
|
34
40
|
private findAffectedEntriesAfterPriorityChange;
|
|
35
41
|
private requeueAffectedEntries;
|
|
36
42
|
private nextPosition;
|
|
43
|
+
private findActiveEntryByBranch;
|
|
37
44
|
}
|
package/dist/service-queue.js
CHANGED
|
@@ -66,6 +66,7 @@ export class MergeStewardQueueCommands {
|
|
|
66
66
|
headPatchId: null,
|
|
67
67
|
specTreeId: null,
|
|
68
68
|
prTitle: params.prTitle ?? null,
|
|
69
|
+
baseRefName: params.baseRefName ?? null,
|
|
69
70
|
enqueuedAt: new Date().toISOString(),
|
|
70
71
|
updatedAt: new Date().toISOString(),
|
|
71
72
|
};
|
|
@@ -185,12 +186,36 @@ export class MergeStewardQueueCommands {
|
|
|
185
186
|
return false;
|
|
186
187
|
}
|
|
187
188
|
}
|
|
189
|
+
// Plan §8.4: stack-aware admission. When the PR's base ref
|
|
190
|
+
// names another open PR's branch (head ref), the entry is
|
|
191
|
+
// stacked. Enqueue it only when the parent is already in the
|
|
192
|
+
// queue — otherwise the child's spec would build against the
|
|
193
|
+
// unmerged parent's pre-spec content. Positions are monotonic
|
|
194
|
+
// (`nextPosition`), so the child's position is always greater
|
|
195
|
+
// than the parent's; sibling PRs admitted between the parent's
|
|
196
|
+
// enqueue and the child's tryAdmit can sit between them. That's
|
|
197
|
+
// fine: queue head selection orders by (priority, position), so
|
|
198
|
+
// the parent is still processed before the child. The functional
|
|
199
|
+
// guarantee is "parent before child", not strict adjacency.
|
|
200
|
+
const baseRefName = status.baseRefName ?? null;
|
|
201
|
+
if (baseRefName && baseRefName !== this.config.baseBranch) {
|
|
202
|
+
const parentEntry = this.findActiveEntryByBranch(baseRefName);
|
|
203
|
+
if (!parentEntry) {
|
|
204
|
+
this.logger.debug({
|
|
205
|
+
prNumber,
|
|
206
|
+
baseRefName,
|
|
207
|
+
repoBaseBranch: this.config.baseBranch,
|
|
208
|
+
}, "Deferring admission for stacked PR — parent branch is not in the queue yet");
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
188
212
|
this.enqueue({
|
|
189
213
|
prNumber,
|
|
190
214
|
branch,
|
|
191
215
|
headSha,
|
|
192
216
|
priority,
|
|
193
217
|
...(status.title ? { prTitle: status.title } : {}),
|
|
218
|
+
...(baseRefName ? { baseRefName } : {}),
|
|
194
219
|
});
|
|
195
220
|
return true;
|
|
196
221
|
}
|
|
@@ -279,4 +304,10 @@ export class MergeStewardQueueCommands {
|
|
|
279
304
|
}
|
|
280
305
|
return next;
|
|
281
306
|
}
|
|
307
|
+
// Plan §8.4: lookup helper used by stack-aware admission. Returns
|
|
308
|
+
// the active queue entry whose `branch` (head ref) matches `name`,
|
|
309
|
+
// or undefined when no such entry is in the queue.
|
|
310
|
+
findActiveEntryByBranch(name) {
|
|
311
|
+
return this.store.listActive(this.config.repoId).find((entry) => entry.branch === name);
|
|
312
|
+
}
|
|
282
313
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -50,6 +50,13 @@ export interface QueueEntry {
|
|
|
50
50
|
postMergeSummary: string | null;
|
|
51
51
|
/** Timestamp of the most recent post-merge verification attempt. */
|
|
52
52
|
postMergeCheckedAt: string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Plan §8.4: PR's base ref captured at admission. When this names
|
|
55
|
+
* another open PR's `branch` (head ref), the entry is stacked and
|
|
56
|
+
* the queue holds it behind the parent until the parent is itself
|
|
57
|
+
* admitted. `null` when the PR was opened against the repo default.
|
|
58
|
+
*/
|
|
59
|
+
baseRefName: string | null;
|
|
53
60
|
/**
|
|
54
61
|
* Plan §5.3: stable patch-id (`git patch-id --stable`) of the
|
|
55
62
|
* current `headSha` against the entry's `baseSha`. Cached at spec
|
|
@@ -198,6 +205,12 @@ export interface PRStatus {
|
|
|
198
205
|
branch: string;
|
|
199
206
|
headSha: string;
|
|
200
207
|
title?: string | undefined;
|
|
208
|
+
/**
|
|
209
|
+
* Plan §8.4: PR's base ref. When this names another open PR's
|
|
210
|
+
* `branch` (head ref), the PR is stacked and admission must defer
|
|
211
|
+
* until the parent is in the queue.
|
|
212
|
+
*/
|
|
213
|
+
baseRefName?: string | undefined;
|
|
201
214
|
mergeable: boolean;
|
|
202
215
|
mergeStateStatus?: string | undefined;
|
|
203
216
|
reviewDecision?: string | undefined;
|