@on-par/factory-core 0.9.28-next.1 → 0.9.28-next.11
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/blockers/declared-prerequisites.d.ts +4 -1
- package/dist/blockers/declared-prerequisites.d.ts.map +1 -1
- package/dist/blockers/declared-prerequisites.js +10 -5
- package/dist/blockers/declared-prerequisites.js.map +1 -1
- package/dist/config/example.d.ts.map +1 -1
- package/dist/config/example.js +6 -0
- package/dist/config/example.js.map +1 -1
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/runtime-config-keys.d.ts.map +1 -1
- package/dist/config/runtime-config-keys.js +1 -0
- package/dist/config/runtime-config-keys.js.map +1 -1
- package/dist/config/tracker-section.d.ts +39 -0
- package/dist/config/tracker-section.d.ts.map +1 -0
- package/dist/config/tracker-section.js +31 -0
- package/dist/config/tracker-section.js.map +1 -0
- package/dist/events/queue-traits.d.ts +1 -1
- package/dist/events/queue-traits.d.ts.map +1 -1
- package/dist/events/queue-traits.js +5 -1
- package/dist/events/queue-traits.js.map +1 -1
- package/dist/filing/redact.d.ts +1 -0
- package/dist/filing/redact.d.ts.map +1 -1
- package/dist/filing/redact.js +1 -1
- package/dist/filing/redact.js.map +1 -1
- package/dist/internal.d.ts +5 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -0
- package/dist/internal.js.map +1 -1
- package/dist/phases/ship-ci-watch.d.ts +25 -0
- package/dist/phases/ship-ci-watch.d.ts.map +1 -0
- package/dist/phases/ship-ci-watch.js +53 -0
- package/dist/phases/ship-ci-watch.js.map +1 -0
- package/dist/phases/ship-pr-lookup.d.ts +8 -0
- package/dist/phases/ship-pr-lookup.d.ts.map +1 -0
- package/dist/phases/ship-pr-lookup.js +41 -0
- package/dist/phases/ship-pr-lookup.js.map +1 -0
- package/dist/phases/ship-recovery.d.ts +16 -0
- package/dist/phases/ship-recovery.d.ts.map +1 -0
- package/dist/phases/ship-recovery.js +81 -0
- package/dist/phases/ship-recovery.js.map +1 -0
- package/dist/phases/ship-types.d.ts +36 -0
- package/dist/phases/ship-types.d.ts.map +1 -0
- package/dist/phases/ship-types.js +2 -0
- package/dist/phases/ship-types.js.map +1 -0
- package/dist/phases/ship.d.ts +6 -41
- package/dist/phases/ship.d.ts.map +1 -1
- package/dist/phases/ship.js +33 -171
- package/dist/phases/ship.js.map +1 -1
- package/dist/queue/comment-rework-trigger.d.ts +24 -0
- package/dist/queue/comment-rework-trigger.d.ts.map +1 -0
- package/dist/queue/comment-rework-trigger.js +128 -0
- package/dist/queue/comment-rework-trigger.js.map +1 -0
- package/dist/queue/internal-exports.d.ts +2 -0
- package/dist/queue/internal-exports.d.ts.map +1 -1
- package/dist/queue/internal-exports.js +1 -0
- package/dist/queue/internal-exports.js.map +1 -1
- package/dist/queue/linear-queue-lifecycle.d.ts +62 -0
- package/dist/queue/linear-queue-lifecycle.d.ts.map +1 -0
- package/dist/queue/linear-queue-lifecycle.js +139 -0
- package/dist/queue/linear-queue-lifecycle.js.map +1 -0
- package/dist/queue/linear-queue.d.ts +49 -0
- package/dist/queue/linear-queue.d.ts.map +1 -0
- package/dist/queue/linear-queue.js +258 -0
- package/dist/queue/linear-queue.js.map +1 -0
- package/dist/queue/queue-backend.d.ts +25 -6
- package/dist/queue/queue-backend.d.ts.map +1 -1
- package/dist/queue/queue-backend.js +35 -6
- package/dist/queue/queue-backend.js.map +1 -1
- package/dist/queue/review-rework-trigger.d.ts +7 -2
- package/dist/queue/review-rework-trigger.d.ts.map +1 -1
- package/dist/queue/review-rework-trigger.js +12 -8
- package/dist/queue/review-rework-trigger.js.map +1 -1
- package/dist/run/pr-run-state.d.ts +99 -0
- package/dist/run/pr-run-state.d.ts.map +1 -0
- package/dist/run/pr-run-state.js +235 -0
- package/dist/run/pr-run-state.js.map +1 -0
- package/dist/run/review-rework-cap.d.ts +3 -1
- package/dist/run/review-rework-cap.d.ts.map +1 -1
- package/dist/run/review-rework-cap.js +2 -1
- package/dist/run/review-rework-cap.js.map +1 -1
- package/dist/run/review-rework.d.ts +10 -0
- package/dist/run/review-rework.d.ts.map +1 -1
- package/dist/run/review-rework.js +45 -15
- package/dist/run/review-rework.js.map +1 -1
- package/dist/run/state.d.ts +9 -5
- package/dist/run/state.d.ts.map +1 -1
- package/dist/run/state.js +37 -13
- package/dist/run/state.js.map +1 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/work/index.d.ts +2 -2
- package/dist/work/index.d.ts.map +1 -1
- package/dist/work/index.js +4 -2
- package/dist/work/index.js.map +1 -1
- package/dist/work/linear-client.d.ts +21 -0
- package/dist/work/linear-client.d.ts.map +1 -0
- package/dist/work/linear-client.js +69 -0
- package/dist/work/linear-client.js.map +1 -0
- package/dist/work/linear-issue.d.ts +11 -0
- package/dist/work/linear-issue.d.ts.map +1 -0
- package/dist/work/linear-issue.js +69 -0
- package/dist/work/linear-issue.js.map +1 -0
- package/dist/work/linear-preflight.d.ts +21 -0
- package/dist/work/linear-preflight.d.ts.map +1 -0
- package/dist/work/linear-preflight.js +67 -0
- package/dist/work/linear-preflight.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// packages/core/src/queue/linear-queue-lifecycle.ts — Linear queue release, park, lease heartbeat and reap (ADR-0173, #3893).
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { claimedByLabel, DEFAULT_CLAIM_LEASE_MS, defaultClaimantId, PARKED_LABEL, } from './github-queue.js';
|
|
4
|
+
import { toWorkKey } from '../work/work-key.js';
|
|
5
|
+
export const LINEAR_LEASE_KIND = 'factory-claim-lease';
|
|
6
|
+
const LeaseSchema = z.object({
|
|
7
|
+
kind: z.literal(LINEAR_LEASE_KIND),
|
|
8
|
+
claimantId: z.string().min(1),
|
|
9
|
+
expiresAt: z.number(),
|
|
10
|
+
});
|
|
11
|
+
export function parseLinearClaimLease(metadata) {
|
|
12
|
+
const parsed = LeaseSchema.safeParse(metadata);
|
|
13
|
+
return parsed.success ? parsed.data : null;
|
|
14
|
+
}
|
|
15
|
+
function messageOf(err) {
|
|
16
|
+
return err instanceof Error ? err.message : String(err);
|
|
17
|
+
}
|
|
18
|
+
export function createLinearQueueLifecycle(options) {
|
|
19
|
+
const { client, linear, warn } = options;
|
|
20
|
+
const claimantId = options.claimantId ?? defaultClaimantId();
|
|
21
|
+
const leaseMs = options.leaseMs ?? DEFAULT_CLAIM_LEASE_MS;
|
|
22
|
+
const now = options.now ?? Date.now;
|
|
23
|
+
const me = claimedByLabel(claimantId);
|
|
24
|
+
let lastError;
|
|
25
|
+
async function attempt(op, identifier, fn) {
|
|
26
|
+
try {
|
|
27
|
+
await fn();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
lastError = messageOf(err);
|
|
32
|
+
warn(`linear queue: ${op} on ${identifier} failed: ${lastError}`);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function freeClaim(issue, claimLabel, leaseAttachmentId) {
|
|
37
|
+
let ok = true;
|
|
38
|
+
const label = issue.labels.find((l) => l.name === claimLabel);
|
|
39
|
+
if (label)
|
|
40
|
+
ok = (await attempt('claim label removal', issue.identifier, () => client.removeLabel(issue.id, label.id))) && ok;
|
|
41
|
+
if (leaseAttachmentId !== undefined) {
|
|
42
|
+
ok = (await attempt('lease removal', issue.identifier, () => client.deleteAttachment(leaseAttachmentId))) && ok;
|
|
43
|
+
}
|
|
44
|
+
return ok;
|
|
45
|
+
}
|
|
46
|
+
async function release(key, outcome = 'queued', reason) {
|
|
47
|
+
let issue;
|
|
48
|
+
try {
|
|
49
|
+
issue = await client.findIssue(key);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
warn(`linear queue: release of ${key}: lookup failed: ${messageOf(err)}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!issue) {
|
|
56
|
+
warn(`linear queue: release of ${key}: issue not found`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const target = issue;
|
|
60
|
+
const ownLease = parseLinearClaimLease(target.lease?.metadata)?.claimantId === claimantId;
|
|
61
|
+
const hasLabel = target.labels.some((l) => l.name === me);
|
|
62
|
+
if (!ownLease && !hasLabel)
|
|
63
|
+
return;
|
|
64
|
+
await freeClaim(target, me, ownLease ? target.lease?.attachmentId : undefined);
|
|
65
|
+
switch (outcome) {
|
|
66
|
+
case 'queued':
|
|
67
|
+
await attempt('move to ready', key, () => client.moveToState(target.id, linear.states.ready));
|
|
68
|
+
break;
|
|
69
|
+
case 'parked': {
|
|
70
|
+
await attempt('parked label', key, async () => {
|
|
71
|
+
const labelId = await client.ensureLabel(PARKED_LABEL);
|
|
72
|
+
await client.addLabel(target.id, labelId);
|
|
73
|
+
});
|
|
74
|
+
const body = reason?.trim() ? `Parked by the factory: ${reason}` : 'Parked by the factory (no reason given).';
|
|
75
|
+
await attempt('park comment', key, () => client.addComment(target.id, body));
|
|
76
|
+
await attempt('move to parked', key, () => client.moveToState(target.id, linear.states.parked));
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case 'done':
|
|
80
|
+
break;
|
|
81
|
+
default: {
|
|
82
|
+
const _never = outcome;
|
|
83
|
+
return _never;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function heartbeat(key) {
|
|
88
|
+
let issue;
|
|
89
|
+
try {
|
|
90
|
+
issue = await client.findIssue(key);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
warn(`linear queue: heartbeat of ${key}: lookup failed: ${messageOf(err)}`);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (!issue || !issue.labels.some((l) => l.name === me))
|
|
97
|
+
return false;
|
|
98
|
+
const target = issue;
|
|
99
|
+
await attempt('lease renew', key, () => client.upsertLeaseAttachment(target.id, { kind: LINEAR_LEASE_KIND, claimantId, expiresAt: now() + leaseMs }));
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
async function reap() {
|
|
103
|
+
let issues;
|
|
104
|
+
try {
|
|
105
|
+
issues = await client.listLeasedIssues();
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
warn(`linear queue: reap listing failed: ${messageOf(err)}`);
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
const rows = [];
|
|
112
|
+
for (const issue of issues) {
|
|
113
|
+
if (!issue.lease)
|
|
114
|
+
continue;
|
|
115
|
+
const lease = parseLinearClaimLease(issue.lease.metadata);
|
|
116
|
+
if (!lease) {
|
|
117
|
+
warn(`linear queue: reap of ${issue.identifier}: malformed lease attachment`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (lease.expiresAt > now())
|
|
121
|
+
continue;
|
|
122
|
+
lastError = undefined;
|
|
123
|
+
const freed = await freeClaim(issue, claimedByLabel(lease.claimantId), issue.lease.attachmentId);
|
|
124
|
+
const moved = await attempt('move to ready', issue.identifier, () => client.moveToState(issue.id, linear.states.ready));
|
|
125
|
+
const ok = freed && moved;
|
|
126
|
+
rows.push({
|
|
127
|
+
key: toWorkKey(issue.identifier),
|
|
128
|
+
claimantId: lease.claimantId,
|
|
129
|
+
expiresAt: lease.expiresAt,
|
|
130
|
+
released: ok,
|
|
131
|
+
outcome: ok ? 'released' : 'failed',
|
|
132
|
+
...(ok ? {} : { detail: lastError }),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return rows;
|
|
136
|
+
}
|
|
137
|
+
return { release, heartbeat, reap };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=linear-queue-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-queue-lifecycle.js","sourceRoot":"","sources":["../../src/queue/linear-queue-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { LinearTrackerConfig } from '../config/tracker-section.js';
|
|
2
|
+
import type { QueueBackend } from './queue-backend.js';
|
|
3
|
+
export interface LinearQueueLabel {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
/** Parent label (group) name. */
|
|
7
|
+
group?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LinearQueueIssue {
|
|
10
|
+
id: string;
|
|
11
|
+
identifier: string;
|
|
12
|
+
priority: number;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
stateType: string;
|
|
15
|
+
labels: LinearQueueLabel[];
|
|
16
|
+
}
|
|
17
|
+
export interface LinearQueueClient {
|
|
18
|
+
/** Issues in the mapped project, in the ready state, carrying the ready label. Rejects on any API error. */
|
|
19
|
+
listCandidates(): Promise<LinearQueueIssue[]>;
|
|
20
|
+
/** Fresh label names on one issue. */
|
|
21
|
+
issueLabels(issueId: string): Promise<string[]>;
|
|
22
|
+
/** Id of the team label `name`, creating it when missing. */
|
|
23
|
+
ensureLabel(name: string): Promise<string>;
|
|
24
|
+
addLabel(issueId: string, labelId: string): Promise<void>;
|
|
25
|
+
removeLabel(issueId: string, labelId: string): Promise<void>;
|
|
26
|
+
/** Moves the issue to the team workflow state named `stateName`. */
|
|
27
|
+
moveToState(issueId: string, stateName: string): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export type LinearQueue = Pick<QueueBackend, 'list' | 'claimNext'>;
|
|
30
|
+
export interface LinearQueueOptions {
|
|
31
|
+
client: LinearQueueClient;
|
|
32
|
+
linear: LinearTrackerConfig;
|
|
33
|
+
claimantId?: string;
|
|
34
|
+
defaultLane?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const LINEAR_DEFAULT_LANE = "default";
|
|
37
|
+
export declare function isLinearCandidate(issue: LinearQueueIssue, readyLabel: string): boolean;
|
|
38
|
+
export declare function linearLaneOf(issue: LinearQueueIssue, laneLabelGroup: string, defaultLane?: string): string;
|
|
39
|
+
export declare function compareLinearCandidates(a: LinearQueueIssue, b: LinearQueueIssue): number;
|
|
40
|
+
export declare function createLinearQueue(options: LinearQueueOptions): LinearQueue;
|
|
41
|
+
export declare function createLinearQueueGraphqlClient(opts: {
|
|
42
|
+
apiKey: string;
|
|
43
|
+
linear: LinearTrackerConfig;
|
|
44
|
+
project: string;
|
|
45
|
+
fetch?: typeof globalThis.fetch;
|
|
46
|
+
endpoint?: string;
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
}): LinearQueueClient;
|
|
49
|
+
//# sourceMappingURL=linear-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-queue.d.ts","sourceRoot":"","sources":["../../src/queue/linear-queue.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAG1E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AACD,MAAM,WAAW,iBAAiB;IAChC,4GAA4G;IAC5G,cAAc,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC9C,sCAAsC;IACtC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,6DAA6D;IAC7D,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,oEAAoE;IACpE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AACD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC;AACnE,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAK7C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAQtF;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,gBAAgB,EACvB,cAAc,EAAE,MAAM,EACtB,WAAW,GAAE,MAA4B,GACxC,MAAM,CAER;AAaD,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAYxF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAsC1E;AA+DD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,iBAAiB,CAqHpB"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// packages/core/src/queue/linear-queue.ts — Linear-backed queue seam: list and claimNext (ADR-0173, #3892).
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { LinearApiError } from '../work/linear-client.js';
|
|
4
|
+
import { claimedByLabel, CLAIMED_BY_LABEL_PREFIX, defaultClaimantId, PARKED_LABEL } from './github-queue.js';
|
|
5
|
+
import { QUEUE_ORDER_LABEL_PREFIX } from './queue-order.js';
|
|
6
|
+
import { toWorkKey } from '../work/work-key.js';
|
|
7
|
+
export const LINEAR_DEFAULT_LANE = 'default';
|
|
8
|
+
const EXCLUDED_STATE_TYPES = new Set(['started', 'completed', 'canceled']);
|
|
9
|
+
const ORDER_PATTERN = new RegExp(`^${QUEUE_ORDER_LABEL_PREFIX}(\\d+)$`);
|
|
10
|
+
export function isLinearCandidate(issue, readyLabel) {
|
|
11
|
+
if (EXCLUDED_STATE_TYPES.has(issue.stateType))
|
|
12
|
+
return false;
|
|
13
|
+
const names = issue.labels.map((l) => l.name);
|
|
14
|
+
return (names.some((n) => n === readyLabel) &&
|
|
15
|
+
!names.some((n) => n.startsWith(CLAIMED_BY_LABEL_PREFIX)) &&
|
|
16
|
+
!names.includes(PARKED_LABEL));
|
|
17
|
+
}
|
|
18
|
+
export function linearLaneOf(issue, laneLabelGroup, defaultLane = LINEAR_DEFAULT_LANE) {
|
|
19
|
+
return issue.labels.find((l) => l.group === laneLabelGroup)?.name ?? defaultLane;
|
|
20
|
+
}
|
|
21
|
+
function priorityRank(p) {
|
|
22
|
+
return p >= 1 && p <= 4 ? p : 5;
|
|
23
|
+
}
|
|
24
|
+
function orderOf(issue) {
|
|
25
|
+
const matches = issue.labels.map((l) => ORDER_PATTERN.exec(l.name)).filter((m) => m !== null);
|
|
26
|
+
if (matches.length !== 1)
|
|
27
|
+
return Number.POSITIVE_INFINITY;
|
|
28
|
+
const n = Number(matches[0]?.[1]);
|
|
29
|
+
return Number.isSafeInteger(n) && n > 0 ? n : Number.POSITIVE_INFINITY;
|
|
30
|
+
}
|
|
31
|
+
export function compareLinearCandidates(a, b) {
|
|
32
|
+
const pa = priorityRank(a.priority);
|
|
33
|
+
const pb = priorityRank(b.priority);
|
|
34
|
+
if (pa !== pb)
|
|
35
|
+
return pa - pb;
|
|
36
|
+
const oa = orderOf(a);
|
|
37
|
+
const ob = orderOf(b);
|
|
38
|
+
if (oa < ob)
|
|
39
|
+
return -1;
|
|
40
|
+
if (oa > ob)
|
|
41
|
+
return 1;
|
|
42
|
+
const ca = Date.parse(a.createdAt);
|
|
43
|
+
const cb = Date.parse(b.createdAt);
|
|
44
|
+
if (ca !== cb)
|
|
45
|
+
return ca - cb;
|
|
46
|
+
return a.identifier.localeCompare(b.identifier);
|
|
47
|
+
}
|
|
48
|
+
export function createLinearQueue(options) {
|
|
49
|
+
const { client, linear } = options;
|
|
50
|
+
const defaultLane = options.defaultLane ?? LINEAR_DEFAULT_LANE;
|
|
51
|
+
const claimantId = options.claimantId ?? defaultClaimantId();
|
|
52
|
+
const myLabel = claimedByLabel(claimantId);
|
|
53
|
+
let myLabelId;
|
|
54
|
+
async function sortedFor(lane) {
|
|
55
|
+
const issues = await client.listCandidates();
|
|
56
|
+
const laneOf = (i) => linearLaneOf(i, linear.laneLabelGroup, defaultLane);
|
|
57
|
+
const eligible = issues.filter((i) => isLinearCandidate(i, linear.readyLabel) && (lane === undefined || laneOf(i) === lane));
|
|
58
|
+
if (lane !== undefined)
|
|
59
|
+
return eligible.sort(compareLinearCandidates);
|
|
60
|
+
return eligible.sort((a, b) => laneOf(a).localeCompare(laneOf(b)) || compareLinearCandidates(a, b));
|
|
61
|
+
}
|
|
62
|
+
async function list(lane) {
|
|
63
|
+
return (await sortedFor(lane)).map((i) => toWorkKey(i.identifier));
|
|
64
|
+
}
|
|
65
|
+
async function claimNext(lane) {
|
|
66
|
+
const candidates = await sortedFor(lane);
|
|
67
|
+
if (candidates.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
myLabelId ??= await client.ensureLabel(myLabel);
|
|
70
|
+
for (const c of candidates) {
|
|
71
|
+
await client.addLabel(c.id, myLabelId);
|
|
72
|
+
await client.moveToState(c.id, linear.states.inProgress);
|
|
73
|
+
const after = await client.issueLabels(c.id);
|
|
74
|
+
const winner = after.filter((n) => n.startsWith(CLAIMED_BY_LABEL_PREFIX)).sort()[0];
|
|
75
|
+
if (winner === myLabel)
|
|
76
|
+
return { key: toWorkKey(c.identifier), decision: { kind: 'build' } };
|
|
77
|
+
// The winner owns In Progress, so the state is left alone.
|
|
78
|
+
if (after.includes(myLabel))
|
|
79
|
+
await client.removeLabel(c.id, myLabelId);
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return { list, claimNext };
|
|
84
|
+
}
|
|
85
|
+
const MAX_PAGES = 10;
|
|
86
|
+
const ENVELOPE = z.object({
|
|
87
|
+
data: z.unknown().nullish(),
|
|
88
|
+
errors: z.array(z.object({ message: z.string() })).optional(),
|
|
89
|
+
});
|
|
90
|
+
const CANDIDATES_QUERY = `query($after: String, $team: String!, $project: String!, $ready: String!, $label: String!) {
|
|
91
|
+
issues(first: 100, after: $after, filter: { team: { key: { eq: $team } }, project: { or: [{ name: { eq: $project } }, { id: { eq: $project } }] }, state: { name: { eq: $ready } }, labels: { some: { name: { eq: $label } } } }) {
|
|
92
|
+
nodes { id identifier priority createdAt state { type } labels { nodes { id name parent { name } } } }
|
|
93
|
+
pageInfo { hasNextPage endCursor }
|
|
94
|
+
}
|
|
95
|
+
}`;
|
|
96
|
+
const TEAM_QUERY = `query($team: String!) { teams(filter: { key: { eq: $team } }) { nodes { id states { nodes { id name } } } } }`;
|
|
97
|
+
const FIND_LABEL_QUERY = `query($name: String!, $teamId: ID!) { issueLabels(filter: { name: { eq: $name }, team: { id: { eq: $teamId } } }) { nodes { id } } }`;
|
|
98
|
+
const CREATE_LABEL_MUTATION = `mutation($name: String!, $teamId: String!) { issueLabelCreate(input: { name: $name, teamId: $teamId }) { success issueLabel { id } } }`;
|
|
99
|
+
const ADD_LABEL_MUTATION = `mutation($id: String!, $labelId: String!) { issueAddLabel(id: $id, labelId: $labelId) { success } }`;
|
|
100
|
+
const REMOVE_LABEL_MUTATION = `mutation($id: String!, $labelId: String!) { issueRemoveLabel(id: $id, labelId: $labelId) { success } }`;
|
|
101
|
+
const UPDATE_STATE_MUTATION = `mutation($id: String!, $stateId: String!) { issueUpdate(id: $id, input: { stateId: $stateId }) { success } }`;
|
|
102
|
+
const ISSUE_LABELS_QUERY = `query($id: String!) { issue(id: $id) { labels { nodes { name } } } }`;
|
|
103
|
+
const CandidatesSchema = z.object({
|
|
104
|
+
issues: z.object({
|
|
105
|
+
nodes: z.array(z.object({
|
|
106
|
+
id: z.string(),
|
|
107
|
+
identifier: z.string(),
|
|
108
|
+
priority: z.number(),
|
|
109
|
+
createdAt: z.string(),
|
|
110
|
+
state: z.object({ type: z.string() }),
|
|
111
|
+
labels: z.object({
|
|
112
|
+
nodes: z.array(z.object({ id: z.string(), name: z.string(), parent: z.object({ name: z.string() }).nullish() })),
|
|
113
|
+
}),
|
|
114
|
+
})),
|
|
115
|
+
pageInfo: z.object({ hasNextPage: z.boolean(), endCursor: z.string().nullish() }),
|
|
116
|
+
}),
|
|
117
|
+
});
|
|
118
|
+
const TeamSchema = z.object({
|
|
119
|
+
teams: z.object({
|
|
120
|
+
nodes: z.array(z.object({
|
|
121
|
+
id: z.string(),
|
|
122
|
+
states: z.object({ nodes: z.array(z.object({ id: z.string(), name: z.string() })) }),
|
|
123
|
+
})),
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
const FindLabelSchema = z.object({ issueLabels: z.object({ nodes: z.array(z.object({ id: z.string() })) }) });
|
|
127
|
+
const CreateLabelSchema = z.object({
|
|
128
|
+
issueLabelCreate: z.object({ success: z.boolean(), issueLabel: z.object({ id: z.string() }).nullish() }),
|
|
129
|
+
});
|
|
130
|
+
const AddLabelSchema = z.object({ issueAddLabel: z.object({ success: z.boolean() }) });
|
|
131
|
+
const RemoveLabelSchema = z.object({ issueRemoveLabel: z.object({ success: z.boolean() }) });
|
|
132
|
+
const UpdateSchema = z.object({ issueUpdate: z.object({ success: z.boolean() }) });
|
|
133
|
+
const IssueLabelsSchema = z.object({
|
|
134
|
+
issue: z.object({ labels: z.object({ nodes: z.array(z.object({ name: z.string() })) }) }).nullable(),
|
|
135
|
+
});
|
|
136
|
+
export function createLinearQueueGraphqlClient(opts) {
|
|
137
|
+
const { apiKey, linear, project } = opts;
|
|
138
|
+
const fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
139
|
+
const endpoint = opts.endpoint ?? 'https://api.linear.app/graphql';
|
|
140
|
+
const redact = (text) => text.split(apiKey).join('***');
|
|
141
|
+
async function request(query, variables, schema) {
|
|
142
|
+
let res;
|
|
143
|
+
let json;
|
|
144
|
+
try {
|
|
145
|
+
res = await fetchImpl(endpoint, {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: { 'Content-Type': 'application/json', Authorization: apiKey },
|
|
148
|
+
body: JSON.stringify({ query, variables }),
|
|
149
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 30_000),
|
|
150
|
+
});
|
|
151
|
+
if (!res.ok)
|
|
152
|
+
throw new LinearApiError(`Linear API returned HTTP ${res.status}`);
|
|
153
|
+
json = await res.json();
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (err instanceof LinearApiError)
|
|
157
|
+
throw err;
|
|
158
|
+
throw new LinearApiError(redact(err instanceof Error ? err.message : String(err)));
|
|
159
|
+
}
|
|
160
|
+
const envelope = ENVELOPE.safeParse(json);
|
|
161
|
+
if (!envelope.success)
|
|
162
|
+
throw malformed(envelope.error);
|
|
163
|
+
const { data, errors } = envelope.data;
|
|
164
|
+
if (errors && errors.length > 0) {
|
|
165
|
+
throw new LinearApiError(redact(`Linear API error: ${errors.map((e) => e.message).join('; ')}`));
|
|
166
|
+
}
|
|
167
|
+
if (data == null)
|
|
168
|
+
throw new LinearApiError('Linear API returned no data');
|
|
169
|
+
const parsed = schema.safeParse(data);
|
|
170
|
+
if (!parsed.success)
|
|
171
|
+
throw malformed(parsed.error);
|
|
172
|
+
return parsed.data;
|
|
173
|
+
}
|
|
174
|
+
function malformed(error) {
|
|
175
|
+
const first = error.issues[0];
|
|
176
|
+
const where = first ? `${first.path.join('.')}: ${first.message}` : 'unknown';
|
|
177
|
+
return new LinearApiError(redact(`malformed Linear response: ${where}`));
|
|
178
|
+
}
|
|
179
|
+
let team;
|
|
180
|
+
function teamInfo() {
|
|
181
|
+
team ??= request(TEAM_QUERY, { team: linear.teamKey }, TeamSchema).then((d) => {
|
|
182
|
+
const found = d.teams.nodes[0];
|
|
183
|
+
if (!found)
|
|
184
|
+
throw new LinearApiError(`Linear team ${linear.teamKey} not found`);
|
|
185
|
+
return found;
|
|
186
|
+
});
|
|
187
|
+
team.catch(() => {
|
|
188
|
+
team = undefined;
|
|
189
|
+
});
|
|
190
|
+
return team;
|
|
191
|
+
}
|
|
192
|
+
function ensureSuccess(ok, what) {
|
|
193
|
+
if (!ok)
|
|
194
|
+
throw new LinearApiError(`Linear ${what} reported success=false`);
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
async listCandidates() {
|
|
198
|
+
const out = [];
|
|
199
|
+
let after = null;
|
|
200
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
201
|
+
const { issues } = await request(CANDIDATES_QUERY, { after, team: linear.teamKey, project, ready: linear.states.ready, label: linear.readyLabel }, CandidatesSchema);
|
|
202
|
+
for (const n of issues.nodes) {
|
|
203
|
+
out.push({
|
|
204
|
+
id: n.id,
|
|
205
|
+
identifier: n.identifier,
|
|
206
|
+
priority: n.priority,
|
|
207
|
+
createdAt: n.createdAt,
|
|
208
|
+
stateType: n.state.type,
|
|
209
|
+
labels: n.labels.nodes.map((l) => ({
|
|
210
|
+
id: l.id,
|
|
211
|
+
name: l.name,
|
|
212
|
+
...(l.parent ? { group: l.parent.name } : {}),
|
|
213
|
+
})),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if (!issues.pageInfo.hasNextPage)
|
|
217
|
+
return out;
|
|
218
|
+
after = issues.pageInfo.endCursor ?? null;
|
|
219
|
+
}
|
|
220
|
+
throw new LinearApiError('Linear ready queue exceeds 1000 issues');
|
|
221
|
+
},
|
|
222
|
+
async issueLabels(issueId) {
|
|
223
|
+
const d = await request(ISSUE_LABELS_QUERY, { id: issueId }, IssueLabelsSchema);
|
|
224
|
+
if (d.issue === null)
|
|
225
|
+
throw new LinearApiError(`Linear issue ${issueId} not found`);
|
|
226
|
+
return d.issue.labels.nodes.map((l) => l.name);
|
|
227
|
+
},
|
|
228
|
+
async ensureLabel(name) {
|
|
229
|
+
const { id: teamId } = await teamInfo();
|
|
230
|
+
const found = await request(FIND_LABEL_QUERY, { name, teamId }, FindLabelSchema);
|
|
231
|
+
const existing = found.issueLabels.nodes[0];
|
|
232
|
+
if (existing)
|
|
233
|
+
return existing.id;
|
|
234
|
+
const created = (await request(CREATE_LABEL_MUTATION, { name, teamId }, CreateLabelSchema)).issueLabelCreate;
|
|
235
|
+
ensureSuccess(created.success, 'label create');
|
|
236
|
+
if (!created.issueLabel)
|
|
237
|
+
throw new LinearApiError('Linear label create returned no label');
|
|
238
|
+
return created.issueLabel.id;
|
|
239
|
+
},
|
|
240
|
+
async addLabel(issueId, labelId) {
|
|
241
|
+
const d = await request(ADD_LABEL_MUTATION, { id: issueId, labelId }, AddLabelSchema);
|
|
242
|
+
ensureSuccess(d.issueAddLabel.success, 'label add');
|
|
243
|
+
},
|
|
244
|
+
async removeLabel(issueId, labelId) {
|
|
245
|
+
const d = await request(REMOVE_LABEL_MUTATION, { id: issueId, labelId }, RemoveLabelSchema);
|
|
246
|
+
ensureSuccess(d.issueRemoveLabel.success, 'label remove');
|
|
247
|
+
},
|
|
248
|
+
async moveToState(issueId, stateName) {
|
|
249
|
+
const info = await teamInfo();
|
|
250
|
+
const state = info.states.nodes.find((s) => s.name === stateName);
|
|
251
|
+
if (!state)
|
|
252
|
+
throw new LinearApiError(`Linear state "${stateName}" not found in team ${linear.teamKey}`);
|
|
253
|
+
const d = await request(UPDATE_STATE_MUTATION, { id: issueId, stateId: state.id }, UpdateSchema);
|
|
254
|
+
ensureSuccess(d.issueUpdate.success, 'state update');
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=linear-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-queue.js","sourceRoot":"","sources":["../../src/queue/linear-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { type BlockedParkPollResult, type BlockedParkStore } from '../blockers/poller.js';
|
|
2
2
|
import { type GithubQueueOptions, type QueueClaim, type QueueReleaseOutcome } from './github-queue.js';
|
|
3
|
+
import { type WorkKey } from '../work/work-key.js';
|
|
3
4
|
import { type StaleClaimRelease } from './stale-claims.js';
|
|
5
|
+
export interface QueueBackendClaim {
|
|
6
|
+
key: WorkKey;
|
|
7
|
+
decision: QueueClaim['decision'];
|
|
8
|
+
}
|
|
4
9
|
export interface QueueBackend {
|
|
5
|
-
/** Claims and returns the next eligible
|
|
6
|
-
claimNext(lane: string): Promise<
|
|
7
|
-
/** Releases a previously claimed
|
|
8
|
-
release(
|
|
9
|
-
/**
|
|
10
|
-
|
|
10
|
+
/** Claims and returns the next eligible work item in `lane`, or null when none is eligible. */
|
|
11
|
+
claimNext(lane: string): Promise<QueueBackendClaim | null>;
|
|
12
|
+
/** Releases a previously claimed work item back to the queue with the given outcome (default 'queued'). */
|
|
13
|
+
release(key: WorkKey, outcome?: QueueReleaseOutcome): Promise<void>;
|
|
14
|
+
/** Refreshes this claimant's lease; false when the claim is gone (GithubQueue.heartbeat semantics). */
|
|
15
|
+
heartbeat(key: WorkKey): Promise<boolean>;
|
|
16
|
+
/** Queued work keys for one lane, in claim order; every lane, lane-sorted, when `lane` is omitted. */
|
|
17
|
+
list(lane?: string): Promise<WorkKey[]>;
|
|
18
|
+
/** Lane names that currently have queued work. */
|
|
19
|
+
lanes(): Promise<string[]>;
|
|
11
20
|
/** Detects and releases claims whose TTL lease has expired across the whole queue. */
|
|
12
21
|
reap(): Promise<StaleClaimRelease[]>;
|
|
13
22
|
/** Unparks `blocked` parents whose blockers resolved (#2318); [] when no blockedParks store was configured. */
|
|
@@ -17,4 +26,14 @@ export type GithubQueueBackendOptions = GithubQueueOptions & {
|
|
|
17
26
|
blockedParks?: BlockedParkStore;
|
|
18
27
|
};
|
|
19
28
|
export declare function createGithubQueueBackend(options: GithubQueueBackendOptions): QueueBackend;
|
|
29
|
+
export type QueueBackendKind = 'github';
|
|
30
|
+
export interface QueueBackendOptions {
|
|
31
|
+
kind: QueueBackendKind;
|
|
32
|
+
github: GithubQueueBackendOptions;
|
|
33
|
+
}
|
|
34
|
+
export declare class UnsupportedQueueBackendError extends Error {
|
|
35
|
+
readonly kind: string;
|
|
36
|
+
constructor(kind: string);
|
|
37
|
+
}
|
|
38
|
+
export declare function createQueueBackend(options: QueueBackendOptions): QueueBackend;
|
|
20
39
|
//# sourceMappingURL=queue-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue-backend.d.ts","sourceRoot":"","sources":["../../src/queue/queue-backend.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B
|
|
1
|
+
{"version":3,"file":"queue-backend.d.ts","sourceRoot":"","sources":["../../src/queue/queue-backend.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,+FAA+F;IAC/F,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC3D,2GAA2G;IAC3G,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,uGAAuG;IACvG,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,sGAAsG;IACtG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxC,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3B,sFAAsF;IACtF,IAAI,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACrC,+GAA+G;IAC/G,gBAAgB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,GAAG;IAAE,YAAY,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEjG,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAoCzF;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAExC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,yBAAyB,CAAC;CACnC;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YAAY,IAAI,EAAE,MAAM,EAIvB;CACF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAO7E"}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
// packages/core/src/queue/queue-backend.ts — Backend-agnostic queue seam; GitHub-labels is today's only implementation (#1499).
|
|
1
|
+
// packages/core/src/queue/queue-backend.ts — Backend-agnostic queue seam speaking WorkKey; GitHub-labels is today's only implementation (#1499, #3890).
|
|
2
2
|
import { pollBlockedParks } from '../blockers/poller.js';
|
|
3
3
|
import { createGithubQueue, } from './github-queue.js';
|
|
4
|
+
import { issueNumberOf, workKeyFromIssue } from '../work/work-key.js';
|
|
4
5
|
import { releaseStaleClaims } from './stale-claims.js';
|
|
5
6
|
export function createGithubQueueBackend(options) {
|
|
6
7
|
const { client, owner, repo, now } = options;
|
|
7
8
|
const queue = createGithubQueue(options);
|
|
9
|
+
async function claimNext(lane) {
|
|
10
|
+
const claim = await queue.claimNext(lane);
|
|
11
|
+
return claim === null ? null : { key: workKeyFromIssue(claim.issue), decision: claim.decision };
|
|
12
|
+
}
|
|
8
13
|
async function list(lane) {
|
|
9
14
|
if (lane !== undefined)
|
|
10
|
-
return queue.list(lane);
|
|
11
|
-
const
|
|
15
|
+
return (await queue.list(lane)).map(workKeyFromIssue);
|
|
16
|
+
const keys = [];
|
|
12
17
|
for (const l of await queue.lanes()) {
|
|
13
|
-
|
|
18
|
+
keys.push(...(await queue.list(l)).map(workKeyFromIssue));
|
|
14
19
|
}
|
|
15
|
-
return
|
|
20
|
+
return keys;
|
|
16
21
|
}
|
|
17
22
|
async function reap() {
|
|
18
23
|
return releaseStaleClaims({ client, owner, repo, now });
|
|
@@ -22,6 +27,30 @@ export function createGithubQueueBackend(options) {
|
|
|
22
27
|
return [];
|
|
23
28
|
return pollBlockedParks({ client, owner, repo, store: options.blockedParks });
|
|
24
29
|
}
|
|
25
|
-
return {
|
|
30
|
+
return {
|
|
31
|
+
claimNext,
|
|
32
|
+
release: async (key, outcome) => queue.release(issueNumberOf(key), outcome),
|
|
33
|
+
heartbeat: async (key) => queue.heartbeat(issueNumberOf(key)),
|
|
34
|
+
list,
|
|
35
|
+
lanes: () => queue.lanes(),
|
|
36
|
+
reap,
|
|
37
|
+
pollBlockedParks: pollParks,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export class UnsupportedQueueBackendError extends Error {
|
|
41
|
+
kind;
|
|
42
|
+
constructor(kind) {
|
|
43
|
+
super(`unsupported queue backend "${kind}" — supported: github`);
|
|
44
|
+
this.name = 'UnsupportedQueueBackendError';
|
|
45
|
+
this.kind = kind;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function createQueueBackend(options) {
|
|
49
|
+
switch (options.kind) {
|
|
50
|
+
case 'github':
|
|
51
|
+
return createGithubQueueBackend(options.github);
|
|
52
|
+
default:
|
|
53
|
+
throw new UnsupportedQueueBackendError(String(options.kind));
|
|
54
|
+
}
|
|
26
55
|
}
|
|
27
56
|
//# sourceMappingURL=queue-backend.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue-backend.js","sourceRoot":"","sources":["../../src/queue/queue-backend.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"queue-backend.js","sourceRoot":"","sources":["../../src/queue/queue-backend.ts"],"names":[],"mappings":"AAAA,wJAAwJ;AAExJ,OAAO,EAAqD,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EACL,iBAAiB,GAIlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAgB,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAA0B,MAAM,mBAAmB,CAAC;AA0B/E,MAAM,UAAU,wBAAwB,CAAC,OAAkC;IACzE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEzC,KAAK,UAAU,SAAS,CAAC,IAAY;QACnC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAClG,CAAC;IAED,KAAK,UAAU,IAAI,CAAC,IAAa;QAC/B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAc,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,OAAO,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,UAAU,SAAS;QACtB,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QAClD,OAAO,gBAAgB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,OAAO;QACL,SAAS;QACT,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;QAC3E,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI;QACJ,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE;QAC1B,IAAI;QACJ,gBAAgB,EAAE,SAAS;KAC5B,CAAC;AACJ,CAAC;AASD,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,IAAI,CAAS;IAEtB,YAAY,IAAY;QACtB,KAAK,CAAC,8BAA8B,IAAI,uBAAuB,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,wBAAwB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD;YACE,MAAM,IAAI,4BAA4B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
|
|
@@ -19,8 +19,13 @@ export interface ReviewReworkGitHub {
|
|
|
19
19
|
/** Reviews in GitHub's chronological order. */
|
|
20
20
|
listReviews(pr: number): Promise<ReviewReworkReview[]>;
|
|
21
21
|
}
|
|
22
|
+
/** What triggered a rework: a formal review, or a `/factory rework` PR comment (#3882). */
|
|
23
|
+
export type ReviewReworkSource = 'review' | 'comment';
|
|
22
24
|
export interface ReviewReworkRecord {
|
|
25
|
+
/** The GitHub review id, or the issue-comment id when `source` is `'comment'`. */
|
|
23
26
|
reviewId: number;
|
|
27
|
+
/** Absent or `'review'` is a formal review (legacy files have no source). */
|
|
28
|
+
source?: ReviewReworkSource;
|
|
24
29
|
pr: number;
|
|
25
30
|
issue: number;
|
|
26
31
|
lane: string;
|
|
@@ -32,11 +37,11 @@ export interface ReviewReworkRecord {
|
|
|
32
37
|
cappedAt?: string;
|
|
33
38
|
}
|
|
34
39
|
export interface ReviewReworkStore {
|
|
35
|
-
has(reviewId: number): boolean;
|
|
40
|
+
has(reviewId: number, source?: ReviewReworkSource): boolean;
|
|
36
41
|
record(entry: ReviewReworkRecord): void;
|
|
37
42
|
list(): ReviewReworkRecord[];
|
|
38
43
|
/** Stamp `startedAt` on a record; an unknown id does nothing. */
|
|
39
|
-
markStarted(reviewId: number, at: string): void;
|
|
44
|
+
markStarted(reviewId: number, at: string, source?: ReviewReworkSource): void;
|
|
40
45
|
}
|
|
41
46
|
export type ReviewReworkOutcome = 'queued' | 'already-queued' | 'capped' | 'skipped' | 'error';
|
|
42
47
|
export interface ReviewReworkPollResult {
|