patchrelay 0.30.0 → 0.31.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/build-info.json +3 -3
- package/dist/cli/watch/IssueDetailView.js +1 -1
- package/dist/cli/watch/use-detail-stream.js +5 -0
- package/dist/cli/watch/watch-state.js +14 -0
- package/dist/db/migrations.js +9 -0
- package/dist/db.js +82 -14
- package/dist/github-failure-context.js +205 -0
- package/dist/github-webhook-handler.js +140 -22
- package/dist/issue-query-service.js +6 -0
- package/dist/linear-client.js +2 -0
- package/dist/run-orchestrator.js +155 -9
- package/dist/service.js +28 -3
- package/dist/webhook-handler.js +20 -14
- package/dist/webhooks.js +1 -0
- package/package.json +1 -1
package/dist/service.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveGitHubAppCredentials, createGitHubAppTokenManager, ensureGhWrapper, } from "./github-app-token.js";
|
|
2
|
+
import { parseGitHubFailureContext, summarizeGitHubFailureContext } from "./github-failure-context.js";
|
|
2
3
|
import { GitHubWebhookHandler } from "./github-webhook-handler.js";
|
|
3
4
|
import { IssueQueryService } from "./issue-query-service.js";
|
|
4
5
|
import { DatabaseBackedLinearClientProvider } from "./linear-client.js";
|
|
@@ -216,6 +217,10 @@ export class PatchRelayService {
|
|
|
216
217
|
i.current_linear_state, i.factory_state, i.updated_at,
|
|
217
218
|
i.pending_run_type,
|
|
218
219
|
i.pr_number, i.pr_review_state, i.pr_check_status,
|
|
220
|
+
i.last_github_failure_source,
|
|
221
|
+
i.last_github_failure_head_sha,
|
|
222
|
+
i.last_github_failure_check_name,
|
|
223
|
+
i.last_github_failure_context_json,
|
|
219
224
|
active_run.run_type AS active_run_type,
|
|
220
225
|
latest_run.run_type AS latest_run_type,
|
|
221
226
|
latest_run.status AS latest_run_status,
|
|
@@ -229,7 +234,10 @@ export class PatchRelayService {
|
|
|
229
234
|
AND blockers.linear_issue_id = d.blocker_linear_issue_id
|
|
230
235
|
WHERE d.project_id = i.project_id
|
|
231
236
|
AND d.linear_issue_id = i.linear_issue_id
|
|
232
|
-
AND
|
|
237
|
+
AND (
|
|
238
|
+
COALESCE(blockers.current_linear_state_type, d.blocker_current_linear_state_type, '') != 'completed'
|
|
239
|
+
AND LOWER(TRIM(COALESCE(blockers.current_linear_state, d.blocker_current_linear_state, ''))) != 'done'
|
|
240
|
+
)
|
|
233
241
|
) AS blocked_by_count,
|
|
234
242
|
(
|
|
235
243
|
SELECT json_group_array(COALESCE(blockers.issue_key, d.blocker_issue_key, d.blocker_linear_issue_id))
|
|
@@ -239,7 +247,10 @@ export class PatchRelayService {
|
|
|
239
247
|
AND blockers.linear_issue_id = d.blocker_linear_issue_id
|
|
240
248
|
WHERE d.project_id = i.project_id
|
|
241
249
|
AND d.linear_issue_id = i.linear_issue_id
|
|
242
|
-
AND
|
|
250
|
+
AND (
|
|
251
|
+
COALESCE(blockers.current_linear_state_type, d.blocker_current_linear_state_type, '') != 'completed'
|
|
252
|
+
AND LOWER(TRIM(COALESCE(blockers.current_linear_state, d.blocker_current_linear_state, ''))) != 'done'
|
|
253
|
+
)
|
|
243
254
|
) AS blocked_by_keys_json
|
|
244
255
|
FROM issues i
|
|
245
256
|
LEFT JOIN runs active_run ON active_run.id = i.active_run_id
|
|
@@ -251,13 +262,22 @@ export class PatchRelayService {
|
|
|
251
262
|
ORDER BY i.updated_at DESC, i.issue_key ASC`)
|
|
252
263
|
.all();
|
|
253
264
|
return rows.map((row) => {
|
|
265
|
+
const failureContext = parseGitHubFailureContext(typeof row.last_github_failure_context_json === "string" ? row.last_github_failure_context_json : undefined);
|
|
254
266
|
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);
|
|
255
267
|
const blockedByKeys = parseStringArray(typeof row.blocked_by_keys_json === "string" ? row.blocked_by_keys_json : undefined);
|
|
256
268
|
const blockedByCount = Number(row.blocked_by_count ?? 0);
|
|
257
269
|
const readyForExecution = row.pending_run_type !== null && row.pending_run_type !== undefined && row.active_run_type === null && blockedByCount === 0;
|
|
270
|
+
const failureSummary = summarizeGitHubFailureContext(failureContext);
|
|
271
|
+
const derivedStatusNote = blockedByCount > 0
|
|
272
|
+
? `Blocked by ${blockedByKeys.join(", ")}`
|
|
273
|
+
: failureSummary && (row.factory_state === "repairing_ci"
|
|
274
|
+
|| row.factory_state === "repairing_queue"
|
|
275
|
+
|| row.factory_state === "failed")
|
|
276
|
+
? failureSummary
|
|
277
|
+
: statusNote;
|
|
258
278
|
const statusNoteWithBlockers = blockedByCount > 0
|
|
259
279
|
? `Blocked by ${blockedByKeys.join(", ")}`
|
|
260
|
-
:
|
|
280
|
+
: derivedStatusNote;
|
|
261
281
|
return {
|
|
262
282
|
...(row.issue_key !== null ? { issueKey: String(row.issue_key) } : {}),
|
|
263
283
|
...(row.title !== null ? { title: String(row.title) } : {}),
|
|
@@ -275,6 +295,11 @@ export class PatchRelayService {
|
|
|
275
295
|
...(row.pr_number !== null ? { prNumber: Number(row.pr_number) } : {}),
|
|
276
296
|
...(row.pr_review_state !== null ? { prReviewState: String(row.pr_review_state) } : {}),
|
|
277
297
|
...(row.pr_check_status !== null ? { prCheckStatus: String(row.pr_check_status) } : {}),
|
|
298
|
+
...(row.last_github_failure_source !== null ? { latestFailureSource: String(row.last_github_failure_source) } : {}),
|
|
299
|
+
...(row.last_github_failure_head_sha !== null ? { latestFailureHeadSha: String(row.last_github_failure_head_sha) } : {}),
|
|
300
|
+
...(row.last_github_failure_check_name !== null ? { latestFailureCheckName: String(row.last_github_failure_check_name) } : {}),
|
|
301
|
+
...(failureContext?.stepName ? { latestFailureStepName: failureContext.stepName } : {}),
|
|
302
|
+
...(failureContext?.summary ? { latestFailureSummary: failureContext.summary } : {}),
|
|
278
303
|
updatedAt: String(row.updated_at),
|
|
279
304
|
};
|
|
280
305
|
});
|
package/dist/webhook-handler.js
CHANGED
|
@@ -180,6 +180,7 @@ export class WebhookHandler {
|
|
|
180
180
|
...(hydratedIssue.priority != null ? { priority: hydratedIssue.priority } : {}),
|
|
181
181
|
...(hydratedIssue.estimate != null ? { estimate: hydratedIssue.estimate } : {}),
|
|
182
182
|
...(hydratedIssue.stateName ? { currentLinearState: hydratedIssue.stateName } : {}),
|
|
183
|
+
...(hydratedIssue.stateType ? { currentLinearStateType: hydratedIssue.stateType } : {}),
|
|
183
184
|
...(pendingRunType ? { pendingRunType, factoryState: "delegated" } : {}),
|
|
184
185
|
...(clearPendingImplementation ? { pendingRunType: null } : {}),
|
|
185
186
|
...((pendingRunType || existingIssue?.pendingRunType === "implementation") && pendingRunContextJson
|
|
@@ -203,27 +204,30 @@ export class WebhookHandler {
|
|
|
203
204
|
}
|
|
204
205
|
async syncIssueDependencies(projectId, issue) {
|
|
205
206
|
let source = issue;
|
|
206
|
-
if (source.
|
|
207
|
+
if (!source.relationsKnown) {
|
|
207
208
|
const linear = await this.linearProvider.forProject(projectId);
|
|
208
209
|
if (linear) {
|
|
209
210
|
try {
|
|
210
211
|
source = mergeIssueMetadata(source, await linear.getIssue(issue.id));
|
|
211
212
|
}
|
|
212
213
|
catch {
|
|
213
|
-
//
|
|
214
|
+
// Preserve existing dependency rows when webhook relation data is incomplete.
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
218
|
+
if (source.relationsKnown) {
|
|
219
|
+
this.db.replaceIssueDependencies({
|
|
220
|
+
projectId,
|
|
221
|
+
linearIssueId: source.id,
|
|
222
|
+
blockers: source.blockedBy.map((blocker) => ({
|
|
223
|
+
blockerLinearIssueId: blocker.id,
|
|
224
|
+
...(blocker.identifier ? { blockerIssueKey: blocker.identifier } : {}),
|
|
225
|
+
...(blocker.title ? { blockerTitle: blocker.title } : {}),
|
|
226
|
+
...(blocker.stateName ? { blockerCurrentLinearState: blocker.stateName } : {}),
|
|
227
|
+
...(blocker.stateType ? { blockerCurrentLinearStateType: blocker.stateType } : {}),
|
|
228
|
+
})),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
227
231
|
return source;
|
|
228
232
|
}
|
|
229
233
|
reconcileDependentReadiness(projectId, blockerLinearIssueId) {
|
|
@@ -559,10 +563,12 @@ function mergeIssueMetadata(issue, liveIssue) {
|
|
|
559
563
|
...(issue.teamKey ? {} : liveIssue.teamKey ? { teamKey: liveIssue.teamKey } : {}),
|
|
560
564
|
...(issue.stateId ? {} : liveIssue.stateId ? { stateId: liveIssue.stateId } : {}),
|
|
561
565
|
...(issue.stateName ? {} : liveIssue.stateName ? { stateName: liveIssue.stateName } : {}),
|
|
566
|
+
...(issue.stateType ? {} : liveIssue.stateType ? { stateType: liveIssue.stateType } : {}),
|
|
562
567
|
...(issue.delegateId ? {} : liveIssue.delegateId ? { delegateId: liveIssue.delegateId } : {}),
|
|
563
568
|
...(issue.delegateName ? {} : liveIssue.delegateName ? { delegateName: liveIssue.delegateName } : {}),
|
|
569
|
+
relationsKnown: issue.relationsKnown || liveIssue.blockedBy !== undefined || liveIssue.blocks !== undefined,
|
|
564
570
|
labelNames: issue.labelNames.length > 0 ? issue.labelNames : (liveIssue.labels ?? []).map((l) => l.name),
|
|
565
|
-
blockedBy: issue.
|
|
566
|
-
blocks: issue.
|
|
571
|
+
blockedBy: issue.relationsKnown ? issue.blockedBy : (liveIssue.blockedBy ?? issue.blockedBy),
|
|
572
|
+
blocks: issue.relationsKnown ? issue.blocks : (liveIssue.blocks ?? issue.blocks),
|
|
567
573
|
};
|
|
568
574
|
}
|
package/dist/webhooks.js
CHANGED
|
@@ -227,6 +227,7 @@ function extractIssueMetadata(payload) {
|
|
|
227
227
|
...(delegateName ? { delegateName } : {}),
|
|
228
228
|
...(priority != null ? { priority } : {}),
|
|
229
229
|
...(estimate != null ? { estimate } : {}),
|
|
230
|
+
relationsKnown: false,
|
|
230
231
|
labelNames: extractLabelNames(issueRecord),
|
|
231
232
|
blockedBy: [],
|
|
232
233
|
blocks: [],
|