merge-steward 0.5.4 → 0.5.6
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/github/pr-client.js +2 -1
- package/dist/reconciler.js +16 -3
- package/dist/service.js +4 -0
- package/dist/types.d.ts +1 -0
- package/dist/watch/format.js +1 -1
- package/package.json +1 -1
package/dist/github/pr-client.js
CHANGED
|
@@ -24,7 +24,7 @@ export class GitHubPRClient {
|
|
|
24
24
|
const result = await exec("gh", [
|
|
25
25
|
"pr", "view", String(prNumber),
|
|
26
26
|
"--repo", this.repoFullName,
|
|
27
|
-
"--json", "number,headRefName,headRefOid,reviewDecision,state",
|
|
27
|
+
"--json", "number,headRefName,headRefOid,reviewDecision,state,mergeStateStatus",
|
|
28
28
|
], { githubRepoFullName: this.repoFullName });
|
|
29
29
|
const data = JSON.parse(result.stdout);
|
|
30
30
|
return {
|
|
@@ -32,6 +32,7 @@ export class GitHubPRClient {
|
|
|
32
32
|
branch: data.headRefName,
|
|
33
33
|
headSha: data.headRefOid,
|
|
34
34
|
mergeable: data.state === "OPEN",
|
|
35
|
+
mergeStateStatus: data.mergeStateStatus,
|
|
35
36
|
reviewApproved: data.reviewDecision === "APPROVED",
|
|
36
37
|
merged: data.state === "MERGED",
|
|
37
38
|
};
|
package/dist/reconciler.js
CHANGED
|
@@ -114,6 +114,19 @@ async function prepareHead(ctx, entry) {
|
|
|
114
114
|
// Gate: non-spinning — skip if base hasn't changed since last conflict.
|
|
115
115
|
if (isRetryGated(entry, baseSha)) {
|
|
116
116
|
emit(ctx, entry, "retry_gated", { baseSha, detail: "base unchanged since last conflict" });
|
|
117
|
+
try {
|
|
118
|
+
const prStatus = await ctx.github.getStatus(entry.prNumber);
|
|
119
|
+
if (prStatus.mergeStateStatus === "DIRTY") {
|
|
120
|
+
emit(ctx, entry, "budget_exhausted", {
|
|
121
|
+
baseSha,
|
|
122
|
+
detail: "retry gated and GitHub still reports merge conflict",
|
|
123
|
+
});
|
|
124
|
+
await evictEntry(ctx, entry, "integration_conflict");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Best-effort check. If GitHub status is unavailable, preserve the non-spinning wait.
|
|
129
|
+
}
|
|
117
130
|
return;
|
|
118
131
|
}
|
|
119
132
|
await performBranchRefresh(ctx, entry, baseSha);
|
|
@@ -136,7 +149,7 @@ function summarizeCheckNames(checks, limit = 3) {
|
|
|
136
149
|
return `${names.slice(0, limit).join(", ")} +${names.length - limit} more`;
|
|
137
150
|
}
|
|
138
151
|
async function performBranchRefresh(ctx, entry, baseSha) {
|
|
139
|
-
emit(ctx, entry, "rebase_started", { baseSha });
|
|
152
|
+
emit(ctx, entry, "rebase_started", { baseSha, detail: `refreshing ${entry.branch} with ${ctx.baseBranch}` });
|
|
140
153
|
const result = await ctx.git.mergeBaseInto(entry.branch, ref(ctx, ctx.baseBranch));
|
|
141
154
|
if (!result.success) {
|
|
142
155
|
emit(ctx, entry, "rebase_conflict", { baseSha, conflictFiles: result.conflictFiles });
|
|
@@ -164,7 +177,7 @@ async function performBranchRefresh(ctx, entry, baseSha) {
|
|
|
164
177
|
return;
|
|
165
178
|
}
|
|
166
179
|
await ctx.git.push(entry.branch, false);
|
|
167
|
-
emit(ctx, entry, "rebase_succeeded", { baseSha });
|
|
180
|
+
emit(ctx, entry, "rebase_succeeded", { baseSha, detail: `refreshed ${entry.branch} with ${ctx.baseBranch}` });
|
|
168
181
|
// Build speculative branch for downstream entries.
|
|
169
182
|
let specBranch = null;
|
|
170
183
|
let specSha = null;
|
|
@@ -186,7 +199,7 @@ async function performBranchRefresh(ctx, entry, baseSha) {
|
|
|
186
199
|
ctx.store.transition(entry.id, "validating", {
|
|
187
200
|
headSha, baseSha, ciRunId: runId, lastFailedBaseSha: null,
|
|
188
201
|
specBranch, specSha, specBasedOn: null,
|
|
189
|
-
}, `
|
|
202
|
+
}, `refreshed with ${ctx.baseBranch} @ ${baseSha.slice(0, 8)}, CI ${runId}`);
|
|
190
203
|
}
|
|
191
204
|
// ─── Non-head entry: speculative branch ─────────────────────────
|
|
192
205
|
async function prepareSpeculative(ctx, entry, prevEntry) {
|
package/dist/service.js
CHANGED
|
@@ -222,6 +222,10 @@ export class MergeStewardService {
|
|
|
222
222
|
updateHeadByPR(prNumber, headSha) {
|
|
223
223
|
const entry = this.store.getEntryByPR(this.config.repoId, prNumber);
|
|
224
224
|
if (entry) {
|
|
225
|
+
if (entry.headSha === headSha) {
|
|
226
|
+
this.logger.debug({ prNumber, entryId: entry.id, headSha }, "Ignoring synchronize webhook for unchanged head");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
225
229
|
this.store.updateHead(entry.id, headSha);
|
|
226
230
|
this.logger.info({ prNumber, entryId: entry.id, headSha }, "PR head updated via webhook");
|
|
227
231
|
}
|
package/dist/types.d.ts
CHANGED
package/dist/watch/format.js
CHANGED
|
@@ -76,7 +76,7 @@ export function nextStepLabel(status) {
|
|
|
76
76
|
case "queued":
|
|
77
77
|
return "waiting for head-of-line turn";
|
|
78
78
|
case "preparing_head":
|
|
79
|
-
return "
|
|
79
|
+
return "refreshing branch with latest main";
|
|
80
80
|
case "validating":
|
|
81
81
|
return "waiting for CI result";
|
|
82
82
|
case "merging":
|