@cliangdev/flux-plugin 0.3.1-dev.ee3b5ee → 0.4.0-dev.0892a21
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/package.json +1 -1
- package/src/server/adapters/github/__tests__/criteria-deps.test.ts +1 -1
- package/src/server/adapters/github/__tests__/prd-crud.test.ts +8 -8
- package/src/server/adapters/github/adapter.ts +110 -88
- package/src/server/adapters/github/client.ts +4 -3
- package/src/server/adapters/github/helpers/index-store.ts +11 -7
- package/src/server/adapters/linear/adapter.ts +121 -105
- package/src/server/adapters/linear/client.ts +21 -14
- package/src/server/tools/__tests__/z-configure-github.test.ts +22 -10
- package/src/server/tools/__tests__/z-get-linear-url.test.ts +2 -2
- package/src/server/tools/configure-github.ts +43 -9
package/package.json
CHANGED
|
@@ -284,7 +284,7 @@ function makeAdapter() {
|
|
|
284
284
|
},
|
|
285
285
|
};
|
|
286
286
|
|
|
287
|
-
(adapter as any).client.rest.request = async (url: string,
|
|
287
|
+
(adapter as any).client.rest.request = async (url: string, _params: any) => {
|
|
288
288
|
if (url.includes("sub_issues") && url.startsWith("GET")) {
|
|
289
289
|
return { data: [] };
|
|
290
290
|
}
|
|
@@ -16,7 +16,7 @@ let mockGraphqlFn: (
|
|
|
16
16
|
variables?: Record<string, unknown>,
|
|
17
17
|
) => Promise<unknown> = async () => ({});
|
|
18
18
|
let lastCreateParams: any = null;
|
|
19
|
-
let
|
|
19
|
+
let _lastUpdateParams: any = null;
|
|
20
20
|
let lastUpdateByNumberParams: Record<number, any> = {};
|
|
21
21
|
let lastPutParams: any = null;
|
|
22
22
|
let issueNodeIdCounter = 0;
|
|
@@ -46,10 +46,10 @@ mock.module("@octokit/rest", () => ({
|
|
|
46
46
|
update: async (params: any) => {
|
|
47
47
|
const num = params.issue_number;
|
|
48
48
|
lastUpdateByNumberParams[num] = params;
|
|
49
|
-
|
|
49
|
+
_lastUpdateParams = params;
|
|
50
50
|
return { data: mockIssuesUpdate ?? mockIssuesCreate };
|
|
51
51
|
},
|
|
52
|
-
get: async (
|
|
52
|
+
get: async (_params: any) => {
|
|
53
53
|
if (mockIssuesGet === null) {
|
|
54
54
|
const err: any = new Error("Not Found");
|
|
55
55
|
err.status = 404;
|
|
@@ -122,7 +122,7 @@ function makeAdapter() {
|
|
|
122
122
|
update: async (params: any) => {
|
|
123
123
|
const num = params.issue_number;
|
|
124
124
|
lastUpdateByNumberParams[num] = params;
|
|
125
|
-
|
|
125
|
+
_lastUpdateParams = params;
|
|
126
126
|
if (mockIssuesUpdate !== null) {
|
|
127
127
|
return { data: mockIssuesUpdate };
|
|
128
128
|
}
|
|
@@ -244,9 +244,9 @@ describe("prd status mappers", () => {
|
|
|
244
244
|
"COMPLETED",
|
|
245
245
|
] as const;
|
|
246
246
|
for (const status of statuses) {
|
|
247
|
-
const label = prdStatusToLabel(status)
|
|
247
|
+
const label = prdStatusToLabel(status);
|
|
248
248
|
expect(label).not.toBeNull();
|
|
249
|
-
const result = labelToPrdStatus([label], false);
|
|
249
|
+
const result = labelToPrdStatus([label as string], false);
|
|
250
250
|
expect(result).toBe(status);
|
|
251
251
|
}
|
|
252
252
|
});
|
|
@@ -280,7 +280,7 @@ describe("GitHubAdapter PRD CRUD", () => {
|
|
|
280
280
|
mockSubIssues = {};
|
|
281
281
|
mockGetContent = null;
|
|
282
282
|
lastCreateParams = null;
|
|
283
|
-
|
|
283
|
+
_lastUpdateParams = null;
|
|
284
284
|
lastUpdateByNumberParams = {};
|
|
285
285
|
lastPutParams = null;
|
|
286
286
|
issueNodeIdCounter = 0;
|
|
@@ -378,7 +378,7 @@ describe("GitHubAdapter PRD CRUD", () => {
|
|
|
378
378
|
await adapter.createPrd({ title: "Board PRD" });
|
|
379
379
|
|
|
380
380
|
expect(capturedMutation).not.toBeNull();
|
|
381
|
-
expect(capturedMutation
|
|
381
|
+
expect(String(capturedMutation)).toContain("addProjectV2ItemById");
|
|
382
382
|
expect(capturedVariables?.contentId).toBe("NODE_10");
|
|
383
383
|
expect(capturedVariables?.projectId).toBe("PVT_kwDO123");
|
|
384
384
|
});
|
|
@@ -50,9 +50,27 @@ import {
|
|
|
50
50
|
} from "./mappers/index.js";
|
|
51
51
|
import { GITHUB_LABELS, type GitHubConfig } from "./types.js";
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
interface GitHubIssue {
|
|
54
|
+
number: number;
|
|
55
|
+
id: number;
|
|
56
|
+
node_id: string;
|
|
57
|
+
title: string;
|
|
58
|
+
body: string | null;
|
|
59
|
+
state: string;
|
|
60
|
+
labels: Array<{ name: string }>;
|
|
61
|
+
created_at: string;
|
|
62
|
+
updated_at: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface GitHubDirectoryEntry {
|
|
66
|
+
type: string;
|
|
67
|
+
name: string;
|
|
68
|
+
path: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function issueToPrd(issue: GitHubIssue, config: GitHubConfig): Prd {
|
|
54
72
|
const meta = decodeMeta(issue.body || "");
|
|
55
|
-
const labels = issue.labels.map((l
|
|
73
|
+
const labels = issue.labels.map((l) => l.name);
|
|
56
74
|
const ref = meta?.ref ?? `${config.refPrefix}-P${issue.number}`;
|
|
57
75
|
const refSlug = ref.toLowerCase().replace(":", "-");
|
|
58
76
|
const tag = labelToTag(labels) ?? meta?.tag;
|
|
@@ -122,7 +140,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
122
140
|
body: string | null;
|
|
123
141
|
}>;
|
|
124
142
|
for (const issue of issues) {
|
|
125
|
-
if (issue.body
|
|
143
|
+
if (issue.body?.includes(`"ref":"${ref}"`)) {
|
|
126
144
|
await this.addToIndex(ref, issue.number);
|
|
127
145
|
return issue.number;
|
|
128
146
|
}
|
|
@@ -166,7 +184,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
166
184
|
labels,
|
|
167
185
|
});
|
|
168
186
|
|
|
169
|
-
const createdIssue = createResponse.data as
|
|
187
|
+
const createdIssue = createResponse.data as GitHubIssue;
|
|
170
188
|
const issueNumber = createdIssue.number;
|
|
171
189
|
const ref = `${this.config.refPrefix}-P${issueNumber}`;
|
|
172
190
|
|
|
@@ -195,7 +213,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
195
213
|
issue_number: issueNumber,
|
|
196
214
|
});
|
|
197
215
|
|
|
198
|
-
return issueToPrd(getResponse.data, this.config);
|
|
216
|
+
return issueToPrd(getResponse.data as GitHubIssue, this.config);
|
|
199
217
|
}
|
|
200
218
|
|
|
201
219
|
async updatePrd(ref: string, input: UpdatePrdInput): Promise<Prd> {
|
|
@@ -209,10 +227,8 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
209
227
|
repo: this.config.repo,
|
|
210
228
|
issue_number: issueNumber,
|
|
211
229
|
});
|
|
212
|
-
const existingIssue = getResponse.data as
|
|
213
|
-
const existingLabels: string[] = existingIssue.labels.map(
|
|
214
|
-
(l: any) => l.name as string,
|
|
215
|
-
);
|
|
230
|
+
const existingIssue = getResponse.data as GitHubIssue;
|
|
231
|
+
const existingLabels: string[] = existingIssue.labels.map((l) => l.name);
|
|
216
232
|
|
|
217
233
|
const statusLabels = new Set(getAllStatusLabels());
|
|
218
234
|
const baseLabels = existingLabels.filter(
|
|
@@ -251,7 +267,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
251
267
|
? `${cleanDescription}\n\n${updatedMeta}`
|
|
252
268
|
: updatedMeta;
|
|
253
269
|
|
|
254
|
-
const updateParams:
|
|
270
|
+
const updateParams: Record<string, unknown> = {
|
|
255
271
|
owner: this.config.owner,
|
|
256
272
|
repo: this.config.repo,
|
|
257
273
|
issue_number: issueNumber,
|
|
@@ -267,9 +283,11 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
267
283
|
updateParams.state = "closed";
|
|
268
284
|
}
|
|
269
285
|
|
|
270
|
-
const updateResponse = await this.client.rest.issues.update(
|
|
286
|
+
const updateResponse = await this.client.rest.issues.update(
|
|
287
|
+
updateParams as Parameters<typeof this.client.rest.issues.update>[0],
|
|
288
|
+
);
|
|
271
289
|
|
|
272
|
-
return issueToPrd(updateResponse.data, this.config);
|
|
290
|
+
return issueToPrd(updateResponse.data as GitHubIssue, this.config);
|
|
273
291
|
}
|
|
274
292
|
|
|
275
293
|
async getPrd(ref: string): Promise<Prd | null> {
|
|
@@ -282,7 +300,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
282
300
|
issue_number: issueNumber,
|
|
283
301
|
});
|
|
284
302
|
|
|
285
|
-
return issueToPrd(response.data, this.config);
|
|
303
|
+
return issueToPrd(response.data as GitHubIssue, this.config);
|
|
286
304
|
}
|
|
287
305
|
|
|
288
306
|
async listPrds(
|
|
@@ -312,7 +330,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
312
330
|
page: 1,
|
|
313
331
|
});
|
|
314
332
|
|
|
315
|
-
const allIssues = response.data as
|
|
333
|
+
const allIssues = response.data as GitHubIssue[];
|
|
316
334
|
const total = allIssues.length;
|
|
317
335
|
const paginated = allIssues.slice(offset, offset + limit);
|
|
318
336
|
|
|
@@ -344,7 +362,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
344
362
|
per_page: 100,
|
|
345
363
|
});
|
|
346
364
|
|
|
347
|
-
const epics = (epicsResponse.data as
|
|
365
|
+
const epics = (epicsResponse.data as GitHubIssue[]).filter((issue) => {
|
|
348
366
|
const meta = decodeMeta(issue.body || "");
|
|
349
367
|
return meta?.prd_ref === ref;
|
|
350
368
|
});
|
|
@@ -362,7 +380,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
362
380
|
per_page: 100,
|
|
363
381
|
});
|
|
364
382
|
|
|
365
|
-
const tasks = (tasksResponse.data as
|
|
383
|
+
const tasks = (tasksResponse.data as GitHubIssue[]).filter((issue) => {
|
|
366
384
|
const meta = decodeMeta(issue.body || "");
|
|
367
385
|
return meta?.epic_ref === epicRef;
|
|
368
386
|
});
|
|
@@ -411,9 +429,9 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
411
429
|
};
|
|
412
430
|
}
|
|
413
431
|
|
|
414
|
-
private issueToEpic(issue:
|
|
432
|
+
private issueToEpic(issue: GitHubIssue): Epic {
|
|
415
433
|
const meta = decodeMeta(issue.body || "");
|
|
416
|
-
const labels = issue.labels.map((l
|
|
434
|
+
const labels = issue.labels.map((l) => l.name);
|
|
417
435
|
return {
|
|
418
436
|
id: String(issue.number),
|
|
419
437
|
prdId: meta?.prd_ref || "",
|
|
@@ -426,9 +444,9 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
426
444
|
};
|
|
427
445
|
}
|
|
428
446
|
|
|
429
|
-
private issueToTask(issue:
|
|
447
|
+
private issueToTask(issue: GitHubIssue): Task {
|
|
430
448
|
const meta = decodeMeta(issue.body || "");
|
|
431
|
-
const labels = issue.labels.map((l
|
|
449
|
+
const labels = issue.labels.map((l) => l.name);
|
|
432
450
|
return {
|
|
433
451
|
id: String(issue.number),
|
|
434
452
|
epicId: meta?.epic_ref || "",
|
|
@@ -466,7 +484,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
466
484
|
labels,
|
|
467
485
|
});
|
|
468
486
|
|
|
469
|
-
const createdIssue = createResponse.data as
|
|
487
|
+
const createdIssue = createResponse.data as GitHubIssue;
|
|
470
488
|
const issueNumber = createdIssue.number;
|
|
471
489
|
const ref = `${this.config.refPrefix}-E${issueNumber}`;
|
|
472
490
|
|
|
@@ -515,7 +533,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
515
533
|
issue_number: issueNumber,
|
|
516
534
|
});
|
|
517
535
|
|
|
518
|
-
return this.issueToEpic(getResponse.data);
|
|
536
|
+
return this.issueToEpic(getResponse.data as GitHubIssue);
|
|
519
537
|
}
|
|
520
538
|
|
|
521
539
|
async updateEpic(ref: string, input: UpdateEpicInput): Promise<Epic> {
|
|
@@ -529,10 +547,8 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
529
547
|
repo: this.config.repo,
|
|
530
548
|
issue_number: issueNumber,
|
|
531
549
|
});
|
|
532
|
-
const existingIssue = getResponse.data as
|
|
533
|
-
const existingLabels: string[] = existingIssue.labels.map(
|
|
534
|
-
(l: any) => l.name as string,
|
|
535
|
-
);
|
|
550
|
+
const existingIssue = getResponse.data as GitHubIssue;
|
|
551
|
+
const existingLabels: string[] = existingIssue.labels.map((l) => l.name);
|
|
536
552
|
|
|
537
553
|
const statusLabelToRemove = GITHUB_LABELS.STATUS_IN_PROGRESS;
|
|
538
554
|
const baseLabels = existingLabels.filter((l) => l !== statusLabelToRemove);
|
|
@@ -562,7 +578,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
562
578
|
? `${cleanDescription}\n\n${updatedMeta}`
|
|
563
579
|
: updatedMeta;
|
|
564
580
|
|
|
565
|
-
const updateParams:
|
|
581
|
+
const updateParams: Record<string, unknown> = {
|
|
566
582
|
owner: this.config.owner,
|
|
567
583
|
repo: this.config.repo,
|
|
568
584
|
issue_number: issueNumber,
|
|
@@ -578,9 +594,11 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
578
594
|
updateParams.state = "closed";
|
|
579
595
|
}
|
|
580
596
|
|
|
581
|
-
const updateResponse = await this.client.rest.issues.update(
|
|
597
|
+
const updateResponse = await this.client.rest.issues.update(
|
|
598
|
+
updateParams as Parameters<typeof this.client.rest.issues.update>[0],
|
|
599
|
+
);
|
|
582
600
|
|
|
583
|
-
return this.issueToEpic(updateResponse.data);
|
|
601
|
+
return this.issueToEpic(updateResponse.data as GitHubIssue);
|
|
584
602
|
}
|
|
585
603
|
|
|
586
604
|
async getEpic(ref: string): Promise<Epic | null> {
|
|
@@ -593,7 +611,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
593
611
|
issue_number: issueNumber,
|
|
594
612
|
});
|
|
595
613
|
|
|
596
|
-
return this.issueToEpic(response.data);
|
|
614
|
+
return this.issueToEpic(response.data as GitHubIssue);
|
|
597
615
|
}
|
|
598
616
|
|
|
599
617
|
async listEpics(
|
|
@@ -603,7 +621,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
603
621
|
const limit = pagination?.limit ?? 50;
|
|
604
622
|
const offset = pagination?.offset ?? 0;
|
|
605
623
|
|
|
606
|
-
let allIssues:
|
|
624
|
+
let allIssues: GitHubIssue[];
|
|
607
625
|
|
|
608
626
|
if (filters?.prdRef) {
|
|
609
627
|
const response = await this.client.rest.issues.listForRepo({
|
|
@@ -613,7 +631,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
613
631
|
state: "all",
|
|
614
632
|
per_page: 100,
|
|
615
633
|
});
|
|
616
|
-
allIssues = (response.data as
|
|
634
|
+
allIssues = (response.data as GitHubIssue[]).filter((issue) => {
|
|
617
635
|
const meta = decodeMeta(issue.body || "");
|
|
618
636
|
return meta?.prd_ref === filters.prdRef;
|
|
619
637
|
});
|
|
@@ -634,12 +652,12 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
634
652
|
per_page: 100,
|
|
635
653
|
page: 1,
|
|
636
654
|
});
|
|
637
|
-
allIssues = response.data as
|
|
655
|
+
allIssues = response.data as GitHubIssue[];
|
|
638
656
|
}
|
|
639
657
|
|
|
640
658
|
if (filters?.status) {
|
|
641
|
-
allIssues = allIssues.filter((issue
|
|
642
|
-
const labels = issue.labels.map((l
|
|
659
|
+
allIssues = allIssues.filter((issue) => {
|
|
660
|
+
const labels = issue.labels.map((l) => l.name);
|
|
643
661
|
return (
|
|
644
662
|
labelToEpicStatus(labels, issue.state === "closed") === filters.status
|
|
645
663
|
);
|
|
@@ -676,7 +694,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
676
694
|
per_page: 100,
|
|
677
695
|
});
|
|
678
696
|
|
|
679
|
-
const tasks = (tasksResponse.data as
|
|
697
|
+
const tasks = (tasksResponse.data as GitHubIssue[]).filter((issue) => {
|
|
680
698
|
const meta = decodeMeta(issue.body || "");
|
|
681
699
|
return meta?.epic_ref === ref;
|
|
682
700
|
});
|
|
@@ -729,7 +747,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
729
747
|
repo: this.config.repo,
|
|
730
748
|
issue_number: epicIssueNum,
|
|
731
749
|
});
|
|
732
|
-
const epicData = epicResponse.data as
|
|
750
|
+
const epicData = epicResponse.data as GitHubIssue;
|
|
733
751
|
const epicMeta = decodeMeta(epicData.body || "");
|
|
734
752
|
const prdRef = epicMeta?.prd_ref || "";
|
|
735
753
|
|
|
@@ -757,7 +775,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
757
775
|
labels,
|
|
758
776
|
});
|
|
759
777
|
|
|
760
|
-
const createdIssue = createResponse.data as
|
|
778
|
+
const createdIssue = createResponse.data as GitHubIssue;
|
|
761
779
|
const issueNumber = createdIssue.number;
|
|
762
780
|
const ref = `${this.config.refPrefix}-T${issueNumber}`;
|
|
763
781
|
|
|
@@ -808,7 +826,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
808
826
|
issue_number: issueNumber,
|
|
809
827
|
});
|
|
810
828
|
|
|
811
|
-
return this.issueToTask(getResponse.data);
|
|
829
|
+
return this.issueToTask(getResponse.data as GitHubIssue);
|
|
812
830
|
}
|
|
813
831
|
|
|
814
832
|
async updateTask(ref: string, input: UpdateTaskInput): Promise<Task> {
|
|
@@ -822,10 +840,8 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
822
840
|
repo: this.config.repo,
|
|
823
841
|
issue_number: issueNumber,
|
|
824
842
|
});
|
|
825
|
-
const existingIssue = getResponse.data as
|
|
826
|
-
const existingLabels: string[] = existingIssue.labels.map(
|
|
827
|
-
(l: any) => l.name as string,
|
|
828
|
-
);
|
|
843
|
+
const existingIssue = getResponse.data as GitHubIssue;
|
|
844
|
+
const existingLabels: string[] = existingIssue.labels.map((l) => l.name);
|
|
829
845
|
|
|
830
846
|
const priorityLabels = new Set<string>([
|
|
831
847
|
GITHUB_LABELS.PRIORITY_LOW,
|
|
@@ -866,7 +882,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
866
882
|
? `${cleanDescription}\n\n${updatedMeta}`
|
|
867
883
|
: updatedMeta;
|
|
868
884
|
|
|
869
|
-
const updateParams:
|
|
885
|
+
const updateParams: Record<string, unknown> = {
|
|
870
886
|
owner: this.config.owner,
|
|
871
887
|
repo: this.config.repo,
|
|
872
888
|
issue_number: issueNumber,
|
|
@@ -882,9 +898,11 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
882
898
|
updateParams.state = "closed";
|
|
883
899
|
}
|
|
884
900
|
|
|
885
|
-
const updateResponse = await this.client.rest.issues.update(
|
|
901
|
+
const updateResponse = await this.client.rest.issues.update(
|
|
902
|
+
updateParams as Parameters<typeof this.client.rest.issues.update>[0],
|
|
903
|
+
);
|
|
886
904
|
|
|
887
|
-
return this.issueToTask(updateResponse.data);
|
|
905
|
+
return this.issueToTask(updateResponse.data as GitHubIssue);
|
|
888
906
|
}
|
|
889
907
|
|
|
890
908
|
async getTask(ref: string): Promise<Task | null> {
|
|
@@ -897,7 +915,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
897
915
|
issue_number: issueNumber,
|
|
898
916
|
});
|
|
899
917
|
|
|
900
|
-
return this.issueToTask(response.data);
|
|
918
|
+
return this.issueToTask(response.data as GitHubIssue);
|
|
901
919
|
}
|
|
902
920
|
|
|
903
921
|
async listTasks(
|
|
@@ -907,7 +925,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
907
925
|
const limit = pagination?.limit ?? 50;
|
|
908
926
|
const offset = pagination?.offset ?? 0;
|
|
909
927
|
|
|
910
|
-
let allIssues:
|
|
928
|
+
let allIssues: GitHubIssue[];
|
|
911
929
|
|
|
912
930
|
if (filters?.epicRef) {
|
|
913
931
|
const response = await this.client.rest.issues.listForRepo({
|
|
@@ -917,7 +935,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
917
935
|
state: "all",
|
|
918
936
|
per_page: 100,
|
|
919
937
|
});
|
|
920
|
-
allIssues = (response.data as
|
|
938
|
+
allIssues = (response.data as GitHubIssue[]).filter((issue) => {
|
|
921
939
|
const meta = decodeMeta(issue.body || "");
|
|
922
940
|
return meta?.epic_ref === filters.epicRef;
|
|
923
941
|
});
|
|
@@ -941,12 +959,12 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
941
959
|
per_page: 100,
|
|
942
960
|
page: 1,
|
|
943
961
|
});
|
|
944
|
-
allIssues = response.data as
|
|
962
|
+
allIssues = response.data as GitHubIssue[];
|
|
945
963
|
}
|
|
946
964
|
|
|
947
965
|
if (filters?.status) {
|
|
948
|
-
allIssues = allIssues.filter((issue
|
|
949
|
-
const labels = issue.labels.map((l
|
|
966
|
+
allIssues = allIssues.filter((issue) => {
|
|
967
|
+
const labels = issue.labels.map((l) => l.name);
|
|
950
968
|
return (
|
|
951
969
|
labelToTaskStatus(labels, issue.state === "closed") === filters.status
|
|
952
970
|
);
|
|
@@ -1009,7 +1027,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1009
1027
|
if (body.includes("<!-- flux-meta")) {
|
|
1010
1028
|
return body.replace(/<!--\s*flux-meta[\s\S]*?-->/, newMetaBlock);
|
|
1011
1029
|
}
|
|
1012
|
-
return body
|
|
1030
|
+
return `${body}\n\n${newMetaBlock}`;
|
|
1013
1031
|
}
|
|
1014
1032
|
|
|
1015
1033
|
async addCriterion(input: AddCriterionInput): Promise<AcceptanceCriterion> {
|
|
@@ -1024,7 +1042,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1024
1042
|
repo: this.config.repo,
|
|
1025
1043
|
issue_number: issueNumber,
|
|
1026
1044
|
});
|
|
1027
|
-
const currentBody = (getResponse.data as
|
|
1045
|
+
const currentBody = (getResponse.data as GitHubIssue).body ?? "";
|
|
1028
1046
|
|
|
1029
1047
|
const newBody = addCriterionToDescription(currentBody, input.criteria);
|
|
1030
1048
|
|
|
@@ -1046,7 +1064,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1046
1064
|
}
|
|
1047
1065
|
|
|
1048
1066
|
async markCriterionMet(criterionId: string): Promise<AcceptanceCriterion> {
|
|
1049
|
-
const allIssues:
|
|
1067
|
+
const allIssues: GitHubIssue[] = [];
|
|
1050
1068
|
|
|
1051
1069
|
const epicResponse = await this.client.rest.issues.listForRepo({
|
|
1052
1070
|
owner: this.config.owner,
|
|
@@ -1055,7 +1073,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1055
1073
|
state: "open",
|
|
1056
1074
|
per_page: 100,
|
|
1057
1075
|
});
|
|
1058
|
-
allIssues.push(...(epicResponse.data as
|
|
1076
|
+
allIssues.push(...(epicResponse.data as GitHubIssue[]));
|
|
1059
1077
|
|
|
1060
1078
|
const taskResponse = await this.client.rest.issues.listForRepo({
|
|
1061
1079
|
owner: this.config.owner,
|
|
@@ -1064,7 +1082,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1064
1082
|
state: "open",
|
|
1065
1083
|
per_page: 100,
|
|
1066
1084
|
});
|
|
1067
|
-
allIssues.push(...(taskResponse.data as
|
|
1085
|
+
allIssues.push(...(taskResponse.data as GitHubIssue[]));
|
|
1068
1086
|
|
|
1069
1087
|
for (const issue of allIssues) {
|
|
1070
1088
|
const body = issue.body ?? "";
|
|
@@ -1079,7 +1097,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1079
1097
|
body: newBody,
|
|
1080
1098
|
});
|
|
1081
1099
|
|
|
1082
|
-
const labels: string[] = issue.labels.map((l
|
|
1100
|
+
const labels: string[] = issue.labels.map((l) => l.name);
|
|
1083
1101
|
const parentType = labels.includes(GITHUB_LABELS.ENTITY_EPIC)
|
|
1084
1102
|
? "epic"
|
|
1085
1103
|
: "task";
|
|
@@ -1110,7 +1128,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1110
1128
|
repo: this.config.repo,
|
|
1111
1129
|
issue_number: issueNumber,
|
|
1112
1130
|
});
|
|
1113
|
-
const body = (response.data as
|
|
1131
|
+
const body = (response.data as GitHubIssue).body ?? "";
|
|
1114
1132
|
const parsed = parseCriteriaFromDescription(body);
|
|
1115
1133
|
const parentType = this.getParentType(parentRef);
|
|
1116
1134
|
|
|
@@ -1155,7 +1173,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1155
1173
|
repo: this.config.repo,
|
|
1156
1174
|
issue_number: issueNumber,
|
|
1157
1175
|
});
|
|
1158
|
-
const currentBody = (getResponse.data as
|
|
1176
|
+
const currentBody = (getResponse.data as GitHubIssue).body ?? "";
|
|
1159
1177
|
const meta = decodeMeta(currentBody);
|
|
1160
1178
|
|
|
1161
1179
|
if (!meta) {
|
|
@@ -1188,7 +1206,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1188
1206
|
repo: this.config.repo,
|
|
1189
1207
|
issue_number: issueNumber,
|
|
1190
1208
|
});
|
|
1191
|
-
const currentBody = (getResponse.data as
|
|
1209
|
+
const currentBody = (getResponse.data as GitHubIssue).body ?? "";
|
|
1192
1210
|
const meta = decodeMeta(currentBody);
|
|
1193
1211
|
|
|
1194
1212
|
if (!meta) {
|
|
@@ -1220,7 +1238,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1220
1238
|
repo: this.config.repo,
|
|
1221
1239
|
issue_number: issueNumber,
|
|
1222
1240
|
});
|
|
1223
|
-
const body = (response.data as
|
|
1241
|
+
const body = (response.data as GitHubIssue).body ?? "";
|
|
1224
1242
|
const meta = decodeMeta(body);
|
|
1225
1243
|
|
|
1226
1244
|
return meta?.dependencies ?? [];
|
|
@@ -1243,8 +1261,8 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1243
1261
|
});
|
|
1244
1262
|
const data = response.data as { sha: string };
|
|
1245
1263
|
return data.sha;
|
|
1246
|
-
} catch (err:
|
|
1247
|
-
if (err.status === 404) return null;
|
|
1264
|
+
} catch (err: unknown) {
|
|
1265
|
+
if ((err as { status?: number }).status === 404) return null;
|
|
1248
1266
|
throw err;
|
|
1249
1267
|
}
|
|
1250
1268
|
}
|
|
@@ -1314,7 +1332,11 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1314
1332
|
putParams.sha = existingSha;
|
|
1315
1333
|
}
|
|
1316
1334
|
|
|
1317
|
-
await this.client.rest.repos.createOrUpdateFileContents(
|
|
1335
|
+
await this.client.rest.repos.createOrUpdateFileContents(
|
|
1336
|
+
putParams as Parameters<
|
|
1337
|
+
typeof this.client.rest.repos.createOrUpdateFileContents
|
|
1338
|
+
>[0],
|
|
1339
|
+
);
|
|
1318
1340
|
|
|
1319
1341
|
const blobUrl = this.blobUrl(filePath);
|
|
1320
1342
|
|
|
@@ -1323,7 +1345,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1323
1345
|
repo: this.config.repo,
|
|
1324
1346
|
issue_number: issueNumber,
|
|
1325
1347
|
});
|
|
1326
|
-
const currentBody = (issueResponse.data as
|
|
1348
|
+
const currentBody = (issueResponse.data as GitHubIssue).body ?? "";
|
|
1327
1349
|
const updatedBody = this.addDocumentLink(
|
|
1328
1350
|
currentBody,
|
|
1329
1351
|
doc.filename,
|
|
@@ -1344,21 +1366,21 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1344
1366
|
const slug = this.refSlug(prdRef);
|
|
1345
1367
|
const dirPath = `prds/${slug}`;
|
|
1346
1368
|
|
|
1347
|
-
let entries:
|
|
1369
|
+
let entries: GitHubDirectoryEntry[];
|
|
1348
1370
|
try {
|
|
1349
1371
|
const response = await this.client.rest.repos.getContent({
|
|
1350
1372
|
owner: this.config.owner,
|
|
1351
1373
|
repo: this.config.repo,
|
|
1352
1374
|
path: dirPath,
|
|
1353
1375
|
});
|
|
1354
|
-
entries = response.data as
|
|
1355
|
-
} catch (err:
|
|
1356
|
-
if (err.status === 404) return [];
|
|
1376
|
+
entries = response.data as GitHubDirectoryEntry[];
|
|
1377
|
+
} catch (err: unknown) {
|
|
1378
|
+
if ((err as { status?: number }).status === 404) return [];
|
|
1357
1379
|
throw err;
|
|
1358
1380
|
}
|
|
1359
1381
|
|
|
1360
1382
|
const mdFiles = entries.filter(
|
|
1361
|
-
(entry
|
|
1383
|
+
(entry) => entry.type === "file" && entry.name.endsWith(".md"),
|
|
1362
1384
|
);
|
|
1363
1385
|
|
|
1364
1386
|
const documents: Document[] = [];
|
|
@@ -1396,7 +1418,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1396
1418
|
const sha = await this.getFileSha(filePath);
|
|
1397
1419
|
|
|
1398
1420
|
if (sha !== null) {
|
|
1399
|
-
await
|
|
1421
|
+
await this.client.rest.repos.deleteFile({
|
|
1400
1422
|
owner: this.config.owner,
|
|
1401
1423
|
repo: this.config.repo,
|
|
1402
1424
|
path: filePath,
|
|
@@ -1410,7 +1432,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1410
1432
|
repo: this.config.repo,
|
|
1411
1433
|
issue_number: issueNumber,
|
|
1412
1434
|
});
|
|
1413
|
-
const currentBody = (issueResponse.data as
|
|
1435
|
+
const currentBody = (issueResponse.data as GitHubIssue).body ?? "";
|
|
1414
1436
|
const updatedBody = this.removeDocumentLink(currentBody, filename);
|
|
1415
1437
|
|
|
1416
1438
|
await this.client.rest.issues.update({
|
|
@@ -1474,12 +1496,12 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1474
1496
|
}),
|
|
1475
1497
|
]);
|
|
1476
1498
|
|
|
1477
|
-
const openPrdIssues = openPrds.data as
|
|
1478
|
-
const closedPrdIssues = closedPrds.data as
|
|
1479
|
-
const openEpicIssues = openEpics.data as
|
|
1480
|
-
const closedEpicIssues = closedEpics.data as
|
|
1481
|
-
const openTaskIssues = openTasks.data as
|
|
1482
|
-
const closedTaskIssues = closedTasks.data as
|
|
1499
|
+
const openPrdIssues = openPrds.data as GitHubIssue[];
|
|
1500
|
+
const closedPrdIssues = closedPrds.data as GitHubIssue[];
|
|
1501
|
+
const openEpicIssues = openEpics.data as GitHubIssue[];
|
|
1502
|
+
const closedEpicIssues = closedEpics.data as GitHubIssue[];
|
|
1503
|
+
const openTaskIssues = openTasks.data as GitHubIssue[];
|
|
1504
|
+
const closedTaskIssues = closedTasks.data as GitHubIssue[];
|
|
1483
1505
|
|
|
1484
1506
|
const prdStats = {
|
|
1485
1507
|
total: openPrdIssues.length,
|
|
@@ -1493,7 +1515,7 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1493
1515
|
};
|
|
1494
1516
|
|
|
1495
1517
|
for (const issue of openPrdIssues) {
|
|
1496
|
-
const labels = issue.labels.map((l
|
|
1518
|
+
const labels = issue.labels.map((l) => l.name);
|
|
1497
1519
|
if (labels.includes(GITHUB_LABELS.STATUS_COMPLETED)) {
|
|
1498
1520
|
prdStats.completed++;
|
|
1499
1521
|
} else if (labels.includes(GITHUB_LABELS.STATUS_BREAKDOWN_READY)) {
|
|
@@ -1509,25 +1531,25 @@ export class GitHubAdapter implements BackendAdapter {
|
|
|
1509
1531
|
}
|
|
1510
1532
|
}
|
|
1511
1533
|
|
|
1512
|
-
const epicPending = openEpicIssues.filter((issue
|
|
1513
|
-
const labels = issue.labels.map((l
|
|
1534
|
+
const epicPending = openEpicIssues.filter((issue) => {
|
|
1535
|
+
const labels = issue.labels.map((l) => l.name);
|
|
1514
1536
|
return !labels.includes(GITHUB_LABELS.STATUS_IN_PROGRESS);
|
|
1515
1537
|
}).length;
|
|
1516
1538
|
|
|
1517
|
-
const epicInProgress = openEpicIssues.filter((issue
|
|
1518
|
-
const labels = issue.labels.map((l
|
|
1539
|
+
const epicInProgress = openEpicIssues.filter((issue) => {
|
|
1540
|
+
const labels = issue.labels.map((l) => l.name);
|
|
1519
1541
|
return labels.includes(GITHUB_LABELS.STATUS_IN_PROGRESS);
|
|
1520
1542
|
}).length;
|
|
1521
1543
|
|
|
1522
1544
|
const epicCompleted = closedEpicIssues.length;
|
|
1523
1545
|
|
|
1524
|
-
const taskPending = openTaskIssues.filter((issue
|
|
1525
|
-
const labels = issue.labels.map((l
|
|
1546
|
+
const taskPending = openTaskIssues.filter((issue) => {
|
|
1547
|
+
const labels = issue.labels.map((l) => l.name);
|
|
1526
1548
|
return !labels.includes(GITHUB_LABELS.STATUS_IN_PROGRESS);
|
|
1527
1549
|
}).length;
|
|
1528
1550
|
|
|
1529
|
-
const taskInProgress = openTaskIssues.filter((issue
|
|
1530
|
-
const labels = issue.labels.map((l
|
|
1551
|
+
const taskInProgress = openTaskIssues.filter((issue) => {
|
|
1552
|
+
const labels = issue.labels.map((l) => l.name);
|
|
1531
1553
|
return labels.includes(GITHUB_LABELS.STATUS_IN_PROGRESS);
|
|
1532
1554
|
}).length;
|
|
1533
1555
|
|
|
@@ -21,10 +21,11 @@ export class GitHubClient {
|
|
|
21
21
|
): Promise<T> {
|
|
22
22
|
try {
|
|
23
23
|
return await this.gql<T>(query, variables);
|
|
24
|
-
} catch (error:
|
|
25
|
-
|
|
24
|
+
} catch (error: unknown) {
|
|
25
|
+
const err = error as { status?: number };
|
|
26
|
+
if (err.status === 401 || err.status === 403) {
|
|
26
27
|
throw new Error(
|
|
27
|
-
`GitHub API auth error: token may lack 'repo' scope (HTTP ${
|
|
28
|
+
`GitHub API auth error: token may lack 'repo' scope (HTTP ${err.status})`,
|
|
28
29
|
);
|
|
29
30
|
}
|
|
30
31
|
throw error;
|