github-issue-tower-defence-management 1.103.1 → 1.104.1
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/CHANGELOG.md +14 -0
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +83 -58
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +8 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +16 -0
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +7 -2
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +4 -5
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
- package/bin/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.js +30 -4
- package/bin/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +2 -1
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/resolveAllowedIssueAuthors.js +8 -0
- package/bin/domain/usecases/resolveAllowedIssueAuthors.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +1 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.test.ts +36 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +23 -1
- package/src/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.test.ts +1 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.test.ts +1 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.test.ts +1 -0
- package/src/adapter/entry-points/handlers/situationFileWriter.test.ts +1 -0
- package/src/adapter/repositories/GitHubIssueCommentRepository.test.ts +1 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +9 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +10 -0
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +24 -0
- package/src/adapter/repositories/issue/RestIssueRepository.test.ts +1 -0
- package/src/domain/entities/Issue.ts +1 -0
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.test.ts +1 -0
- package/src/domain/usecases/GetStoryObjectMapUseCase.test.ts +1 -0
- package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +109 -0
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +8 -2
- package/src/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.test.ts +1 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +1 -0
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +110 -12
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +5 -7
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +1 -0
- package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.test.ts +148 -115
- package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.ts +35 -10
- package/src/domain/usecases/SetupTowerDefenceProjectUseCase.test.ts +1 -0
- package/src/domain/usecases/StartPreparationUseCase.test.ts +203 -88
- package/src/domain/usecases/StartPreparationUseCase.ts +2 -1
- package/src/domain/usecases/console/GenerateConsoleListsUseCase.test.ts +1 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +1 -0
- package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +1 -0
- package/src/domain/usecases/resolveAllowedIssueAuthors.test.ts +51 -0
- package/src/domain/usecases/resolveAllowedIssueAuthors.ts +6 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +1 -0
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
- package/types/domain/entities/Issue.d.ts +1 -0
- package/types/domain/entities/Issue.d.ts.map +1 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +1 -0
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
- package/types/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.d.ts +3 -2
- package/types/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/resolveAllowedIssueAuthors.d.ts +5 -0
- package/types/domain/usecases/resolveAllowedIssueAuthors.d.ts.map +1 -0
|
@@ -543,6 +543,7 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
543
543
|
isClosed: item.state !== 'OPEN',
|
|
544
544
|
createdAt: new Date(item.createdAt || '2000-01-01'),
|
|
545
545
|
author: item.author,
|
|
546
|
+
closingIssueReferenceUrls: item.closingIssueReferenceUrls,
|
|
546
547
|
};
|
|
547
548
|
};
|
|
548
549
|
getAllIssuesFromCache = async (
|
|
@@ -578,6 +579,14 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
578
579
|
!('createdAt' in issue) || typeof issue.createdAt !== 'string'
|
|
579
580
|
? new Date()
|
|
580
581
|
: new Date(issue.createdAt);
|
|
582
|
+
const closingIssueReferenceUrls =
|
|
583
|
+
'closingIssueReferenceUrls' in issue &&
|
|
584
|
+
Array.isArray(issue.closingIssueReferenceUrls) &&
|
|
585
|
+
issue.closingIssueReferenceUrls.every(
|
|
586
|
+
(url): url is string => typeof url === 'string',
|
|
587
|
+
)
|
|
588
|
+
? issue.closingIssueReferenceUrls
|
|
589
|
+
: [];
|
|
581
590
|
|
|
582
591
|
return {
|
|
583
592
|
...issue,
|
|
@@ -585,6 +594,7 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
585
594
|
completionDate50PercentConfidence:
|
|
586
595
|
completionDate50PercentConfidence,
|
|
587
596
|
createdAt: createdAt,
|
|
597
|
+
closingIssueReferenceUrls: closingIssueReferenceUrls,
|
|
588
598
|
};
|
|
589
599
|
});
|
|
590
600
|
|
|
@@ -14,6 +14,7 @@ export type ProjectItem = {
|
|
|
14
14
|
assignees: string[];
|
|
15
15
|
createdAt: string;
|
|
16
16
|
author: string;
|
|
17
|
+
closingIssueReferenceUrls: string[];
|
|
17
18
|
customFields: {
|
|
18
19
|
name: string;
|
|
19
20
|
value: string | null;
|
|
@@ -214,6 +215,11 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
214
215
|
repository {
|
|
215
216
|
nameWithOwner
|
|
216
217
|
}
|
|
218
|
+
closingIssuesReferences(first: 50) {
|
|
219
|
+
nodes {
|
|
220
|
+
url
|
|
221
|
+
}
|
|
222
|
+
}
|
|
217
223
|
}
|
|
218
224
|
}
|
|
219
225
|
}
|
|
@@ -257,6 +263,7 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
257
263
|
author: { login: string } | null;
|
|
258
264
|
labels: { nodes: { name: string }[] };
|
|
259
265
|
assignees: { nodes: { login: string }[] };
|
|
266
|
+
closingIssuesReferences?: { nodes: { url: string }[] };
|
|
260
267
|
};
|
|
261
268
|
}[];
|
|
262
269
|
};
|
|
@@ -309,6 +316,7 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
309
316
|
author: { login: string } | null;
|
|
310
317
|
labels: { nodes: { name: string }[] };
|
|
311
318
|
assignees: { nodes: { login: string }[] };
|
|
319
|
+
closingIssuesReferences?: { nodes: { url: string }[] };
|
|
312
320
|
};
|
|
313
321
|
}[];
|
|
314
322
|
};
|
|
@@ -364,6 +372,7 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
364
372
|
author: { login: string } | null;
|
|
365
373
|
labels: { nodes: { name: string }[] };
|
|
366
374
|
assignees: { nodes: { login: string }[] };
|
|
375
|
+
closingIssuesReferences?: { nodes: { url: string }[] };
|
|
367
376
|
};
|
|
368
377
|
}[];
|
|
369
378
|
};
|
|
@@ -435,6 +444,7 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
435
444
|
author: { login: string } | null;
|
|
436
445
|
labels: { nodes: { name: string }[] };
|
|
437
446
|
assignees: { nodes: { login: string }[] };
|
|
447
|
+
closingIssuesReferences?: { nodes: { url: string }[] };
|
|
438
448
|
};
|
|
439
449
|
}[] = pageNodes;
|
|
440
450
|
projectItems.forEach((item) => {
|
|
@@ -453,6 +463,10 @@ query GetProjectItems($projectId: ID!, $after: String, $first: Int!) {
|
|
|
453
463
|
assignees: item.content.assignees?.nodes?.map((a) => a.login) || [],
|
|
454
464
|
createdAt: item.content.createdAt || new Date().toISOString(),
|
|
455
465
|
author: item.content.author?.login || '',
|
|
466
|
+
closingIssueReferenceUrls:
|
|
467
|
+
item.content.closingIssuesReferences?.nodes
|
|
468
|
+
?.map((node) => node.url)
|
|
469
|
+
.filter((url) => url.length > 0) || [],
|
|
456
470
|
customFields: item.fieldValues.nodes
|
|
457
471
|
.filter((field) => !!field.field)
|
|
458
472
|
.map((field) => {
|
|
@@ -768,6 +782,11 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
768
782
|
repository {
|
|
769
783
|
nameWithOwner
|
|
770
784
|
}
|
|
785
|
+
closingIssuesReferences(first: 50) {
|
|
786
|
+
nodes {
|
|
787
|
+
url
|
|
788
|
+
}
|
|
789
|
+
}
|
|
771
790
|
projectItems(first: 10) {
|
|
772
791
|
nodes {
|
|
773
792
|
id
|
|
@@ -843,6 +862,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
843
862
|
labels: { nodes: { name: string }[] };
|
|
844
863
|
assignees: { nodes: { login: string }[] };
|
|
845
864
|
repository: { nameWithOwner: string };
|
|
865
|
+
closingIssuesReferences?: { nodes: { url: string }[] };
|
|
846
866
|
projectItems: {
|
|
847
867
|
nodes: {
|
|
848
868
|
id: string;
|
|
@@ -914,6 +934,10 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
914
934
|
assignees: content.assignees?.nodes?.map((a) => a.login) || [],
|
|
915
935
|
createdAt: content.createdAt || new Date().toISOString(),
|
|
916
936
|
author: content.author?.login || '',
|
|
937
|
+
closingIssueReferenceUrls:
|
|
938
|
+
content.closingIssuesReferences?.nodes
|
|
939
|
+
?.map((node) => node.url)
|
|
940
|
+
.filter((url) => url.length > 0) || [],
|
|
917
941
|
customFields: item.fieldValues.nodes
|
|
918
942
|
.filter((field) => !!field.field)
|
|
919
943
|
.map((field) => {
|
|
@@ -379,6 +379,115 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
379
379
|
).toHaveBeenCalledTimes(1);
|
|
380
380
|
});
|
|
381
381
|
|
|
382
|
+
it('should pass a top-level allowedIssueAuthors to revertNotReadyReviewQueueIssueUseCase', async () => {
|
|
383
|
+
const input = {
|
|
384
|
+
projectName: 'test-project',
|
|
385
|
+
org: 'test-org',
|
|
386
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
387
|
+
manager: 'test-manager',
|
|
388
|
+
workingReport: {
|
|
389
|
+
repo: 'test-repo',
|
|
390
|
+
members: ['member1'],
|
|
391
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
392
|
+
},
|
|
393
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
394
|
+
disabled: false,
|
|
395
|
+
allowIssueCacheMinutes: 60,
|
|
396
|
+
allowedIssueAuthors: ['top-level-author'],
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
mockProjectRepository.getProject.mockResolvedValue(mock<Project>());
|
|
400
|
+
await useCase.run(input);
|
|
401
|
+
|
|
402
|
+
expect(
|
|
403
|
+
mockRevertNotReadyReviewQueueIssueUseCase.run,
|
|
404
|
+
).toHaveBeenCalledWith(
|
|
405
|
+
expect.objectContaining({
|
|
406
|
+
allowedIssueAuthors: ['top-level-author'],
|
|
407
|
+
}),
|
|
408
|
+
);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('should prefer a top-level allowedIssueAuthors over the startPreparation one', async () => {
|
|
412
|
+
const input = {
|
|
413
|
+
projectName: 'test-project',
|
|
414
|
+
org: 'test-org',
|
|
415
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
416
|
+
manager: 'test-manager',
|
|
417
|
+
workingReport: {
|
|
418
|
+
repo: 'test-repo',
|
|
419
|
+
members: ['member1'],
|
|
420
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
421
|
+
},
|
|
422
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
423
|
+
disabled: false,
|
|
424
|
+
allowIssueCacheMinutes: 60,
|
|
425
|
+
allowedIssueAuthors: ['top-level-author'],
|
|
426
|
+
startPreparation: {
|
|
427
|
+
defaultAgentName: 'agent1',
|
|
428
|
+
configFilePath: '/path/to/config.yml',
|
|
429
|
+
maximumPreparingIssuesCount: null,
|
|
430
|
+
allowedIssueAuthors: ['nested-author'],
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
mockProjectRepository.getProject.mockResolvedValue(mock<Project>());
|
|
435
|
+
mockStartPreparationUseCase.run.mockResolvedValue({
|
|
436
|
+
rotationOrder: null,
|
|
437
|
+
});
|
|
438
|
+
await useCase.run(input);
|
|
439
|
+
|
|
440
|
+
expect(
|
|
441
|
+
mockRevertNotReadyReviewQueueIssueUseCase.run,
|
|
442
|
+
).toHaveBeenCalledWith(
|
|
443
|
+
expect.objectContaining({
|
|
444
|
+
allowedIssueAuthors: ['top-level-author'],
|
|
445
|
+
}),
|
|
446
|
+
);
|
|
447
|
+
expect(mockStartPreparationUseCase.run).toHaveBeenCalledWith(
|
|
448
|
+
expect.objectContaining({
|
|
449
|
+
allowedIssueAuthors: ['top-level-author'],
|
|
450
|
+
}),
|
|
451
|
+
);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('should fall back to startPreparation allowedIssueAuthors when no top-level value is set', async () => {
|
|
455
|
+
const input = {
|
|
456
|
+
projectName: 'test-project',
|
|
457
|
+
org: 'test-org',
|
|
458
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
459
|
+
manager: 'test-manager',
|
|
460
|
+
workingReport: {
|
|
461
|
+
repo: 'test-repo',
|
|
462
|
+
members: ['member1'],
|
|
463
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
464
|
+
},
|
|
465
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
466
|
+
disabled: false,
|
|
467
|
+
allowIssueCacheMinutes: 60,
|
|
468
|
+
startPreparation: {
|
|
469
|
+
defaultAgentName: 'agent1',
|
|
470
|
+
configFilePath: '/path/to/config.yml',
|
|
471
|
+
maximumPreparingIssuesCount: null,
|
|
472
|
+
allowedIssueAuthors: ['nested-author'],
|
|
473
|
+
},
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
mockProjectRepository.getProject.mockResolvedValue(mock<Project>());
|
|
477
|
+
mockStartPreparationUseCase.run.mockResolvedValue({
|
|
478
|
+
rotationOrder: null,
|
|
479
|
+
});
|
|
480
|
+
await useCase.run(input);
|
|
481
|
+
|
|
482
|
+
expect(
|
|
483
|
+
mockRevertNotReadyReviewQueueIssueUseCase.run,
|
|
484
|
+
).toHaveBeenCalledWith(
|
|
485
|
+
expect.objectContaining({
|
|
486
|
+
allowedIssueAuthors: ['nested-author'],
|
|
487
|
+
}),
|
|
488
|
+
);
|
|
489
|
+
});
|
|
490
|
+
|
|
382
491
|
it('should invoke UpdateRateLimitCacheUseCase before StartPreparationUseCase when startPreparation is configured', async () => {
|
|
383
492
|
const callOrder: string[] = [];
|
|
384
493
|
mockUpdateRateLimitCacheUseCase.run.mockImplementation(async () => {
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
import { RevertOrphanedPreparationUseCase } from './RevertOrphanedPreparationUseCase';
|
|
28
28
|
import { RevertNotReadyReviewQueueIssueUseCase } from './RevertNotReadyReviewQueueIssueUseCase';
|
|
29
29
|
import { resolveLabelsAsLlmAgentName } from './resolveLabelsAsLlmAgentName';
|
|
30
|
+
import { resolveAllowedIssueAuthors } from './resolveAllowedIssueAuthors';
|
|
30
31
|
import { SetupTowerDefenceProjectUseCase } from './SetupTowerDefenceProjectUseCase';
|
|
31
32
|
import { UpdateRateLimitCacheUseCase } from './UpdateRateLimitCacheUseCase';
|
|
32
33
|
import {
|
|
@@ -86,6 +87,7 @@ export class HandleScheduledEventUseCase {
|
|
|
86
87
|
allowIssueCacheMinutes: number;
|
|
87
88
|
labelsAsLlmAgentName?: string[] | null;
|
|
88
89
|
changeTargetPathAliases?: Record<string, string> | null;
|
|
90
|
+
allowedIssueAuthors?: string[] | null;
|
|
89
91
|
startPreparation?: {
|
|
90
92
|
defaultAgentName: string;
|
|
91
93
|
defaultLlmModelName?: string | null;
|
|
@@ -293,12 +295,16 @@ ${JSON.stringify(e)}
|
|
|
293
295
|
topLevel: input.labelsAsLlmAgentName,
|
|
294
296
|
startPreparation: input.startPreparation?.labelsAsLlmAgentName,
|
|
295
297
|
});
|
|
298
|
+
const allowedIssueAuthors = resolveAllowedIssueAuthors({
|
|
299
|
+
topLevel: input.allowedIssueAuthors,
|
|
300
|
+
startPreparation: input.startPreparation?.allowedIssueAuthors,
|
|
301
|
+
});
|
|
296
302
|
await this.revertNotReadyReviewQueueIssueUseCase.run({
|
|
297
303
|
projectUrl: input.projectUrl,
|
|
298
304
|
allowIssueCacheMinutes: input.allowIssueCacheMinutes,
|
|
299
305
|
labelsAsLlmAgentName,
|
|
300
306
|
changeTargetPathAliases: input.changeTargetPathAliases,
|
|
301
|
-
allowedIssueAuthors
|
|
307
|
+
allowedIssueAuthors,
|
|
302
308
|
});
|
|
303
309
|
if (this.dailySecurityScanUseCase !== null && input.dailySecurityScan) {
|
|
304
310
|
await this.dailySecurityScanUseCase.run({
|
|
@@ -341,7 +347,7 @@ ${JSON.stringify(e)}
|
|
|
341
347
|
input.startPreparation.maximumPreparingIssuesCount,
|
|
342
348
|
utilizationPercentageThreshold:
|
|
343
349
|
input.startPreparation.utilizationPercentageThreshold ?? 90,
|
|
344
|
-
allowedIssueAuthors
|
|
350
|
+
allowedIssueAuthors,
|
|
345
351
|
codexHomeCandidates: input.startPreparation.codexHomeCandidates ?? null,
|
|
346
352
|
allowIssueCacheMinutes: input.allowIssueCacheMinutes,
|
|
347
353
|
labelsAsLlmAgentName,
|
|
@@ -79,7 +79,8 @@ const createMockIssue = (overrides: Partial<Issue> = {}): Issue => ({
|
|
|
79
79
|
isInProgress: false,
|
|
80
80
|
isClosed: false,
|
|
81
81
|
createdAt: new Date(),
|
|
82
|
-
author: '',
|
|
82
|
+
author: 'owner',
|
|
83
|
+
closingIssueReferenceUrls: [],
|
|
83
84
|
...overrides,
|
|
84
85
|
});
|
|
85
86
|
|
|
@@ -170,6 +171,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
170
171
|
await useCase.run({
|
|
171
172
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
172
173
|
allowIssueCacheMinutes: 10,
|
|
174
|
+
allowedIssueAuthors: ['owner'],
|
|
173
175
|
});
|
|
174
176
|
|
|
175
177
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -189,6 +191,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
189
191
|
await useCase.run({
|
|
190
192
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
191
193
|
allowIssueCacheMinutes: 10,
|
|
194
|
+
allowedIssueAuthors: ['owner'],
|
|
192
195
|
});
|
|
193
196
|
|
|
194
197
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -208,6 +211,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
208
211
|
await useCase.run({
|
|
209
212
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
210
213
|
allowIssueCacheMinutes: 10,
|
|
214
|
+
allowedIssueAuthors: ['owner'],
|
|
211
215
|
});
|
|
212
216
|
|
|
213
217
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -240,6 +244,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
240
244
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
241
245
|
allowIssueCacheMinutes: 10,
|
|
242
246
|
labelsAsLlmAgentName: ['story', 'chore', 'accounting'],
|
|
247
|
+
allowedIssueAuthors: ['owner'],
|
|
243
248
|
});
|
|
244
249
|
|
|
245
250
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -261,6 +266,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
261
266
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
262
267
|
allowIssueCacheMinutes: 10,
|
|
263
268
|
labelsAsLlmAgentName: ['story', 'chore'],
|
|
269
|
+
allowedIssueAuthors: ['owner'],
|
|
264
270
|
});
|
|
265
271
|
|
|
266
272
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -281,6 +287,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
281
287
|
await useCase.run({
|
|
282
288
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
283
289
|
allowIssueCacheMinutes: 10,
|
|
290
|
+
allowedIssueAuthors: ['owner'],
|
|
284
291
|
});
|
|
285
292
|
|
|
286
293
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -309,6 +316,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
309
316
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
310
317
|
allowIssueCacheMinutes: 10,
|
|
311
318
|
labelsAsLlmAgentName: null,
|
|
319
|
+
allowedIssueAuthors: ['owner'],
|
|
312
320
|
});
|
|
313
321
|
|
|
314
322
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -333,6 +341,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
333
341
|
await useCase.run({
|
|
334
342
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
335
343
|
allowIssueCacheMinutes: 10,
|
|
344
|
+
allowedIssueAuthors: ['owner'],
|
|
336
345
|
});
|
|
337
346
|
|
|
338
347
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -354,6 +363,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
354
363
|
await useCase.run({
|
|
355
364
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
356
365
|
allowIssueCacheMinutes: 10,
|
|
366
|
+
allowedIssueAuthors: ['owner'],
|
|
357
367
|
});
|
|
358
368
|
|
|
359
369
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -390,6 +400,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
390
400
|
await useCase.run({
|
|
391
401
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
392
402
|
allowIssueCacheMinutes: 10,
|
|
403
|
+
allowedIssueAuthors: ['owner'],
|
|
393
404
|
});
|
|
394
405
|
|
|
395
406
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -422,6 +433,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
422
433
|
await useCase.run({
|
|
423
434
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
424
435
|
allowIssueCacheMinutes: 10,
|
|
436
|
+
allowedIssueAuthors: ['owner'],
|
|
425
437
|
});
|
|
426
438
|
|
|
427
439
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -454,6 +466,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
454
466
|
await useCase.run({
|
|
455
467
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
456
468
|
allowIssueCacheMinutes: 10,
|
|
469
|
+
allowedIssueAuthors: ['owner'],
|
|
457
470
|
});
|
|
458
471
|
|
|
459
472
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -487,6 +500,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
487
500
|
await useCase.run({
|
|
488
501
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
489
502
|
allowIssueCacheMinutes: 10,
|
|
503
|
+
allowedIssueAuthors: ['owner'],
|
|
490
504
|
});
|
|
491
505
|
|
|
492
506
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -524,6 +538,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
524
538
|
await useCase.run({
|
|
525
539
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
526
540
|
allowIssueCacheMinutes: 10,
|
|
541
|
+
allowedIssueAuthors: ['owner'],
|
|
527
542
|
});
|
|
528
543
|
|
|
529
544
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -561,6 +576,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
561
576
|
useCase.run({
|
|
562
577
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
563
578
|
allowIssueCacheMinutes: 10,
|
|
579
|
+
allowedIssueAuthors: ['owner'],
|
|
564
580
|
});
|
|
565
581
|
|
|
566
582
|
it('should not approve PR when issue has no change-target label', async () => {
|
|
@@ -772,6 +788,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
772
788
|
await useCase.run({
|
|
773
789
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
774
790
|
allowIssueCacheMinutes: 10,
|
|
791
|
+
allowedIssueAuthors: ['owner'],
|
|
775
792
|
changeTargetPathAliases: {
|
|
776
793
|
adapters: 'src/domain/usecases/adapter-interfaces',
|
|
777
794
|
},
|
|
@@ -791,6 +808,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
791
808
|
await useCase.run({
|
|
792
809
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
793
810
|
allowIssueCacheMinutes: 10,
|
|
811
|
+
allowedIssueAuthors: ['owner'],
|
|
794
812
|
changeTargetPathAliases: {
|
|
795
813
|
adapters: 'src/domain/usecases/adapter-interfaces',
|
|
796
814
|
},
|
|
@@ -814,6 +832,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
814
832
|
await useCase.run({
|
|
815
833
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
816
834
|
allowIssueCacheMinutes: 10,
|
|
835
|
+
allowedIssueAuthors: ['owner'],
|
|
817
836
|
});
|
|
818
837
|
|
|
819
838
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -835,6 +854,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
835
854
|
await useCase.run({
|
|
836
855
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
837
856
|
allowIssueCacheMinutes: 10,
|
|
857
|
+
allowedIssueAuthors: ['owner'],
|
|
838
858
|
});
|
|
839
859
|
|
|
840
860
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -855,6 +875,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
855
875
|
await useCase.run({
|
|
856
876
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
857
877
|
allowIssueCacheMinutes: 10,
|
|
878
|
+
allowedIssueAuthors: ['owner'],
|
|
858
879
|
});
|
|
859
880
|
|
|
860
881
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -875,6 +896,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
875
896
|
await useCase.run({
|
|
876
897
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
877
898
|
allowIssueCacheMinutes: 10,
|
|
899
|
+
allowedIssueAuthors: ['owner'],
|
|
878
900
|
});
|
|
879
901
|
|
|
880
902
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -898,6 +920,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
898
920
|
await useCase.run({
|
|
899
921
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
900
922
|
allowIssueCacheMinutes: 10,
|
|
923
|
+
allowedIssueAuthors: ['owner'],
|
|
901
924
|
});
|
|
902
925
|
|
|
903
926
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -937,6 +960,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
937
960
|
await useCase.run({
|
|
938
961
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
939
962
|
allowIssueCacheMinutes: 10,
|
|
963
|
+
allowedIssueAuthors: ['owner'],
|
|
940
964
|
});
|
|
941
965
|
|
|
942
966
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -971,6 +995,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
971
995
|
await useCase.run({
|
|
972
996
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
973
997
|
allowIssueCacheMinutes: 10,
|
|
998
|
+
allowedIssueAuthors: ['owner'],
|
|
974
999
|
});
|
|
975
1000
|
|
|
976
1001
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -1007,6 +1032,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1007
1032
|
await useCase.run({
|
|
1008
1033
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1009
1034
|
allowIssueCacheMinutes: 10,
|
|
1035
|
+
allowedIssueAuthors: ['owner'],
|
|
1010
1036
|
});
|
|
1011
1037
|
|
|
1012
1038
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -1041,6 +1067,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1041
1067
|
await useCase.run({
|
|
1042
1068
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1043
1069
|
allowIssueCacheMinutes: 10,
|
|
1070
|
+
allowedIssueAuthors: ['owner'],
|
|
1044
1071
|
});
|
|
1045
1072
|
|
|
1046
1073
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -1072,6 +1099,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1072
1099
|
await useCase.run({
|
|
1073
1100
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1074
1101
|
allowIssueCacheMinutes: 10,
|
|
1102
|
+
allowedIssueAuthors: ['owner'],
|
|
1075
1103
|
});
|
|
1076
1104
|
|
|
1077
1105
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -1109,6 +1137,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1109
1137
|
await useCase.run({
|
|
1110
1138
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1111
1139
|
allowIssueCacheMinutes: 10,
|
|
1140
|
+
allowedIssueAuthors: ['owner'],
|
|
1112
1141
|
});
|
|
1113
1142
|
|
|
1114
1143
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
@@ -1153,6 +1182,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1153
1182
|
await useCase.run({
|
|
1154
1183
|
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1155
1184
|
allowIssueCacheMinutes: 10,
|
|
1185
|
+
allowedIssueAuthors: ['owner'],
|
|
1156
1186
|
});
|
|
1157
1187
|
|
|
1158
1188
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
@@ -1222,7 +1252,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1222
1252
|
);
|
|
1223
1253
|
});
|
|
1224
1254
|
|
|
1225
|
-
it('should
|
|
1255
|
+
it('should skip an Unread pull request authored by a dependency-update bot not in allowedIssueAuthors', async () => {
|
|
1226
1256
|
const pullRequest = createMockPullRequest({
|
|
1227
1257
|
status: 'Unread',
|
|
1228
1258
|
author: 'dependabot[bot]',
|
|
@@ -1242,6 +1272,31 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1242
1272
|
allowedIssueAuthors: ['owner'],
|
|
1243
1273
|
});
|
|
1244
1274
|
|
|
1275
|
+
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1276
|
+
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1277
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
it('should act on a dependency-update bot only when it is explicitly listed in allowedIssueAuthors', async () => {
|
|
1281
|
+
const pullRequest = createMockPullRequest({
|
|
1282
|
+
status: 'Unread',
|
|
1283
|
+
author: 'dependabot[bot]',
|
|
1284
|
+
});
|
|
1285
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1286
|
+
issues: [pullRequest],
|
|
1287
|
+
cacheUsed: false,
|
|
1288
|
+
});
|
|
1289
|
+
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1290
|
+
...createReadyPr(),
|
|
1291
|
+
isConflicted: true,
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
await useCase.run({
|
|
1295
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1296
|
+
allowIssueCacheMinutes: 10,
|
|
1297
|
+
allowedIssueAuthors: ['owner', 'dependabot[bot]'],
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1245
1300
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1246
1301
|
mockProject,
|
|
1247
1302
|
pullRequest,
|
|
@@ -1253,7 +1308,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1253
1308
|
);
|
|
1254
1309
|
});
|
|
1255
1310
|
|
|
1256
|
-
it('should
|
|
1311
|
+
it('should process no author when allowedIssueAuthors is null', async () => {
|
|
1257
1312
|
const pullRequest = createMockPullRequest({
|
|
1258
1313
|
status: 'Unread',
|
|
1259
1314
|
author: 'outside-contributor',
|
|
@@ -1273,15 +1328,58 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1273
1328
|
allowedIssueAuthors: null,
|
|
1274
1329
|
});
|
|
1275
1330
|
|
|
1276
|
-
expect(mockIssueRepository.updateStatus).
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1331
|
+
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1332
|
+
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1333
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
it('should process no author when allowedIssueAuthors is undefined', async () => {
|
|
1337
|
+
const pullRequest = createMockPullRequest({
|
|
1338
|
+
status: 'Unread',
|
|
1339
|
+
author: 'owner',
|
|
1340
|
+
});
|
|
1341
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1342
|
+
issues: [pullRequest],
|
|
1343
|
+
cacheUsed: false,
|
|
1344
|
+
});
|
|
1345
|
+
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1346
|
+
...createReadyPr(),
|
|
1347
|
+
isConflicted: true,
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
await useCase.run({
|
|
1351
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1352
|
+
allowIssueCacheMinutes: 10,
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1356
|
+
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1357
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1358
|
+
});
|
|
1359
|
+
|
|
1360
|
+
it('should process no author when allowedIssueAuthors is an empty list', async () => {
|
|
1361
|
+
const pullRequest = createMockPullRequest({
|
|
1362
|
+
status: 'Unread',
|
|
1363
|
+
author: 'owner',
|
|
1364
|
+
});
|
|
1365
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1366
|
+
issues: [pullRequest],
|
|
1367
|
+
cacheUsed: false,
|
|
1368
|
+
});
|
|
1369
|
+
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1370
|
+
...createReadyPr(),
|
|
1371
|
+
isConflicted: true,
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
await useCase.run({
|
|
1375
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1376
|
+
allowIssueCacheMinutes: 10,
|
|
1377
|
+
allowedIssueAuthors: [],
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1381
|
+
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1382
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1285
1383
|
});
|
|
1286
1384
|
});
|
|
1287
1385
|
});
|