patchrelay 0.8.2 → 0.8.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
|
@@ -200,7 +200,7 @@ export class IssueWorkflowCoordinator {
|
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
202
|
const workspace = this.authoritativeLedger.getWorkspaceOwnership(stageRun.workspaceId);
|
|
203
|
-
if (workspace) {
|
|
203
|
+
if (workspace && workspace.currentRunLeaseId === params.stageRunId) {
|
|
204
204
|
this.authoritativeLedger.upsertWorkspaceOwnership({
|
|
205
205
|
projectId: stageRun.projectId,
|
|
206
206
|
linearIssueId: stageRun.linearIssueId,
|
|
@@ -8,7 +8,6 @@ import { resolveDefaultTransitionTarget, transitionTargetAllowed } from "./workf
|
|
|
8
8
|
import { buildFailedStageReport, buildPendingMaterializationThread, buildStageReport, countEventMethods, extractStageSummary, extractTurnId, resolveStageRunStatus, summarizeCurrentThread, } from "./stage-reporting.js";
|
|
9
9
|
import { StageLifecyclePublisher } from "./stage-lifecycle-publisher.js";
|
|
10
10
|
import { StageTurnInputDispatcher } from "./stage-turn-input-dispatcher.js";
|
|
11
|
-
const MAX_AUTOMATIC_TRANSITION_ATTEMPTS = 3;
|
|
12
11
|
export class ServiceStageFinalizer {
|
|
13
12
|
config;
|
|
14
13
|
stores;
|
|
@@ -153,6 +152,7 @@ export class ServiceStageFinalizer {
|
|
|
153
152
|
const report = buildStageReport(finalizedStageRun, issue, thread, countEventMethods(this.stores.stageEvents.listThreadEvents(stageRun.id)));
|
|
154
153
|
this.runAtomically(() => {
|
|
155
154
|
this.finishLedgerRun(stageRun.projectId, stageRun.linearIssueId, "completed", {
|
|
155
|
+
stageRunId: stageRun.id,
|
|
156
156
|
threadId: params.threadId,
|
|
157
157
|
...(params.turnId ? { turnId: params.turnId } : {}),
|
|
158
158
|
nextLifecycleStatus: params.nextLifecycleStatus ?? (issue.desiredStage ? "queued" : "completed"),
|
|
@@ -171,6 +171,7 @@ export class ServiceStageFinalizer {
|
|
|
171
171
|
failStageRun(stageRun, threadId, message, options) {
|
|
172
172
|
this.runAtomically(() => {
|
|
173
173
|
this.finishLedgerRun(stageRun.projectId, stageRun.linearIssueId, "failed", {
|
|
174
|
+
stageRunId: stageRun.id,
|
|
174
175
|
threadId,
|
|
175
176
|
...(options?.turnId ? { turnId: options.turnId } : {}),
|
|
176
177
|
failureReason: message,
|
|
@@ -315,9 +316,19 @@ export class ServiceStageFinalizer {
|
|
|
315
316
|
await this.routeStageToHumanNeeded(project, stageRun, linearIssue, `PatchRelay received ${nextTarget} as the next stage again and needs a human to confirm the intended loop.`);
|
|
316
317
|
return;
|
|
317
318
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
319
|
+
if (this.isTransitionAlreadyInFlight(stageRun, nextTarget)) {
|
|
320
|
+
this.feed?.publish({
|
|
321
|
+
level: "info",
|
|
322
|
+
kind: "workflow",
|
|
323
|
+
issueKey: refreshedIssue.issueKey,
|
|
324
|
+
projectId: stageRun.projectId,
|
|
325
|
+
stage: stageRun.stage,
|
|
326
|
+
...(refreshedIssue.selectedWorkflowId ? { workflowId: refreshedIssue.selectedWorkflowId } : {}),
|
|
327
|
+
nextStage: nextTarget,
|
|
328
|
+
status: "transition_in_progress",
|
|
329
|
+
summary: `${nextTarget} is already queued or running`,
|
|
330
|
+
detail: `PatchRelay kept ${stageRun.stage} completion from re-queueing ${nextTarget}.`,
|
|
331
|
+
});
|
|
321
332
|
return;
|
|
322
333
|
}
|
|
323
334
|
this.feed?.publish({
|
|
@@ -360,19 +371,16 @@ export class ServiceStageFinalizer {
|
|
|
360
371
|
}
|
|
361
372
|
return resolveDefaultTransitionTarget(project, stageRun.stage, workflowDefinitionId) ?? "human_needed";
|
|
362
373
|
}
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const next = stageHistory[index + 1];
|
|
371
|
-
if (current?.stage === currentStage && next?.stage === nextTarget) {
|
|
372
|
-
count += 1;
|
|
373
|
-
}
|
|
374
|
+
isTransitionAlreadyInFlight(stageRun, nextTarget) {
|
|
375
|
+
const refreshedIssue = this.stores.issueWorkflows.getTrackedIssue(stageRun.projectId, stageRun.linearIssueId);
|
|
376
|
+
if (!refreshedIssue) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
if (refreshedIssue.desiredStage === nextTarget) {
|
|
380
|
+
return true;
|
|
374
381
|
}
|
|
375
|
-
|
|
382
|
+
const activeStageRun = this.resolveActiveStageRun(refreshedIssue);
|
|
383
|
+
return activeStageRun !== undefined && activeStageRun.id !== stageRun.id && activeStageRun.stage === nextTarget;
|
|
376
384
|
}
|
|
377
385
|
async routeStageToHumanNeeded(project, stageRun, linearIssue, reason) {
|
|
378
386
|
const linear = await this.linearProvider.forProject(stageRun.projectId);
|
|
@@ -408,29 +416,41 @@ export class ServiceStageFinalizer {
|
|
|
408
416
|
}
|
|
409
417
|
finishLedgerRun(projectId, linearIssueId, status, params) {
|
|
410
418
|
const issueControl = this.stores.issueControl.getIssueControl(projectId, linearIssueId);
|
|
411
|
-
|
|
419
|
+
const targetRunLeaseId = params.stageRunId ?? issueControl?.activeRunLeaseId;
|
|
420
|
+
if (!targetRunLeaseId) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const targetRunLease = this.stores.runLeases.getRunLease(targetRunLeaseId);
|
|
424
|
+
if (!targetRunLease) {
|
|
412
425
|
return;
|
|
413
426
|
}
|
|
414
427
|
this.stores.runLeases.finishRunLease({
|
|
415
|
-
runLeaseId:
|
|
428
|
+
runLeaseId: targetRunLeaseId,
|
|
416
429
|
status,
|
|
417
430
|
...(params.threadId ? { threadId: params.threadId } : {}),
|
|
418
431
|
...(params.turnId ? { turnId: params.turnId } : {}),
|
|
419
432
|
...(params.failureReason ? { failureReason: params.failureReason } : {}),
|
|
420
433
|
});
|
|
421
|
-
if (
|
|
422
|
-
const workspace = this.stores.workspaceOwnership.getWorkspaceOwnership(
|
|
434
|
+
if (targetRunLease.workspaceOwnershipId !== undefined) {
|
|
435
|
+
const workspace = this.stores.workspaceOwnership.getWorkspaceOwnership(targetRunLease.workspaceOwnershipId);
|
|
423
436
|
if (workspace) {
|
|
424
437
|
this.stores.workspaceOwnership.upsertWorkspaceOwnership({
|
|
425
438
|
projectId,
|
|
426
439
|
linearIssueId,
|
|
427
440
|
branchName: workspace.branchName,
|
|
428
441
|
worktreePath: workspace.worktreePath,
|
|
429
|
-
status: status === "completed" ? "active" : "paused",
|
|
430
|
-
currentRunLeaseId
|
|
442
|
+
status: workspace.currentRunLeaseId === targetRunLeaseId ? (status === "completed" ? "active" : "paused") : workspace.status,
|
|
443
|
+
...(workspace.currentRunLeaseId === targetRunLeaseId
|
|
444
|
+
? { currentRunLeaseId: null }
|
|
445
|
+
: workspace.currentRunLeaseId !== undefined
|
|
446
|
+
? { currentRunLeaseId: workspace.currentRunLeaseId }
|
|
447
|
+
: {}),
|
|
431
448
|
});
|
|
432
449
|
}
|
|
433
450
|
}
|
|
451
|
+
if (!issueControl?.activeRunLeaseId || issueControl.activeRunLeaseId !== targetRunLeaseId) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
434
454
|
this.stores.issueControl.upsertIssueControl({
|
|
435
455
|
projectId,
|
|
436
456
|
linearIssueId,
|