github-issue-tower-defence-management 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +0 -2
- package/bin/adapter/entry-points/cli/index.js +0 -5
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/cli/projectConfig.js +0 -3
- package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +1 -3
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js +2 -1
- package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js.map +1 -1
- package/bin/adapter/repositories/GitHubIssueCheckpointRepository.js +37 -0
- package/bin/adapter/repositories/GitHubIssueCheckpointRepository.js.map +1 -0
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js +4 -2
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js.map +1 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -6
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/IssueRejectionEvaluator.js +0 -23
- package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +39 -69
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +3 -2
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +0 -43
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js +10 -2
- package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js.map +1 -1
- package/bin/domain/usecases/adapter-interfaces/IssueCheckpointRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/IssueCheckpointRepository.js.map +1 -0
- package/bin/domain/usecases/autoStatusCheckComments.js +1 -11
- package/bin/domain/usecases/autoStatusCheckComments.js.map +1 -1
- package/bin/domain/usecases/extractNextStepAgentFromComments.js +14 -0
- package/bin/domain/usecases/extractNextStepAgentFromComments.js.map +1 -0
- package/bin/domain/usecases/triagerAgentName.js +7 -0
- package/bin/domain/usecases/triagerAgentName.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +0 -2
- package/src/adapter/entry-points/cli/index.ts +0 -9
- package/src/adapter/entry-points/cli/projectConfig.ts +0 -8
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +0 -7
- package/src/adapter/entry-points/handlers/tokenExhaustionHandover.ts +2 -0
- package/src/adapter/repositories/GitHubIssueCheckpointRepository.test.ts +51 -0
- package/src/adapter/repositories/GitHubIssueCheckpointRepository.ts +47 -0
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.test.ts +26 -4
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.ts +5 -3
- package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +0 -28
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +0 -6
- package/src/domain/usecases/IssueRejectionEvaluator.test.ts +0 -119
- package/src/domain/usecases/IssueRejectionEvaluator.ts +0 -21
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +185 -327
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +68 -138
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +4 -4
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +11 -5
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +0 -313
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +1 -102
- package/src/domain/usecases/TokenExhaustionHandoverUseCase.test.ts +87 -3
- package/src/domain/usecases/TokenExhaustionHandoverUseCase.ts +14 -1
- package/src/domain/usecases/adapter-interfaces/IssueCheckpointRepository.ts +3 -0
- package/src/domain/usecases/autoStatusCheckComments.ts +0 -17
- package/src/domain/usecases/extractNextStepAgentFromComments.ts +13 -0
- package/src/domain/usecases/isHumanComment.test.ts +0 -13
- package/src/domain/usecases/triagerAgentName.ts +4 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/cli/projectConfig.d.ts +0 -1
- package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts.map +1 -1
- package/types/adapter/repositories/GitHubIssueCheckpointRepository.d.ts +8 -0
- package/types/adapter/repositories/GitHubIssueCheckpointRepository.d.ts.map +1 -0
- package/types/domain/usecases/CheckIssueReviewReadinessUseCase.d.ts.map +1 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +1 -3
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/IssueRejectionEvaluator.d.ts +0 -1
- package/types/domain/usecases/IssueRejectionEvaluator.d.ts.map +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +0 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts +0 -1
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts +3 -1
- package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/IssueCheckpointRepository.d.ts +4 -0
- package/types/domain/usecases/adapter-interfaces/IssueCheckpointRepository.d.ts.map +1 -0
- package/types/domain/usecases/autoStatusCheckComments.d.ts +0 -4
- package/types/domain/usecases/autoStatusCheckComments.d.ts.map +1 -1
- package/types/domain/usecases/extractNextStepAgentFromComments.d.ts +5 -0
- package/types/domain/usecases/extractNextStepAgentFromComments.d.ts.map +1 -0
- package/types/domain/usecases/triagerAgentName.d.ts +3 -0
- package/types/domain/usecases/triagerAgentName.d.ts.map +1 -0
- package/src/domain/usecases/TriagerApprovalDispatchUseCase.test.ts +0 -1051
- package/src/domain/usecases/TriagerApprovalDispatchUseCase.ts +0 -274
- package/src/domain/usecases/awaitingOwnerApprovalMessage.ts +0 -5
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.test.ts +0 -162
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.ts +0 -29
- package/src/domain/usecases/isWaitingForOwnerApproval.test.ts +0 -91
- package/src/domain/usecases/isWaitingForOwnerApproval.ts +0 -17
- package/src/domain/usecases/returnedToAwaitingWorkspaceMessage.ts +0 -5
|
@@ -154,7 +154,17 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
154
154
|
updateStatus: jest.fn(),
|
|
155
155
|
updateLabels: jest.fn().mockResolvedValue(undefined),
|
|
156
156
|
getOrCreateLabel: jest.fn().mockResolvedValue(undefined),
|
|
157
|
-
findRelatedOpenPRs: jest.fn()
|
|
157
|
+
findRelatedOpenPRs: jest.fn().mockResolvedValue([
|
|
158
|
+
{
|
|
159
|
+
url: 'https://github.com/user/repo/pull/1',
|
|
160
|
+
isConflicted: false,
|
|
161
|
+
isPassedAllCiJob: true,
|
|
162
|
+
isCiStateSuccess: true,
|
|
163
|
+
isResolvedAllReviewComments: true,
|
|
164
|
+
isBranchOutOfDate: false,
|
|
165
|
+
missingRequiredCheckNames: [],
|
|
166
|
+
},
|
|
167
|
+
]),
|
|
158
168
|
getOpenPullRequest: jest.fn(),
|
|
159
169
|
getPullRequestChangedFilePaths: jest.fn().mockResolvedValue([]),
|
|
160
170
|
approvePullRequest: jest.fn().mockResolvedValue(undefined),
|
|
@@ -248,7 +258,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
248
258
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
249
259
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
250
260
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
251
|
-
createMockComment({ content: 'From: :robot:
|
|
261
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
252
262
|
]);
|
|
253
263
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
254
264
|
{
|
|
@@ -350,7 +360,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
350
360
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
351
361
|
mockIssueRepository.get.mockResolvedValue(prIssue);
|
|
352
362
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
353
|
-
createMockComment({ content: 'From: :robot:
|
|
363
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
354
364
|
]);
|
|
355
365
|
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
356
366
|
url: 'https://github.com/user/repo/pull/77',
|
|
@@ -849,7 +859,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
849
859
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
850
860
|
createMockComment({
|
|
851
861
|
content:
|
|
852
|
-
'From: :robot:
|
|
862
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": "Fix the tests"}\n```',
|
|
853
863
|
}),
|
|
854
864
|
]);
|
|
855
865
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -892,7 +902,8 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
892
902
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
893
903
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
894
904
|
createMockComment({
|
|
895
|
-
content:
|
|
905
|
+
content:
|
|
906
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": null}\n```',
|
|
896
907
|
}),
|
|
897
908
|
]);
|
|
898
909
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -935,7 +946,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
935
946
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
936
947
|
createMockComment({
|
|
937
948
|
content:
|
|
938
|
-
'From: :robot:
|
|
949
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "llm-agent:chore", "nextStep": null}\n```',
|
|
939
950
|
}),
|
|
940
951
|
]);
|
|
941
952
|
|
|
@@ -1197,7 +1208,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1197
1208
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1198
1209
|
createMockComment({
|
|
1199
1210
|
content:
|
|
1200
|
-
'From: :robot:
|
|
1211
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "llm-agent:impl", "nextStep": null}\n```',
|
|
1201
1212
|
}),
|
|
1202
1213
|
]);
|
|
1203
1214
|
|
|
@@ -1224,7 +1235,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1224
1235
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1225
1236
|
createMockComment({
|
|
1226
1237
|
content:
|
|
1227
|
-
'From: :robot:
|
|
1238
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": null, "nextStep": null}\n```',
|
|
1228
1239
|
}),
|
|
1229
1240
|
]);
|
|
1230
1241
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -1269,7 +1280,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1269
1280
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1270
1281
|
createMockComment({
|
|
1271
1282
|
content:
|
|
1272
|
-
'From: :robot:
|
|
1283
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "llm-agent:new-agent", "nextStep": null}\n```',
|
|
1273
1284
|
}),
|
|
1274
1285
|
]);
|
|
1275
1286
|
|
|
@@ -1298,7 +1309,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1298
1309
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1299
1310
|
createMockComment({
|
|
1300
1311
|
content:
|
|
1301
|
-
'From: :robot:
|
|
1312
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "llm-agent:impl", "nextStep": null}\n```',
|
|
1302
1313
|
}),
|
|
1303
1314
|
]);
|
|
1304
1315
|
|
|
@@ -1326,7 +1337,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1326
1337
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1327
1338
|
createMockComment({
|
|
1328
1339
|
content:
|
|
1329
|
-
'From: :robot:
|
|
1340
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "", "nextStep": null}\n```',
|
|
1330
1341
|
}),
|
|
1331
1342
|
]);
|
|
1332
1343
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -1673,200 +1684,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1673
1684
|
);
|
|
1674
1685
|
});
|
|
1675
1686
|
|
|
1676
|
-
it('should
|
|
1677
|
-
const issue = createMockIssue({
|
|
1678
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1679
|
-
status: 'Preparation',
|
|
1680
|
-
});
|
|
1681
|
-
|
|
1682
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1683
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
1684
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1685
|
-
createMockComment({
|
|
1686
|
-
content:
|
|
1687
|
-
'From: :robot: Test report\n```json\n{"pullRequestRequired": false}\n```',
|
|
1688
|
-
}),
|
|
1689
|
-
]);
|
|
1690
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
1691
|
-
|
|
1692
|
-
await useCase.run({
|
|
1693
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1694
|
-
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
1695
|
-
thresholdForAutoReject: 3,
|
|
1696
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
1697
|
-
allowedIssueAuthors: ['test-user'],
|
|
1698
|
-
});
|
|
1699
|
-
|
|
1700
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1701
|
-
expect.anything(),
|
|
1702
|
-
expect.stringContaining('PULL_REQUEST_NOT_FOUND'),
|
|
1703
|
-
);
|
|
1704
|
-
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
1705
|
-
expect.objectContaining({
|
|
1706
|
-
status: 'Awaiting Workspace',
|
|
1707
|
-
}),
|
|
1708
|
-
mockProject,
|
|
1709
|
-
);
|
|
1710
|
-
});
|
|
1711
|
-
|
|
1712
|
-
it('should return the issue to Awaiting Workspace and say why when the last report declares pullRequestRequired as false', async () => {
|
|
1713
|
-
const issue = createMockIssue({
|
|
1714
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1715
|
-
status: 'Preparation',
|
|
1716
|
-
});
|
|
1717
|
-
|
|
1718
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1719
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
1720
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1721
|
-
createMockComment({
|
|
1722
|
-
content:
|
|
1723
|
-
'From: :robot: Test report\n```json\n{"pullRequestRequired": false, "nextStep": null}\n```',
|
|
1724
|
-
}),
|
|
1725
|
-
]);
|
|
1726
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
1727
|
-
|
|
1728
|
-
await useCase.run({
|
|
1729
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1730
|
-
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
1731
|
-
thresholdForAutoReject: 3,
|
|
1732
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
1733
|
-
allowedIssueAuthors: ['test-user'],
|
|
1734
|
-
});
|
|
1735
|
-
|
|
1736
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1737
|
-
mockProject,
|
|
1738
|
-
expect.objectContaining({ url: 'https://github.com/user/repo/issues/1' }),
|
|
1739
|
-
'awaiting-workspace-id',
|
|
1740
|
-
);
|
|
1741
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1742
|
-
expect.objectContaining({ url: 'https://github.com/user/repo/issues/1' }),
|
|
1743
|
-
expect.stringContaining(
|
|
1744
|
-
'Auto Status Check: RETURNED_TO_AWAITING_WORKSPACE',
|
|
1745
|
-
),
|
|
1746
|
-
);
|
|
1747
|
-
});
|
|
1748
|
-
|
|
1749
|
-
it('should take the Awaiting Quality Check path when the declaration arrives again after an earlier return to Awaiting Workspace', async () => {
|
|
1750
|
-
const issue = createMockIssue({
|
|
1751
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1752
|
-
status: 'Preparation',
|
|
1753
|
-
});
|
|
1754
|
-
|
|
1755
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1756
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
1757
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1758
|
-
createMockComment({
|
|
1759
|
-
content:
|
|
1760
|
-
'Auto Status Check: RETURNED_TO_AWAITING_WORKSPACE\nThe report declared that this task needs no pull request.',
|
|
1761
|
-
}),
|
|
1762
|
-
createMockComment({
|
|
1763
|
-
content:
|
|
1764
|
-
'From: :robot: Test report\n```json\n{"pullRequestRequired": false, "nextStep": null}\n```',
|
|
1765
|
-
}),
|
|
1766
|
-
]);
|
|
1767
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
1768
|
-
|
|
1769
|
-
await useCase.run({
|
|
1770
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1771
|
-
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
1772
|
-
thresholdForAutoReject: 3,
|
|
1773
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
1774
|
-
allowedIssueAuthors: ['test-user'],
|
|
1775
|
-
});
|
|
1776
|
-
|
|
1777
|
-
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
1778
|
-
expect.objectContaining({
|
|
1779
|
-
status: 'Awaiting Quality Check',
|
|
1780
|
-
}),
|
|
1781
|
-
mockProject,
|
|
1782
|
-
);
|
|
1783
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1784
|
-
expect.anything(),
|
|
1785
|
-
expect.stringContaining(
|
|
1786
|
-
'Auto Status Check: RETURNED_TO_AWAITING_WORKSPACE',
|
|
1787
|
-
),
|
|
1788
|
-
);
|
|
1789
|
-
});
|
|
1790
|
-
|
|
1791
|
-
it('should take the Awaiting Quality Check path when a later report omits the next step agent an earlier report declared', async () => {
|
|
1792
|
-
const issue = createMockIssue({
|
|
1793
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1794
|
-
status: 'Preparation',
|
|
1795
|
-
});
|
|
1796
|
-
|
|
1797
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1798
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
1799
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1800
|
-
createMockComment({
|
|
1801
|
-
content:
|
|
1802
|
-
'From: :robot: Test report\n```json\n{"nextStepAgent": "pr-reviewer"}\n```',
|
|
1803
|
-
}),
|
|
1804
|
-
createMockComment({
|
|
1805
|
-
content:
|
|
1806
|
-
'Auto Status Check: RETURNED_TO_AWAITING_WORKSPACE\nThe report declared that this task needs no pull request.',
|
|
1807
|
-
}),
|
|
1808
|
-
createMockComment({
|
|
1809
|
-
content:
|
|
1810
|
-
'From: :robot: Test report\n```json\n{"pullRequestRequired": false, "reviewResult": "PASS", "nextStep": null}\n```',
|
|
1811
|
-
}),
|
|
1812
|
-
]);
|
|
1813
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
1814
|
-
|
|
1815
|
-
await useCase.run({
|
|
1816
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1817
|
-
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
1818
|
-
thresholdForAutoReject: 3,
|
|
1819
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
1820
|
-
allowedIssueAuthors: ['test-user'],
|
|
1821
|
-
});
|
|
1822
|
-
|
|
1823
|
-
expect(mockIssueRepository.setIssueAgentField).not.toHaveBeenCalled();
|
|
1824
|
-
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
1825
|
-
expect.objectContaining({
|
|
1826
|
-
status: 'Awaiting Quality Check',
|
|
1827
|
-
}),
|
|
1828
|
-
mockProject,
|
|
1829
|
-
);
|
|
1830
|
-
});
|
|
1831
|
-
|
|
1832
|
-
it('should still return the issue to Awaiting Workspace when the earlier return comment came from an untrusted author', async () => {
|
|
1833
|
-
const issue = createMockIssue({
|
|
1834
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1835
|
-
status: 'Preparation',
|
|
1836
|
-
});
|
|
1837
|
-
|
|
1838
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1839
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
1840
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1841
|
-
createMockComment({
|
|
1842
|
-
author: 'attacker',
|
|
1843
|
-
content:
|
|
1844
|
-
'Auto Status Check: RETURNED_TO_AWAITING_WORKSPACE\nInjected by someone who is not the agent bot.',
|
|
1845
|
-
}),
|
|
1846
|
-
createMockComment({
|
|
1847
|
-
author: 'trusted-bot',
|
|
1848
|
-
content:
|
|
1849
|
-
'From: :robot: Test report\n```json\n{"pullRequestRequired": false, "nextStep": null}\n```',
|
|
1850
|
-
}),
|
|
1851
|
-
]);
|
|
1852
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
1853
|
-
|
|
1854
|
-
await useCase.run({
|
|
1855
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1856
|
-
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
1857
|
-
thresholdForAutoReject: 3,
|
|
1858
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
1859
|
-
allowedIssueAuthors: ['trusted-bot'],
|
|
1860
|
-
});
|
|
1861
|
-
|
|
1862
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1863
|
-
mockProject,
|
|
1864
|
-
expect.objectContaining({ url: 'https://github.com/user/repo/issues/1' }),
|
|
1865
|
-
'awaiting-workspace-id',
|
|
1866
|
-
);
|
|
1867
|
-
});
|
|
1868
|
-
|
|
1869
|
-
it('should still reject a draft PR when the last report declares pullRequestRequired as false', async () => {
|
|
1687
|
+
it('should reject a draft PR', async () => {
|
|
1870
1688
|
const issue = createMockIssue({
|
|
1871
1689
|
url: 'https://github.com/user/repo/issues/1',
|
|
1872
1690
|
status: 'Preparation',
|
|
@@ -2557,7 +2375,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
2557
2375
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
2558
2376
|
mockIssueRepository.get.mockResolvedValue(prIssue);
|
|
2559
2377
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
2560
|
-
createMockComment({ content: 'From: :robot:
|
|
2378
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
2561
2379
|
]);
|
|
2562
2380
|
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
2563
2381
|
url: 'https://github.com/user/repo/pull/10',
|
|
@@ -2773,7 +2591,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
2773
2591
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
2774
2592
|
mockIssueRepository.get.mockResolvedValue(prIssue);
|
|
2775
2593
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
2776
|
-
createMockComment({ content: 'From: :robot:
|
|
2594
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
2777
2595
|
]);
|
|
2778
2596
|
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
2779
2597
|
url: prUrl,
|
|
@@ -3204,7 +3022,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3204
3022
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
3205
3023
|
mockIssueRepository.get.mockResolvedValue(prIssue);
|
|
3206
3024
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3207
|
-
createMockComment({ content: 'From: :robot:
|
|
3025
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
3208
3026
|
]);
|
|
3209
3027
|
mockIssueRepository.getOpenPullRequest.mockResolvedValue(null);
|
|
3210
3028
|
|
|
@@ -3239,7 +3057,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3239
3057
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
3240
3058
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3241
3059
|
createMockComment({
|
|
3242
|
-
content: 'From: :robot:
|
|
3060
|
+
content: 'From: :robot: agent (model)\n```json\n{invalid json}\n```',
|
|
3243
3061
|
}),
|
|
3244
3062
|
]);
|
|
3245
3063
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -3278,7 +3096,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3278
3096
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
3279
3097
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3280
3098
|
createMockComment({
|
|
3281
|
-
content: 'From: :robot:
|
|
3099
|
+
content: 'From: :robot: agent (model)\n```json\nnull\n```',
|
|
3282
3100
|
}),
|
|
3283
3101
|
]);
|
|
3284
3102
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -3318,7 +3136,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3318
3136
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3319
3137
|
createMockComment({
|
|
3320
3138
|
content:
|
|
3321
|
-
'From: :robot:
|
|
3139
|
+
'From: :robot: agent (model)\n```json\n{"status": "done", "result": "success"}\n```',
|
|
3322
3140
|
}),
|
|
3323
3141
|
]);
|
|
3324
3142
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -3357,7 +3175,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3357
3175
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
3358
3176
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3359
3177
|
createMockComment({
|
|
3360
|
-
content: 'From: :robot:
|
|
3178
|
+
content: 'From: :robot: agent (model)\n```json\n"just a string"\n```',
|
|
3361
3179
|
}),
|
|
3362
3180
|
]);
|
|
3363
3181
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
@@ -3686,7 +3504,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3686
3504
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
3687
3505
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
3688
3506
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3689
|
-
createMockComment({ content: 'From: :robot:
|
|
3507
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
3690
3508
|
]);
|
|
3691
3509
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
3692
3510
|
{
|
|
@@ -3883,7 +3701,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
3883
3701
|
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
3884
3702
|
mockIssueRepository.get.mockResolvedValue(issue);
|
|
3885
3703
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
3886
|
-
createMockComment({ content: 'From: :robot:
|
|
3704
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
3887
3705
|
]);
|
|
3888
3706
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
3889
3707
|
|
|
@@ -4002,7 +3820,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4002
3820
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4003
3821
|
createMockComment({
|
|
4004
3822
|
content:
|
|
4005
|
-
'From: :robot: agent (model)\n```json\n{"nextStep":
|
|
3823
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": null, "nextStepAgent": "impl"}\n```',
|
|
4006
3824
|
}),
|
|
4007
3825
|
]);
|
|
4008
3826
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
@@ -4030,7 +3848,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4030
3848
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4031
3849
|
createMockComment({
|
|
4032
3850
|
content:
|
|
4033
|
-
'From: :robot: agent (model)\n```json\n{"nextStep":
|
|
3851
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": null, "nextStepAgent": "impl"}\n```',
|
|
4034
3852
|
}),
|
|
4035
3853
|
createMockComment({
|
|
4036
3854
|
content:
|
|
@@ -4058,7 +3876,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4058
3876
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4059
3877
|
createMockComment({
|
|
4060
3878
|
content:
|
|
4061
|
-
'From: :robot: agent (model)\n```json\n{"nextStep":
|
|
3879
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": null, "nextStepAgent": "chore"}\n```',
|
|
4062
3880
|
}),
|
|
4063
3881
|
]);
|
|
4064
3882
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
@@ -4132,7 +3950,7 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4132
3950
|
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4133
3951
|
createMockComment({
|
|
4134
3952
|
content:
|
|
4135
|
-
'From: :robot: agent (model)\n```json\n{"nextStep":
|
|
3953
|
+
'From: :robot: agent (model)\n```json\n{"nextStep": null, "nextStepAgent": "impl"}\n```',
|
|
4136
3954
|
}),
|
|
4137
3955
|
]);
|
|
4138
3956
|
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
@@ -4847,73 +4665,6 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4847
4665
|
describe('waitingForOwnerApproval', () => {
|
|
4848
4666
|
const issueUrl = 'https://github.com/user/repo/issues/1';
|
|
4849
4667
|
|
|
4850
|
-
it('moves to Awaiting Quality Check and posts AWAITING_OWNER_APPROVAL message when last report declares waitingForOwnerApproval', async () => {
|
|
4851
|
-
const issue = createMockIssue({ url: issueUrl, status: 'Preparation' });
|
|
4852
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
4853
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
4854
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4855
|
-
createMockComment({
|
|
4856
|
-
content:
|
|
4857
|
-
'From: :robot: systems-analyst (model)\n```json\n{"pullRequestRequired": false, "waitingForOwnerApproval": true}\n```',
|
|
4858
|
-
}),
|
|
4859
|
-
]);
|
|
4860
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
4861
|
-
|
|
4862
|
-
await useCase.run({
|
|
4863
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
4864
|
-
issueUrl,
|
|
4865
|
-
thresholdForAutoReject: 3,
|
|
4866
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
4867
|
-
allowedIssueAuthors: ['test-user'],
|
|
4868
|
-
});
|
|
4869
|
-
|
|
4870
|
-
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
4871
|
-
expect.objectContaining({ status: 'Awaiting Quality Check' }),
|
|
4872
|
-
mockProject,
|
|
4873
|
-
);
|
|
4874
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
4875
|
-
mockProject,
|
|
4876
|
-
expect.objectContaining({ status: 'Awaiting Quality Check' }),
|
|
4877
|
-
'awaiting-quality-check-id',
|
|
4878
|
-
);
|
|
4879
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
4880
|
-
expect.objectContaining({ url: issueUrl }),
|
|
4881
|
-
expect.stringContaining('Auto Status Check: AWAITING_OWNER_APPROVAL'),
|
|
4882
|
-
);
|
|
4883
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalledWith(
|
|
4884
|
-
mockProject,
|
|
4885
|
-
expect.anything(),
|
|
4886
|
-
'failed-preparation-id',
|
|
4887
|
-
);
|
|
4888
|
-
});
|
|
4889
|
-
|
|
4890
|
-
it('does not return the issue to the dispatch pool when it is waiting for owner approval', async () => {
|
|
4891
|
-
const issue = createMockIssue({ url: issueUrl, status: 'Preparation' });
|
|
4892
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
4893
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
4894
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4895
|
-
createMockComment({
|
|
4896
|
-
content:
|
|
4897
|
-
'From: :robot: systems-analyst (model)\n```json\n{"pullRequestRequired": false, "waitingForOwnerApproval": true}\n```',
|
|
4898
|
-
}),
|
|
4899
|
-
]);
|
|
4900
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
4901
|
-
|
|
4902
|
-
await useCase.run({
|
|
4903
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
4904
|
-
issueUrl,
|
|
4905
|
-
thresholdForAutoReject: 3,
|
|
4906
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
4907
|
-
allowedIssueAuthors: ['test-user'],
|
|
4908
|
-
});
|
|
4909
|
-
|
|
4910
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalledWith(
|
|
4911
|
-
mockProject,
|
|
4912
|
-
expect.anything(),
|
|
4913
|
-
'awaiting-workspace-id',
|
|
4914
|
-
);
|
|
4915
|
-
});
|
|
4916
|
-
|
|
4917
4668
|
it('writes no status at all when the project has no Awaiting Quality Check option', async () => {
|
|
4918
4669
|
const projectWithoutQualityCheck = {
|
|
4919
4670
|
...mockProject,
|
|
@@ -4947,48 +4698,6 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
4947
4698
|
|
|
4948
4699
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(0);
|
|
4949
4700
|
});
|
|
4950
|
-
|
|
4951
|
-
it('escalates to Failed Preparation after ownerApprovalTimeoutCycles AWAITING_OWNER_APPROVAL messages', async () => {
|
|
4952
|
-
const issue = createMockIssue({ url: issueUrl, status: 'Preparation' });
|
|
4953
|
-
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
4954
|
-
mockIssueRepository.get.mockResolvedValue(issue);
|
|
4955
|
-
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
4956
|
-
createMockComment({
|
|
4957
|
-
content:
|
|
4958
|
-
'From: :robot: systems-analyst (model)\n```json\n{"pullRequestRequired": false, "waitingForOwnerApproval": true}\n```',
|
|
4959
|
-
}),
|
|
4960
|
-
createMockComment({
|
|
4961
|
-
content:
|
|
4962
|
-
'Auto Status Check: AWAITING_OWNER_APPROVAL\nThe last report declared that this task is waiting for owner approval. Returning to Awaiting Workspace for the next cycle.',
|
|
4963
|
-
}),
|
|
4964
|
-
createMockComment({
|
|
4965
|
-
content:
|
|
4966
|
-
'Auto Status Check: AWAITING_OWNER_APPROVAL\nThe last report declared that this task is waiting for owner approval. Returning to Awaiting Workspace for the next cycle.',
|
|
4967
|
-
}),
|
|
4968
|
-
]);
|
|
4969
|
-
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
4970
|
-
|
|
4971
|
-
await useCase.run({
|
|
4972
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
4973
|
-
issueUrl,
|
|
4974
|
-
thresholdForAutoReject: 3,
|
|
4975
|
-
workflowBlockerResolvedWebhookUrl: null,
|
|
4976
|
-
allowedIssueAuthors: ['test-user'],
|
|
4977
|
-
ownerApprovalTimeoutCycles: 2,
|
|
4978
|
-
});
|
|
4979
|
-
|
|
4980
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
4981
|
-
mockProject,
|
|
4982
|
-
expect.anything(),
|
|
4983
|
-
'failed-preparation-id',
|
|
4984
|
-
);
|
|
4985
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
4986
|
-
expect.anything(),
|
|
4987
|
-
expect.stringContaining(
|
|
4988
|
-
'Owner approval was not received after 2 cycles. Moving to Failed Preparation.',
|
|
4989
|
-
),
|
|
4990
|
-
);
|
|
4991
|
-
});
|
|
4992
4701
|
});
|
|
4993
4702
|
|
|
4994
4703
|
describe('non-developer agent CI failure reassignment', () => {
|
|
@@ -5336,4 +5045,153 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
5336
5045
|
expect(mockIssueRepository.setIssueAgentField).not.toHaveBeenCalled();
|
|
5337
5046
|
});
|
|
5338
5047
|
});
|
|
5048
|
+
describe('routing a finished preparation by the designated next step agent', () => {
|
|
5049
|
+
const projectWithAgent = () =>
|
|
5050
|
+
createMockProject({
|
|
5051
|
+
agent: {
|
|
5052
|
+
name: AGENT_FIELD_NAME,
|
|
5053
|
+
fieldId: 'agent-field-id',
|
|
5054
|
+
options: [
|
|
5055
|
+
{ id: 'opt-impl', name: 'impl', color: 'GRAY', description: '' },
|
|
5056
|
+
],
|
|
5057
|
+
},
|
|
5058
|
+
});
|
|
5059
|
+
|
|
5060
|
+
it('should move the issue to Awaiting Quality Check without touching the agent field when no next step agent is designated', async () => {
|
|
5061
|
+
const issue = createMockIssue({ status: 'Preparation' });
|
|
5062
|
+
mockProjectRepository.getByUrl.mockResolvedValue(projectWithAgent());
|
|
5063
|
+
mockIssueRepository.get.mockResolvedValue(issue);
|
|
5064
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
5065
|
+
createMockComment({ content: 'From: :robot: agent (model)' }),
|
|
5066
|
+
]);
|
|
5067
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
5068
|
+
{
|
|
5069
|
+
url: 'https://github.com/user/repo/pull/1',
|
|
5070
|
+
isConflicted: false,
|
|
5071
|
+
isPassedAllCiJob: true,
|
|
5072
|
+
isCiStateSuccess: true,
|
|
5073
|
+
isResolvedAllReviewComments: true,
|
|
5074
|
+
isBranchOutOfDate: false,
|
|
5075
|
+
missingRequiredCheckNames: [],
|
|
5076
|
+
},
|
|
5077
|
+
]);
|
|
5078
|
+
|
|
5079
|
+
await useCase.run({
|
|
5080
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
5081
|
+
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
5082
|
+
thresholdForAutoReject: 3,
|
|
5083
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
5084
|
+
allowedIssueAuthors: ['test-user'],
|
|
5085
|
+
});
|
|
5086
|
+
|
|
5087
|
+
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
5088
|
+
expect.objectContaining({ status: 'Awaiting Quality Check' }),
|
|
5089
|
+
expect.anything(),
|
|
5090
|
+
);
|
|
5091
|
+
expect(mockIssueRepository.setIssueAgentField).not.toHaveBeenCalled();
|
|
5092
|
+
});
|
|
5093
|
+
|
|
5094
|
+
it('should set the agent field and return the issue to Awaiting Workspace when a next step agent is designated', async () => {
|
|
5095
|
+
const project = projectWithAgent();
|
|
5096
|
+
const issue = createMockIssue({ status: 'Preparation' });
|
|
5097
|
+
mockProjectRepository.getByUrl.mockResolvedValue(project);
|
|
5098
|
+
mockIssueRepository.get.mockResolvedValue(issue);
|
|
5099
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
5100
|
+
createMockComment({
|
|
5101
|
+
content:
|
|
5102
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "impl"}\n```',
|
|
5103
|
+
}),
|
|
5104
|
+
]);
|
|
5105
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
5106
|
+
{
|
|
5107
|
+
url: 'https://github.com/user/repo/pull/1',
|
|
5108
|
+
isConflicted: false,
|
|
5109
|
+
isPassedAllCiJob: true,
|
|
5110
|
+
isCiStateSuccess: true,
|
|
5111
|
+
isResolvedAllReviewComments: true,
|
|
5112
|
+
isBranchOutOfDate: false,
|
|
5113
|
+
missingRequiredCheckNames: [],
|
|
5114
|
+
},
|
|
5115
|
+
]);
|
|
5116
|
+
|
|
5117
|
+
await useCase.run({
|
|
5118
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
5119
|
+
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
5120
|
+
thresholdForAutoReject: 3,
|
|
5121
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
5122
|
+
allowedIssueAuthors: ['test-user'],
|
|
5123
|
+
});
|
|
5124
|
+
|
|
5125
|
+
expect(mockIssueRepository.setIssueAgentField).toHaveBeenCalledWith(
|
|
5126
|
+
'https://github.com/user/repo/issues/1',
|
|
5127
|
+
project,
|
|
5128
|
+
'opt-impl',
|
|
5129
|
+
);
|
|
5130
|
+
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
5131
|
+
expect.objectContaining({ status: 'Awaiting Workspace' }),
|
|
5132
|
+
project,
|
|
5133
|
+
);
|
|
5134
|
+
});
|
|
5135
|
+
|
|
5136
|
+
it('should waive the missing pull request rejection when the designated next step agent is the triager', async () => {
|
|
5137
|
+
const issue = createMockIssue({ status: 'Preparation' });
|
|
5138
|
+
mockProjectRepository.getByUrl.mockResolvedValue(projectWithAgent());
|
|
5139
|
+
mockIssueRepository.get.mockResolvedValue(issue);
|
|
5140
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
5141
|
+
createMockComment({
|
|
5142
|
+
content:
|
|
5143
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "triager"}\n```',
|
|
5144
|
+
}),
|
|
5145
|
+
]);
|
|
5146
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
5147
|
+
|
|
5148
|
+
await useCase.run({
|
|
5149
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
5150
|
+
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
5151
|
+
thresholdForAutoReject: 3,
|
|
5152
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
5153
|
+
allowedIssueAuthors: ['test-user'],
|
|
5154
|
+
});
|
|
5155
|
+
|
|
5156
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
5157
|
+
expect.anything(),
|
|
5158
|
+
expect.stringContaining('PULL_REQUEST_NOT_FOUND'),
|
|
5159
|
+
);
|
|
5160
|
+
expect(mockIssueRepository.update).toHaveBeenCalledWith(
|
|
5161
|
+
expect.objectContaining({ status: 'Awaiting Workspace' }),
|
|
5162
|
+
expect.anything(),
|
|
5163
|
+
);
|
|
5164
|
+
});
|
|
5165
|
+
|
|
5166
|
+
it('should keep the missing pull request rejection when the designated next step agent is not the triager', async () => {
|
|
5167
|
+
const issue = createMockIssue({ status: 'Preparation' });
|
|
5168
|
+
mockProjectRepository.getByUrl.mockResolvedValue(projectWithAgent());
|
|
5169
|
+
mockIssueRepository.get.mockResolvedValue(issue);
|
|
5170
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
5171
|
+
createMockComment({
|
|
5172
|
+
content:
|
|
5173
|
+
'From: :robot: agent (model)\n```json\n{"nextStepAgent": "impl"}\n```',
|
|
5174
|
+
}),
|
|
5175
|
+
]);
|
|
5176
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
|
|
5177
|
+
|
|
5178
|
+
await useCase.run({
|
|
5179
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
5180
|
+
issueUrl: 'https://github.com/user/repo/issues/1',
|
|
5181
|
+
thresholdForAutoReject: 3,
|
|
5182
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
5183
|
+
allowedIssueAuthors: ['test-user'],
|
|
5184
|
+
});
|
|
5185
|
+
|
|
5186
|
+
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
5187
|
+
expect.anything(),
|
|
5188
|
+
expect.stringContaining('PULL_REQUEST_NOT_FOUND'),
|
|
5189
|
+
);
|
|
5190
|
+
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
5191
|
+
expect.anything(),
|
|
5192
|
+
expect.anything(),
|
|
5193
|
+
'awaiting-workspace-id',
|
|
5194
|
+
);
|
|
5195
|
+
});
|
|
5196
|
+
});
|
|
5339
5197
|
});
|