github-issue-tower-defence-management 1.174.2 → 1.175.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/bin/adapter/entry-points/console/consoleDoneStore.js +0 -2
- package/bin/adapter/entry-points/console/consoleDoneStore.js.map +1 -1
- package/bin/adapter/entry-points/console/consoleTabNames.js +0 -1
- package/bin/adapter/entry-points/console/consoleTabNames.js.map +1 -1
- package/bin/adapter/entry-points/console/dashboardComposeService.js +2 -4
- package/bin/adapter/entry-points/console/dashboardComposeService.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-g4SqIzCh.js → index-BhDothvr.js} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/domain/entities/WorkflowStatus.js +1 -6
- package/bin/domain/entities/WorkflowStatus.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +4 -5
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +0 -39
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +4 -5
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/SetupTowerDefenceProjectUseCase.js +15 -1
- package/bin/domain/usecases/SetupTowerDefenceProjectUseCase.js.map +1 -1
- package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js +0 -2
- package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js.map +1 -1
- package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js +2 -3
- package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js.map +1 -1
- package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js +0 -1
- package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js.map +1 -1
- package/bin/domain/usecases/findLastAgentDeclaringReport.js +12 -0
- package/bin/domain/usecases/findLastAgentDeclaringReport.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/console/consoleDoneStore.ts +0 -2
- package/src/adapter/entry-points/console/consoleTabNames.ts +0 -1
- package/src/adapter/entry-points/console/dashboardComposeService.test.ts +4 -8
- package/src/adapter/entry-points/console/dashboardComposeService.ts +1 -3
- package/src/adapter/entry-points/console/dashboardEmitterComposerKey.test.ts +12 -17
- package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +4 -32
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +1 -18
- package/src/adapter/entry-points/console/ui/src/features/console/components/layout/ConsoleTabList.stories.tsx +3 -7
- package/src/adapter/entry-points/console/ui/src/features/console/components/layout/ConsoleTabList.test.tsx +2 -4
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleNavigation.test.ts +6 -8
- package/src/adapter/entry-points/console/ui/src/features/console/logic/tabAdvance.test.ts +8 -17
- package/src/adapter/entry-points/console/ui/src/features/console/logic/types.ts +0 -2
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +3 -3
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +5 -6
- package/src/adapter/entry-points/console/ui-dist/assets/{index-g4SqIzCh.js → index-BhDothvr.js} +1 -1
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/console/webServer.test.ts +4 -6
- package/src/adapter/entry-points/handlers/consoleListsWriter.test.ts +30 -26
- package/src/adapter/entry-points/handlers/dashboardRowWriter.test.ts +5 -6
- package/src/domain/entities/WorkflowStatus.ts +0 -5
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +32 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +7 -8
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +198 -863
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +0 -68
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +8 -11
- package/src/domain/usecases/SetupTowerDefenceProjectUseCase.test.ts +89 -51
- package/src/domain/usecases/SetupTowerDefenceProjectUseCase.ts +30 -2
- package/src/domain/usecases/console/GenerateConsoleListsUseCase.test.ts +62 -72
- package/src/domain/usecases/console/GenerateConsoleListsUseCase.ts +0 -8
- package/src/domain/usecases/dashboard/ComposeDashboardUseCase.test.ts +19 -28
- package/src/domain/usecases/dashboard/ComposeDashboardUseCase.ts +2 -3
- package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.test.ts +11 -12
- package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.ts +0 -3
- package/src/domain/usecases/findLastAgentDeclaringReport.test.ts +71 -0
- package/src/domain/usecases/findLastAgentDeclaringReport.ts +17 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +2 -2
- package/types/adapter/entry-points/console/consoleDoneStore.d.ts.map +1 -1
- package/types/adapter/entry-points/console/consoleTabNames.d.ts.map +1 -1
- package/types/adapter/entry-points/console/dashboardComposeService.d.ts.map +1 -1
- package/types/domain/entities/WorkflowStatus.d.ts +0 -1
- package/types/domain/entities/WorkflowStatus.d.ts.map +1 -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.map +1 -1
- package/types/domain/usecases/SetupTowerDefenceProjectUseCase.d.ts +1 -0
- package/types/domain/usecases/SetupTowerDefenceProjectUseCase.d.ts.map +1 -1
- package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts +1 -2
- package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/dashboard/ComposeDashboardUseCase.d.ts.map +1 -1
- package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts +0 -1
- package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts.map +1 -1
- package/types/domain/usecases/findLastAgentDeclaringReport.d.ts +5 -0
- package/types/domain/usecases/findLastAgentDeclaringReport.d.ts.map +1 -0
|
@@ -24,12 +24,6 @@ const createMockProject = (overrides: Partial<Project> = {}): Project => ({
|
|
|
24
24
|
color: 'BLUE',
|
|
25
25
|
description: '',
|
|
26
26
|
},
|
|
27
|
-
{
|
|
28
|
-
id: 'unread-id',
|
|
29
|
-
name: 'Unread',
|
|
30
|
-
color: 'ORANGE',
|
|
31
|
-
description: '',
|
|
32
|
-
},
|
|
33
27
|
],
|
|
34
28
|
},
|
|
35
29
|
nextActionDate: null,
|
|
@@ -90,7 +84,7 @@ const createMockIssue = (overrides: Partial<Issue> = {}): Issue => ({
|
|
|
90
84
|
const createMockPullRequest = (overrides: Partial<Issue> = {}): Issue =>
|
|
91
85
|
createMockIssue({
|
|
92
86
|
title: 'Test PR',
|
|
93
|
-
status: '
|
|
87
|
+
status: 'Awaiting Workspace',
|
|
94
88
|
url: 'https://github.com/user/repo/pull/1',
|
|
95
89
|
isPr: true,
|
|
96
90
|
...overrides,
|
|
@@ -1142,39 +1136,43 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1142
1136
|
});
|
|
1143
1137
|
});
|
|
1144
1138
|
|
|
1145
|
-
describe('
|
|
1146
|
-
|
|
1147
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1148
|
-
project: mockProject,
|
|
1149
|
-
issues: [
|
|
1150
|
-
createMockPullRequest({ status: 'Awaiting Workspace' }),
|
|
1151
|
-
createMockPullRequest({ status: 'Preparation' }),
|
|
1152
|
-
],
|
|
1153
|
-
cacheUsed: false,
|
|
1154
|
-
});
|
|
1139
|
+
describe('archived project item containment', () => {
|
|
1140
|
+
let warnSpy: jest.SpyInstance;
|
|
1155
1141
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
allowedIssueAuthors: ['owner'],
|
|
1160
|
-
});
|
|
1142
|
+
beforeEach(() => {
|
|
1143
|
+
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
1144
|
+
});
|
|
1161
1145
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1146
|
+
afterEach(() => {
|
|
1147
|
+
warnSpy.mockRestore();
|
|
1165
1148
|
});
|
|
1166
1149
|
|
|
1167
|
-
it('should skip
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1170
|
-
isPr: false,
|
|
1150
|
+
it('should skip an archived issue on updateStatus failure and continue with remaining issues', async () => {
|
|
1151
|
+
const archivedIssue = createMockIssue({
|
|
1152
|
+
number: 1,
|
|
1171
1153
|
url: 'https://github.com/user/repo/issues/1',
|
|
1154
|
+
itemId: 'archived-item',
|
|
1155
|
+
status: 'Awaiting Quality Check',
|
|
1156
|
+
});
|
|
1157
|
+
const normalIssue = createMockIssue({
|
|
1158
|
+
number: 2,
|
|
1159
|
+
url: 'https://github.com/user/repo/issues/2',
|
|
1160
|
+
itemId: 'normal-item',
|
|
1161
|
+
status: 'Awaiting Quality Check',
|
|
1172
1162
|
});
|
|
1173
1163
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1174
1164
|
project: mockProject,
|
|
1175
|
-
issues: [
|
|
1165
|
+
issues: [archivedIssue, normalIssue],
|
|
1176
1166
|
cacheUsed: false,
|
|
1177
1167
|
});
|
|
1168
|
+
mockIssueRepository.updateStatus.mockImplementation(
|
|
1169
|
+
(_project: Project, issue: Issue) =>
|
|
1170
|
+
issue.url === archivedIssue.url
|
|
1171
|
+
? Promise.reject(
|
|
1172
|
+
new Error('The item is archived and cannot be updated'),
|
|
1173
|
+
)
|
|
1174
|
+
: Promise.resolve(undefined),
|
|
1175
|
+
);
|
|
1178
1176
|
|
|
1179
1177
|
await useCase.run({
|
|
1180
1178
|
manager: 'manager-user',
|
|
@@ -1182,49 +1180,86 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1182
1180
|
allowedIssueAuthors: ['owner'],
|
|
1183
1181
|
});
|
|
1184
1182
|
|
|
1185
|
-
expect(mockIssueRepository.updateStatus).
|
|
1186
|
-
|
|
1187
|
-
|
|
1183
|
+
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1184
|
+
mockProject,
|
|
1185
|
+
archivedIssue,
|
|
1186
|
+
'awaiting-workspace-id',
|
|
1187
|
+
);
|
|
1188
|
+
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1189
|
+
mockProject,
|
|
1190
|
+
normalIssue,
|
|
1191
|
+
'awaiting-workspace-id',
|
|
1192
|
+
);
|
|
1193
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1194
|
+
archivedIssue,
|
|
1195
|
+
expect.anything(),
|
|
1196
|
+
);
|
|
1197
|
+
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1198
|
+
normalIssue,
|
|
1199
|
+
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1200
|
+
);
|
|
1201
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
1202
|
+
expect.stringContaining(archivedIssue.url),
|
|
1203
|
+
);
|
|
1188
1204
|
});
|
|
1189
1205
|
|
|
1190
|
-
it('should
|
|
1191
|
-
const
|
|
1192
|
-
status: '
|
|
1193
|
-
labels: [],
|
|
1194
|
-
agent: 'chore',
|
|
1206
|
+
it('should propagate a non-archived updateStatus error for issues unchanged', async () => {
|
|
1207
|
+
const issue = createMockIssue({
|
|
1208
|
+
status: 'Awaiting Quality Check',
|
|
1195
1209
|
});
|
|
1196
1210
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1197
1211
|
project: mockProject,
|
|
1198
|
-
issues: [
|
|
1212
|
+
issues: [issue],
|
|
1199
1213
|
cacheUsed: false,
|
|
1200
1214
|
});
|
|
1215
|
+
mockIssueRepository.updateStatus.mockRejectedValue(
|
|
1216
|
+
new Error('Something went wrong'),
|
|
1217
|
+
);
|
|
1201
1218
|
|
|
1202
|
-
await
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1219
|
+
await expect(
|
|
1220
|
+
useCase.run({
|
|
1221
|
+
manager: 'manager-user',
|
|
1222
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1223
|
+
allowedIssueAuthors: ['owner'],
|
|
1224
|
+
}),
|
|
1225
|
+
).rejects.toThrow('Something went wrong');
|
|
1207
1226
|
|
|
1208
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1209
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1210
1227
|
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1211
1228
|
});
|
|
1212
1229
|
|
|
1213
|
-
it('should
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1230
|
+
it('should skip an archived Awaiting Quality Check pull request on updateStatus failure and continue with remaining pull requests', async () => {
|
|
1231
|
+
const archivedPullRequest = createMockPullRequest({
|
|
1232
|
+
number: 1,
|
|
1233
|
+
url: 'https://github.com/user/repo/pull/1',
|
|
1234
|
+
itemId: 'archived-pr-item',
|
|
1235
|
+
status: 'Awaiting Quality Check',
|
|
1236
|
+
});
|
|
1237
|
+
const normalPullRequest = createMockPullRequest({
|
|
1238
|
+
number: 2,
|
|
1239
|
+
url: 'https://github.com/user/repo/pull/2',
|
|
1240
|
+
itemId: 'normal-pr-item',
|
|
1241
|
+
status: 'Awaiting Quality Check',
|
|
1218
1242
|
});
|
|
1219
1243
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1220
1244
|
project: mockProject,
|
|
1221
|
-
issues: [
|
|
1245
|
+
issues: [archivedPullRequest, normalPullRequest],
|
|
1222
1246
|
cacheUsed: false,
|
|
1223
1247
|
});
|
|
1224
|
-
mockIssueRepository.getOpenPullRequest.
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1248
|
+
mockIssueRepository.getOpenPullRequest.mockImplementation(
|
|
1249
|
+
(prUrl: string) =>
|
|
1250
|
+
Promise.resolve({
|
|
1251
|
+
...createReadyPr(prUrl),
|
|
1252
|
+
isConflicted: true,
|
|
1253
|
+
}),
|
|
1254
|
+
);
|
|
1255
|
+
mockIssueRepository.updateStatus.mockImplementation(
|
|
1256
|
+
(_project: Project, issue: Issue) =>
|
|
1257
|
+
issue.url === archivedPullRequest.url
|
|
1258
|
+
? Promise.reject(
|
|
1259
|
+
new Error('The item is archived and cannot be updated'),
|
|
1260
|
+
)
|
|
1261
|
+
: Promise.resolve(undefined),
|
|
1262
|
+
);
|
|
1228
1263
|
|
|
1229
1264
|
await useCase.run({
|
|
1230
1265
|
manager: 'manager-user',
|
|
@@ -1234,50 +1269,105 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1234
1269
|
|
|
1235
1270
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1236
1271
|
mockProject,
|
|
1237
|
-
|
|
1272
|
+
archivedPullRequest,
|
|
1273
|
+
'awaiting-workspace-id',
|
|
1274
|
+
);
|
|
1275
|
+
expect(mockIssueRepository.updateStory).not.toHaveBeenCalledWith(
|
|
1276
|
+
expect.anything(),
|
|
1277
|
+
archivedPullRequest,
|
|
1278
|
+
expect.anything(),
|
|
1279
|
+
);
|
|
1280
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1281
|
+
archivedPullRequest,
|
|
1282
|
+
expect.anything(),
|
|
1283
|
+
);
|
|
1284
|
+
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1285
|
+
mockProject,
|
|
1286
|
+
normalPullRequest,
|
|
1238
1287
|
'awaiting-workspace-id',
|
|
1239
1288
|
);
|
|
1240
1289
|
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1241
|
-
|
|
1242
|
-
expect.stringContaining('
|
|
1290
|
+
normalPullRequest,
|
|
1291
|
+
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1292
|
+
);
|
|
1293
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
1294
|
+
expect.stringContaining(archivedPullRequest.url),
|
|
1243
1295
|
);
|
|
1244
1296
|
});
|
|
1245
1297
|
|
|
1246
|
-
it('should
|
|
1298
|
+
it('should propagate a non-archived updateStatus error for Awaiting Quality Check pull requests unchanged', async () => {
|
|
1247
1299
|
const pullRequest = createMockPullRequest({
|
|
1248
|
-
status: '
|
|
1300
|
+
status: 'Awaiting Quality Check',
|
|
1249
1301
|
});
|
|
1250
1302
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1251
1303
|
project: mockProject,
|
|
1252
1304
|
issues: [pullRequest],
|
|
1253
1305
|
cacheUsed: false,
|
|
1254
1306
|
});
|
|
1255
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue(
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
manager: 'manager-user',
|
|
1259
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1260
|
-
allowedIssueAuthors: ['owner'],
|
|
1307
|
+
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1308
|
+
...createReadyPr(),
|
|
1309
|
+
isConflicted: true,
|
|
1261
1310
|
});
|
|
1311
|
+
mockIssueRepository.updateStatus.mockRejectedValue(
|
|
1312
|
+
new Error('Something went wrong'),
|
|
1313
|
+
);
|
|
1314
|
+
|
|
1315
|
+
await expect(
|
|
1316
|
+
useCase.run({
|
|
1317
|
+
manager: 'manager-user',
|
|
1318
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1319
|
+
allowedIssueAuthors: ['owner'],
|
|
1320
|
+
}),
|
|
1321
|
+
).rejects.toThrow('Something went wrong');
|
|
1262
1322
|
|
|
1263
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1264
1323
|
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1265
1324
|
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1266
1325
|
});
|
|
1326
|
+
});
|
|
1267
1327
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1328
|
+
describe('ky TimeoutError containment', () => {
|
|
1329
|
+
let warnSpy: jest.SpyInstance;
|
|
1330
|
+
|
|
1331
|
+
const createKyTimeoutError = (): Error => {
|
|
1332
|
+
const error = new Error(
|
|
1333
|
+
'Request timed out: POST https://api.github.com/graphql',
|
|
1334
|
+
);
|
|
1335
|
+
error.name = 'TimeoutError';
|
|
1336
|
+
return error;
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
beforeEach(() => {
|
|
1340
|
+
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
afterEach(() => {
|
|
1344
|
+
warnSpy.mockRestore();
|
|
1345
|
+
});
|
|
1346
|
+
|
|
1347
|
+
it('should skip an issue whose updateStatus times out and continue with remaining issues', async () => {
|
|
1348
|
+
const timedOutIssue = createMockIssue({
|
|
1349
|
+
number: 1,
|
|
1350
|
+
url: 'https://github.com/user/repo/issues/1',
|
|
1351
|
+
itemId: 'timed-out-item',
|
|
1352
|
+
status: 'Awaiting Quality Check',
|
|
1353
|
+
});
|
|
1354
|
+
const normalIssue = createMockIssue({
|
|
1355
|
+
number: 2,
|
|
1356
|
+
url: 'https://github.com/user/repo/issues/2',
|
|
1357
|
+
itemId: 'normal-item',
|
|
1358
|
+
status: 'Awaiting Quality Check',
|
|
1271
1359
|
});
|
|
1272
1360
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1273
1361
|
project: mockProject,
|
|
1274
|
-
issues: [
|
|
1362
|
+
issues: [timedOutIssue, normalIssue],
|
|
1275
1363
|
cacheUsed: false,
|
|
1276
1364
|
});
|
|
1277
|
-
mockIssueRepository.
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1365
|
+
mockIssueRepository.updateStatus.mockImplementation(
|
|
1366
|
+
(_project: Project, issue: Issue) =>
|
|
1367
|
+
issue.url === timedOutIssue.url
|
|
1368
|
+
? Promise.reject(createKyTimeoutError())
|
|
1369
|
+
: Promise.resolve(undefined),
|
|
1370
|
+
);
|
|
1281
1371
|
|
|
1282
1372
|
await useCase.run({
|
|
1283
1373
|
manager: 'manager-user',
|
|
@@ -1287,762 +1377,43 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
1287
1377
|
|
|
1288
1378
|
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1289
1379
|
mockProject,
|
|
1290
|
-
|
|
1380
|
+
timedOutIssue,
|
|
1291
1381
|
'awaiting-workspace-id',
|
|
1292
1382
|
);
|
|
1293
|
-
expect(mockIssueRepository.
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
'
|
|
1383
|
+
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1384
|
+
mockProject,
|
|
1385
|
+
normalIssue,
|
|
1386
|
+
'awaiting-workspace-id',
|
|
1387
|
+
);
|
|
1388
|
+
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1389
|
+
timedOutIssue,
|
|
1390
|
+
expect.anything(),
|
|
1297
1391
|
);
|
|
1298
1392
|
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1299
|
-
|
|
1393
|
+
normalIssue,
|
|
1300
1394
|
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1301
1395
|
);
|
|
1302
|
-
expect(
|
|
1303
|
-
|
|
1304
|
-
expect.stringContaining('PULL_REQUEST_CONFLICTED'),
|
|
1396
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
1397
|
+
expect.stringContaining(timedOutIssue.url),
|
|
1305
1398
|
);
|
|
1306
1399
|
});
|
|
1307
1400
|
|
|
1308
|
-
it('should
|
|
1309
|
-
const
|
|
1310
|
-
|
|
1401
|
+
it('should skip an issue whose createComment times out and continue with remaining issues', async () => {
|
|
1402
|
+
const timedOutIssue = createMockIssue({
|
|
1403
|
+
number: 1,
|
|
1404
|
+
url: 'https://github.com/user/repo/issues/1',
|
|
1405
|
+
itemId: 'timed-out-item',
|
|
1406
|
+
status: 'Awaiting Quality Check',
|
|
1407
|
+
});
|
|
1408
|
+
const normalIssue = createMockIssue({
|
|
1409
|
+
number: 2,
|
|
1410
|
+
url: 'https://github.com/user/repo/issues/2',
|
|
1411
|
+
itemId: 'normal-item',
|
|
1412
|
+
status: 'Awaiting Quality Check',
|
|
1311
1413
|
});
|
|
1312
1414
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1313
1415
|
project: mockProject,
|
|
1314
|
-
issues: [
|
|
1315
|
-
cacheUsed: false,
|
|
1316
|
-
});
|
|
1317
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1318
|
-
...createReadyPr(),
|
|
1319
|
-
isPassedAllCiJob: false,
|
|
1320
|
-
isCiStateSuccess: false,
|
|
1321
|
-
});
|
|
1322
|
-
|
|
1323
|
-
await useCase.run({
|
|
1324
|
-
manager: 'manager-user',
|
|
1325
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1326
|
-
allowedIssueAuthors: ['owner'],
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1330
|
-
mockProject,
|
|
1331
|
-
pullRequest,
|
|
1332
|
-
'awaiting-workspace-id',
|
|
1333
|
-
);
|
|
1334
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1335
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1336
|
-
pullRequest,
|
|
1337
|
-
'workflow-management-story-id',
|
|
1338
|
-
);
|
|
1339
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1340
|
-
pullRequest,
|
|
1341
|
-
expect.stringContaining('ANY_CI_JOB_FAILED_OR_IN_PROGRESS'),
|
|
1342
|
-
);
|
|
1343
|
-
});
|
|
1344
|
-
|
|
1345
|
-
it('should move Unread pull request when it is in draft state', async () => {
|
|
1346
|
-
const pullRequest = createMockPullRequest({
|
|
1347
|
-
status: 'Unread',
|
|
1348
|
-
});
|
|
1349
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1350
|
-
project: mockProject,
|
|
1351
|
-
issues: [pullRequest],
|
|
1352
|
-
cacheUsed: false,
|
|
1353
|
-
});
|
|
1354
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1355
|
-
...createReadyPr(),
|
|
1356
|
-
isDraft: true,
|
|
1357
|
-
});
|
|
1358
|
-
|
|
1359
|
-
await useCase.run({
|
|
1360
|
-
manager: 'manager-user',
|
|
1361
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1362
|
-
allowedIssueAuthors: ['owner'],
|
|
1363
|
-
});
|
|
1364
|
-
|
|
1365
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1366
|
-
mockProject,
|
|
1367
|
-
pullRequest,
|
|
1368
|
-
'awaiting-workspace-id',
|
|
1369
|
-
);
|
|
1370
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1371
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1372
|
-
pullRequest,
|
|
1373
|
-
'workflow-management-story-id',
|
|
1374
|
-
);
|
|
1375
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1376
|
-
pullRequest,
|
|
1377
|
-
expect.stringContaining('PULL_REQUEST_IS_DRAFT'),
|
|
1378
|
-
);
|
|
1379
|
-
});
|
|
1380
|
-
|
|
1381
|
-
it('should move Unread pull request when CI is SUCCESS but required check never started', async () => {
|
|
1382
|
-
const pullRequest = createMockPullRequest({
|
|
1383
|
-
status: 'Unread',
|
|
1384
|
-
});
|
|
1385
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1386
|
-
project: mockProject,
|
|
1387
|
-
issues: [pullRequest],
|
|
1388
|
-
cacheUsed: false,
|
|
1389
|
-
});
|
|
1390
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1391
|
-
...createReadyPr(),
|
|
1392
|
-
isPassedAllCiJob: false,
|
|
1393
|
-
isCiStateSuccess: true,
|
|
1394
|
-
missingRequiredCheckNames: ['E2E Tests'],
|
|
1395
|
-
});
|
|
1396
|
-
|
|
1397
|
-
await useCase.run({
|
|
1398
|
-
manager: 'manager-user',
|
|
1399
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1400
|
-
allowedIssueAuthors: ['owner'],
|
|
1401
|
-
});
|
|
1402
|
-
|
|
1403
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1404
|
-
mockProject,
|
|
1405
|
-
pullRequest,
|
|
1406
|
-
'awaiting-workspace-id',
|
|
1407
|
-
);
|
|
1408
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1409
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1410
|
-
pullRequest,
|
|
1411
|
-
'workflow-management-story-id',
|
|
1412
|
-
);
|
|
1413
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1414
|
-
pullRequest,
|
|
1415
|
-
expect.stringContaining('REQUIRED_CI_JOB_NEVER_STARTED'),
|
|
1416
|
-
);
|
|
1417
|
-
});
|
|
1418
|
-
|
|
1419
|
-
it('should move Unread pull request when review comments are not resolved', async () => {
|
|
1420
|
-
const pullRequest = createMockPullRequest({
|
|
1421
|
-
status: 'Unread',
|
|
1422
|
-
});
|
|
1423
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1424
|
-
project: mockProject,
|
|
1425
|
-
issues: [pullRequest],
|
|
1426
|
-
cacheUsed: false,
|
|
1427
|
-
});
|
|
1428
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1429
|
-
...createReadyPr(),
|
|
1430
|
-
isResolvedAllReviewComments: false,
|
|
1431
|
-
});
|
|
1432
|
-
|
|
1433
|
-
await useCase.run({
|
|
1434
|
-
manager: 'manager-user',
|
|
1435
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1436
|
-
allowedIssueAuthors: ['owner'],
|
|
1437
|
-
});
|
|
1438
|
-
|
|
1439
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1440
|
-
mockProject,
|
|
1441
|
-
pullRequest,
|
|
1442
|
-
'awaiting-workspace-id',
|
|
1443
|
-
);
|
|
1444
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1445
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1446
|
-
pullRequest,
|
|
1447
|
-
'workflow-management-story-id',
|
|
1448
|
-
);
|
|
1449
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1450
|
-
pullRequest,
|
|
1451
|
-
expect.stringContaining('ANY_REVIEW_COMMENT_NOT_RESOLVED'),
|
|
1452
|
-
);
|
|
1453
|
-
});
|
|
1454
|
-
|
|
1455
|
-
it('should move Unread pull request when no open PR is found at the PR URL', async () => {
|
|
1456
|
-
const pullRequest = createMockPullRequest({
|
|
1457
|
-
status: 'Unread',
|
|
1458
|
-
});
|
|
1459
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1460
|
-
project: mockProject,
|
|
1461
|
-
issues: [pullRequest],
|
|
1462
|
-
cacheUsed: false,
|
|
1463
|
-
});
|
|
1464
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue(null);
|
|
1465
|
-
|
|
1466
|
-
await useCase.run({
|
|
1467
|
-
manager: 'manager-user',
|
|
1468
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1469
|
-
allowedIssueAuthors: ['owner'],
|
|
1470
|
-
});
|
|
1471
|
-
|
|
1472
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1473
|
-
mockProject,
|
|
1474
|
-
pullRequest,
|
|
1475
|
-
'awaiting-workspace-id',
|
|
1476
|
-
);
|
|
1477
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1478
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1479
|
-
pullRequest,
|
|
1480
|
-
'workflow-management-story-id',
|
|
1481
|
-
);
|
|
1482
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1483
|
-
pullRequest,
|
|
1484
|
-
expect.stringContaining('PULL_REQUEST_NOT_FOUND'),
|
|
1485
|
-
);
|
|
1486
|
-
});
|
|
1487
|
-
|
|
1488
|
-
it('should skip updateStory when project has no story field configured', async () => {
|
|
1489
|
-
const projectWithoutStory = createMockProject({ story: null });
|
|
1490
|
-
mockProjectRepository.getProject.mockResolvedValue(projectWithoutStory);
|
|
1491
|
-
|
|
1492
|
-
const pullRequest = createMockPullRequest({
|
|
1493
|
-
status: 'Unread',
|
|
1494
|
-
});
|
|
1495
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1496
|
-
project: mockProject,
|
|
1497
|
-
issues: [pullRequest],
|
|
1498
|
-
cacheUsed: false,
|
|
1499
|
-
});
|
|
1500
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1501
|
-
...createReadyPr(),
|
|
1502
|
-
isConflicted: true,
|
|
1503
|
-
});
|
|
1504
|
-
|
|
1505
|
-
await useCase.run({
|
|
1506
|
-
manager: 'manager-user',
|
|
1507
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1508
|
-
allowedIssueAuthors: ['owner'],
|
|
1509
|
-
});
|
|
1510
|
-
|
|
1511
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1512
|
-
projectWithoutStory,
|
|
1513
|
-
pullRequest,
|
|
1514
|
-
'awaiting-workspace-id',
|
|
1515
|
-
);
|
|
1516
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1517
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1518
|
-
pullRequest,
|
|
1519
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1520
|
-
);
|
|
1521
|
-
});
|
|
1522
|
-
|
|
1523
|
-
it('should return early when Awaiting Workspace status option does not exist', async () => {
|
|
1524
|
-
const projectWithoutAwaitingWorkspace = createMockProject({
|
|
1525
|
-
status: {
|
|
1526
|
-
name: 'Status',
|
|
1527
|
-
fieldId: 'field-1',
|
|
1528
|
-
statuses: [
|
|
1529
|
-
{
|
|
1530
|
-
id: 'unread-id',
|
|
1531
|
-
name: 'Unread',
|
|
1532
|
-
color: 'ORANGE',
|
|
1533
|
-
description: '',
|
|
1534
|
-
},
|
|
1535
|
-
],
|
|
1536
|
-
},
|
|
1537
|
-
});
|
|
1538
|
-
mockProjectRepository.getProject.mockResolvedValue(
|
|
1539
|
-
projectWithoutAwaitingWorkspace,
|
|
1540
|
-
);
|
|
1541
|
-
|
|
1542
|
-
const pullRequest = createMockPullRequest({
|
|
1543
|
-
status: 'Unread',
|
|
1544
|
-
});
|
|
1545
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1546
|
-
project: mockProject,
|
|
1547
|
-
issues: [pullRequest],
|
|
1548
|
-
cacheUsed: false,
|
|
1549
|
-
});
|
|
1550
|
-
|
|
1551
|
-
await useCase.run({
|
|
1552
|
-
manager: 'manager-user',
|
|
1553
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1554
|
-
allowedIssueAuthors: ['owner'],
|
|
1555
|
-
});
|
|
1556
|
-
|
|
1557
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1558
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1559
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1560
|
-
});
|
|
1561
|
-
|
|
1562
|
-
describe('author authorization guard', () => {
|
|
1563
|
-
it('should skip an Unread pull request authored by a non-owner human not in allowedIssueAuthors', async () => {
|
|
1564
|
-
const pullRequest = createMockPullRequest({
|
|
1565
|
-
status: 'Unread',
|
|
1566
|
-
author: 'outside-contributor',
|
|
1567
|
-
});
|
|
1568
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1569
|
-
project: mockProject,
|
|
1570
|
-
issues: [pullRequest],
|
|
1571
|
-
cacheUsed: false,
|
|
1572
|
-
});
|
|
1573
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1574
|
-
...createReadyPr(),
|
|
1575
|
-
isConflicted: true,
|
|
1576
|
-
});
|
|
1577
|
-
|
|
1578
|
-
await useCase.run({
|
|
1579
|
-
manager: 'manager-user',
|
|
1580
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1581
|
-
allowedIssueAuthors: ['owner'],
|
|
1582
|
-
});
|
|
1583
|
-
|
|
1584
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1585
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1586
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1587
|
-
});
|
|
1588
|
-
|
|
1589
|
-
it('should act on an Unread pull request authored by an allowed owner', async () => {
|
|
1590
|
-
const pullRequest = createMockPullRequest({
|
|
1591
|
-
status: 'Unread',
|
|
1592
|
-
author: 'owner',
|
|
1593
|
-
});
|
|
1594
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1595
|
-
project: mockProject,
|
|
1596
|
-
issues: [pullRequest],
|
|
1597
|
-
cacheUsed: false,
|
|
1598
|
-
});
|
|
1599
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1600
|
-
...createReadyPr(),
|
|
1601
|
-
isConflicted: true,
|
|
1602
|
-
});
|
|
1603
|
-
|
|
1604
|
-
await useCase.run({
|
|
1605
|
-
manager: 'manager-user',
|
|
1606
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1607
|
-
allowedIssueAuthors: ['owner'],
|
|
1608
|
-
});
|
|
1609
|
-
|
|
1610
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1611
|
-
mockProject,
|
|
1612
|
-
pullRequest,
|
|
1613
|
-
'awaiting-workspace-id',
|
|
1614
|
-
);
|
|
1615
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1616
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1617
|
-
pullRequest,
|
|
1618
|
-
'workflow-management-story-id',
|
|
1619
|
-
);
|
|
1620
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1621
|
-
pullRequest,
|
|
1622
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1623
|
-
);
|
|
1624
|
-
});
|
|
1625
|
-
|
|
1626
|
-
it('should skip an Unread pull request authored by a dependency-update bot not in allowedIssueAuthors', async () => {
|
|
1627
|
-
const pullRequest = createMockPullRequest({
|
|
1628
|
-
status: 'Unread',
|
|
1629
|
-
author: 'dependabot[bot]',
|
|
1630
|
-
});
|
|
1631
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1632
|
-
project: mockProject,
|
|
1633
|
-
issues: [pullRequest],
|
|
1634
|
-
cacheUsed: false,
|
|
1635
|
-
});
|
|
1636
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1637
|
-
...createReadyPr(),
|
|
1638
|
-
isConflicted: true,
|
|
1639
|
-
});
|
|
1640
|
-
|
|
1641
|
-
await useCase.run({
|
|
1642
|
-
manager: 'manager-user',
|
|
1643
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1644
|
-
allowedIssueAuthors: ['owner'],
|
|
1645
|
-
});
|
|
1646
|
-
|
|
1647
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1648
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1649
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1650
|
-
});
|
|
1651
|
-
|
|
1652
|
-
it('should act on a dependency-update bot only when it is explicitly listed in allowedIssueAuthors', async () => {
|
|
1653
|
-
const pullRequest = createMockPullRequest({
|
|
1654
|
-
status: 'Unread',
|
|
1655
|
-
author: 'dependabot[bot]',
|
|
1656
|
-
});
|
|
1657
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1658
|
-
project: mockProject,
|
|
1659
|
-
issues: [pullRequest],
|
|
1660
|
-
cacheUsed: false,
|
|
1661
|
-
});
|
|
1662
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1663
|
-
...createReadyPr(),
|
|
1664
|
-
isConflicted: true,
|
|
1665
|
-
});
|
|
1666
|
-
|
|
1667
|
-
await useCase.run({
|
|
1668
|
-
manager: 'manager-user',
|
|
1669
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1670
|
-
allowedIssueAuthors: ['owner', 'dependabot[bot]'],
|
|
1671
|
-
});
|
|
1672
|
-
|
|
1673
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1674
|
-
mockProject,
|
|
1675
|
-
pullRequest,
|
|
1676
|
-
'awaiting-workspace-id',
|
|
1677
|
-
);
|
|
1678
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1679
|
-
pullRequest,
|
|
1680
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1681
|
-
);
|
|
1682
|
-
});
|
|
1683
|
-
|
|
1684
|
-
it('should process no author when allowedIssueAuthors is null', async () => {
|
|
1685
|
-
const pullRequest = createMockPullRequest({
|
|
1686
|
-
status: 'Unread',
|
|
1687
|
-
author: 'outside-contributor',
|
|
1688
|
-
});
|
|
1689
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1690
|
-
project: mockProject,
|
|
1691
|
-
issues: [pullRequest],
|
|
1692
|
-
cacheUsed: false,
|
|
1693
|
-
});
|
|
1694
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1695
|
-
...createReadyPr(),
|
|
1696
|
-
isConflicted: true,
|
|
1697
|
-
});
|
|
1698
|
-
|
|
1699
|
-
await useCase.run({
|
|
1700
|
-
manager: 'manager-user',
|
|
1701
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1702
|
-
allowedIssueAuthors: null,
|
|
1703
|
-
});
|
|
1704
|
-
|
|
1705
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1706
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1707
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1708
|
-
});
|
|
1709
|
-
|
|
1710
|
-
it('should process no author when allowedIssueAuthors is undefined', async () => {
|
|
1711
|
-
const pullRequest = createMockPullRequest({
|
|
1712
|
-
status: 'Unread',
|
|
1713
|
-
author: 'owner',
|
|
1714
|
-
});
|
|
1715
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1716
|
-
project: mockProject,
|
|
1717
|
-
issues: [pullRequest],
|
|
1718
|
-
cacheUsed: false,
|
|
1719
|
-
});
|
|
1720
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1721
|
-
...createReadyPr(),
|
|
1722
|
-
isConflicted: true,
|
|
1723
|
-
});
|
|
1724
|
-
|
|
1725
|
-
await useCase.run({
|
|
1726
|
-
manager: 'manager-user',
|
|
1727
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1728
|
-
});
|
|
1729
|
-
|
|
1730
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1731
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1732
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1733
|
-
});
|
|
1734
|
-
|
|
1735
|
-
it('should process no author when allowedIssueAuthors is an empty list', async () => {
|
|
1736
|
-
const pullRequest = createMockPullRequest({
|
|
1737
|
-
status: 'Unread',
|
|
1738
|
-
author: 'owner',
|
|
1739
|
-
});
|
|
1740
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1741
|
-
project: mockProject,
|
|
1742
|
-
issues: [pullRequest],
|
|
1743
|
-
cacheUsed: false,
|
|
1744
|
-
});
|
|
1745
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1746
|
-
...createReadyPr(),
|
|
1747
|
-
isConflicted: true,
|
|
1748
|
-
});
|
|
1749
|
-
|
|
1750
|
-
await useCase.run({
|
|
1751
|
-
manager: 'manager-user',
|
|
1752
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1753
|
-
allowedIssueAuthors: [],
|
|
1754
|
-
});
|
|
1755
|
-
|
|
1756
|
-
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
1757
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1758
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1759
|
-
});
|
|
1760
|
-
});
|
|
1761
|
-
});
|
|
1762
|
-
|
|
1763
|
-
describe('archived project item containment', () => {
|
|
1764
|
-
let warnSpy: jest.SpyInstance;
|
|
1765
|
-
|
|
1766
|
-
beforeEach(() => {
|
|
1767
|
-
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
1768
|
-
});
|
|
1769
|
-
|
|
1770
|
-
afterEach(() => {
|
|
1771
|
-
warnSpy.mockRestore();
|
|
1772
|
-
});
|
|
1773
|
-
|
|
1774
|
-
it('should skip an archived issue on updateStatus failure and continue with remaining issues', async () => {
|
|
1775
|
-
const archivedIssue = createMockIssue({
|
|
1776
|
-
number: 1,
|
|
1777
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1778
|
-
itemId: 'archived-item',
|
|
1779
|
-
status: 'Awaiting Quality Check',
|
|
1780
|
-
});
|
|
1781
|
-
const normalIssue = createMockIssue({
|
|
1782
|
-
number: 2,
|
|
1783
|
-
url: 'https://github.com/user/repo/issues/2',
|
|
1784
|
-
itemId: 'normal-item',
|
|
1785
|
-
status: 'Awaiting Quality Check',
|
|
1786
|
-
});
|
|
1787
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1788
|
-
project: mockProject,
|
|
1789
|
-
issues: [archivedIssue, normalIssue],
|
|
1790
|
-
cacheUsed: false,
|
|
1791
|
-
});
|
|
1792
|
-
mockIssueRepository.updateStatus.mockImplementation(
|
|
1793
|
-
(_project: Project, issue: Issue) =>
|
|
1794
|
-
issue.url === archivedIssue.url
|
|
1795
|
-
? Promise.reject(
|
|
1796
|
-
new Error('The item is archived and cannot be updated'),
|
|
1797
|
-
)
|
|
1798
|
-
: Promise.resolve(undefined),
|
|
1799
|
-
);
|
|
1800
|
-
|
|
1801
|
-
await useCase.run({
|
|
1802
|
-
manager: 'manager-user',
|
|
1803
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1804
|
-
allowedIssueAuthors: ['owner'],
|
|
1805
|
-
});
|
|
1806
|
-
|
|
1807
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1808
|
-
mockProject,
|
|
1809
|
-
archivedIssue,
|
|
1810
|
-
'awaiting-workspace-id',
|
|
1811
|
-
);
|
|
1812
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1813
|
-
mockProject,
|
|
1814
|
-
normalIssue,
|
|
1815
|
-
'awaiting-workspace-id',
|
|
1816
|
-
);
|
|
1817
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1818
|
-
archivedIssue,
|
|
1819
|
-
expect.anything(),
|
|
1820
|
-
);
|
|
1821
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1822
|
-
normalIssue,
|
|
1823
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1824
|
-
);
|
|
1825
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1826
|
-
expect.stringContaining(archivedIssue.url),
|
|
1827
|
-
);
|
|
1828
|
-
});
|
|
1829
|
-
|
|
1830
|
-
it('should propagate a non-archived updateStatus error for issues unchanged', async () => {
|
|
1831
|
-
const issue = createMockIssue({
|
|
1832
|
-
status: 'Awaiting Quality Check',
|
|
1833
|
-
});
|
|
1834
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1835
|
-
project: mockProject,
|
|
1836
|
-
issues: [issue],
|
|
1837
|
-
cacheUsed: false,
|
|
1838
|
-
});
|
|
1839
|
-
mockIssueRepository.updateStatus.mockRejectedValue(
|
|
1840
|
-
new Error('Something went wrong'),
|
|
1841
|
-
);
|
|
1842
|
-
|
|
1843
|
-
await expect(
|
|
1844
|
-
useCase.run({
|
|
1845
|
-
manager: 'manager-user',
|
|
1846
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1847
|
-
allowedIssueAuthors: ['owner'],
|
|
1848
|
-
}),
|
|
1849
|
-
).rejects.toThrow('Something went wrong');
|
|
1850
|
-
|
|
1851
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1852
|
-
});
|
|
1853
|
-
|
|
1854
|
-
it('should skip an archived Unread pull request on updateStatus failure and continue with remaining pull requests', async () => {
|
|
1855
|
-
const archivedPullRequest = createMockPullRequest({
|
|
1856
|
-
number: 1,
|
|
1857
|
-
url: 'https://github.com/user/repo/pull/1',
|
|
1858
|
-
itemId: 'archived-pr-item',
|
|
1859
|
-
status: 'Unread',
|
|
1860
|
-
});
|
|
1861
|
-
const normalPullRequest = createMockPullRequest({
|
|
1862
|
-
number: 2,
|
|
1863
|
-
url: 'https://github.com/user/repo/pull/2',
|
|
1864
|
-
itemId: 'normal-pr-item',
|
|
1865
|
-
status: 'Unread',
|
|
1866
|
-
});
|
|
1867
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1868
|
-
project: mockProject,
|
|
1869
|
-
issues: [archivedPullRequest, normalPullRequest],
|
|
1870
|
-
cacheUsed: false,
|
|
1871
|
-
});
|
|
1872
|
-
mockIssueRepository.getOpenPullRequest.mockImplementation(
|
|
1873
|
-
(prUrl: string) =>
|
|
1874
|
-
Promise.resolve({
|
|
1875
|
-
...createReadyPr(prUrl),
|
|
1876
|
-
isConflicted: true,
|
|
1877
|
-
}),
|
|
1878
|
-
);
|
|
1879
|
-
mockIssueRepository.updateStatus.mockImplementation(
|
|
1880
|
-
(_project: Project, issue: Issue) =>
|
|
1881
|
-
issue.url === archivedPullRequest.url
|
|
1882
|
-
? Promise.reject(
|
|
1883
|
-
new Error('The item is archived and cannot be updated'),
|
|
1884
|
-
)
|
|
1885
|
-
: Promise.resolve(undefined),
|
|
1886
|
-
);
|
|
1887
|
-
|
|
1888
|
-
await useCase.run({
|
|
1889
|
-
manager: 'manager-user',
|
|
1890
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1891
|
-
allowedIssueAuthors: ['owner'],
|
|
1892
|
-
});
|
|
1893
|
-
|
|
1894
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1895
|
-
mockProject,
|
|
1896
|
-
archivedPullRequest,
|
|
1897
|
-
'awaiting-workspace-id',
|
|
1898
|
-
);
|
|
1899
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalledWith(
|
|
1900
|
-
expect.anything(),
|
|
1901
|
-
archivedPullRequest,
|
|
1902
|
-
expect.anything(),
|
|
1903
|
-
);
|
|
1904
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
1905
|
-
archivedPullRequest,
|
|
1906
|
-
expect.anything(),
|
|
1907
|
-
);
|
|
1908
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
1909
|
-
mockProject,
|
|
1910
|
-
normalPullRequest,
|
|
1911
|
-
'awaiting-workspace-id',
|
|
1912
|
-
);
|
|
1913
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
1914
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
1915
|
-
normalPullRequest,
|
|
1916
|
-
'workflow-management-story-id',
|
|
1917
|
-
);
|
|
1918
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
1919
|
-
normalPullRequest,
|
|
1920
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
1921
|
-
);
|
|
1922
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1923
|
-
expect.stringContaining(archivedPullRequest.url),
|
|
1924
|
-
);
|
|
1925
|
-
});
|
|
1926
|
-
|
|
1927
|
-
it('should propagate a non-archived updateStatus error for Unread pull requests unchanged', async () => {
|
|
1928
|
-
const pullRequest = createMockPullRequest({
|
|
1929
|
-
status: 'Unread',
|
|
1930
|
-
});
|
|
1931
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1932
|
-
project: mockProject,
|
|
1933
|
-
issues: [pullRequest],
|
|
1934
|
-
cacheUsed: false,
|
|
1935
|
-
});
|
|
1936
|
-
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1937
|
-
...createReadyPr(),
|
|
1938
|
-
isConflicted: true,
|
|
1939
|
-
});
|
|
1940
|
-
mockIssueRepository.updateStatus.mockRejectedValue(
|
|
1941
|
-
new Error('Something went wrong'),
|
|
1942
|
-
);
|
|
1943
|
-
|
|
1944
|
-
await expect(
|
|
1945
|
-
useCase.run({
|
|
1946
|
-
manager: 'manager-user',
|
|
1947
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1948
|
-
allowedIssueAuthors: ['owner'],
|
|
1949
|
-
}),
|
|
1950
|
-
).rejects.toThrow('Something went wrong');
|
|
1951
|
-
|
|
1952
|
-
expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
|
|
1953
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
1954
|
-
});
|
|
1955
|
-
});
|
|
1956
|
-
|
|
1957
|
-
describe('ky TimeoutError containment', () => {
|
|
1958
|
-
let warnSpy: jest.SpyInstance;
|
|
1959
|
-
|
|
1960
|
-
const createKyTimeoutError = (): Error => {
|
|
1961
|
-
const error = new Error(
|
|
1962
|
-
'Request timed out: POST https://api.github.com/graphql',
|
|
1963
|
-
);
|
|
1964
|
-
error.name = 'TimeoutError';
|
|
1965
|
-
return error;
|
|
1966
|
-
};
|
|
1967
|
-
|
|
1968
|
-
beforeEach(() => {
|
|
1969
|
-
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
1970
|
-
});
|
|
1971
|
-
|
|
1972
|
-
afterEach(() => {
|
|
1973
|
-
warnSpy.mockRestore();
|
|
1974
|
-
});
|
|
1975
|
-
|
|
1976
|
-
it('should skip an issue whose updateStatus times out and continue with remaining issues', async () => {
|
|
1977
|
-
const timedOutIssue = createMockIssue({
|
|
1978
|
-
number: 1,
|
|
1979
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
1980
|
-
itemId: 'timed-out-item',
|
|
1981
|
-
status: 'Awaiting Quality Check',
|
|
1982
|
-
});
|
|
1983
|
-
const normalIssue = createMockIssue({
|
|
1984
|
-
number: 2,
|
|
1985
|
-
url: 'https://github.com/user/repo/issues/2',
|
|
1986
|
-
itemId: 'normal-item',
|
|
1987
|
-
status: 'Awaiting Quality Check',
|
|
1988
|
-
});
|
|
1989
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1990
|
-
project: mockProject,
|
|
1991
|
-
issues: [timedOutIssue, normalIssue],
|
|
1992
|
-
cacheUsed: false,
|
|
1993
|
-
});
|
|
1994
|
-
mockIssueRepository.updateStatus.mockImplementation(
|
|
1995
|
-
(_project: Project, issue: Issue) =>
|
|
1996
|
-
issue.url === timedOutIssue.url
|
|
1997
|
-
? Promise.reject(createKyTimeoutError())
|
|
1998
|
-
: Promise.resolve(undefined),
|
|
1999
|
-
);
|
|
2000
|
-
|
|
2001
|
-
await useCase.run({
|
|
2002
|
-
manager: 'manager-user',
|
|
2003
|
-
projectUrl: 'https://github.com/users/user/projects/1',
|
|
2004
|
-
allowedIssueAuthors: ['owner'],
|
|
2005
|
-
});
|
|
2006
|
-
|
|
2007
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
2008
|
-
mockProject,
|
|
2009
|
-
timedOutIssue,
|
|
2010
|
-
'awaiting-workspace-id',
|
|
2011
|
-
);
|
|
2012
|
-
expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
|
|
2013
|
-
mockProject,
|
|
2014
|
-
normalIssue,
|
|
2015
|
-
'awaiting-workspace-id',
|
|
2016
|
-
);
|
|
2017
|
-
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalledWith(
|
|
2018
|
-
timedOutIssue,
|
|
2019
|
-
expect.anything(),
|
|
2020
|
-
);
|
|
2021
|
-
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
2022
|
-
normalIssue,
|
|
2023
|
-
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
2024
|
-
);
|
|
2025
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
2026
|
-
expect.stringContaining(timedOutIssue.url),
|
|
2027
|
-
);
|
|
2028
|
-
});
|
|
2029
|
-
|
|
2030
|
-
it('should skip an issue whose createComment times out and continue with remaining issues', async () => {
|
|
2031
|
-
const timedOutIssue = createMockIssue({
|
|
2032
|
-
number: 1,
|
|
2033
|
-
url: 'https://github.com/user/repo/issues/1',
|
|
2034
|
-
itemId: 'timed-out-item',
|
|
2035
|
-
status: 'Awaiting Quality Check',
|
|
2036
|
-
});
|
|
2037
|
-
const normalIssue = createMockIssue({
|
|
2038
|
-
number: 2,
|
|
2039
|
-
url: 'https://github.com/user/repo/issues/2',
|
|
2040
|
-
itemId: 'normal-item',
|
|
2041
|
-
status: 'Awaiting Quality Check',
|
|
2042
|
-
});
|
|
2043
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
2044
|
-
project: mockProject,
|
|
2045
|
-
issues: [timedOutIssue, normalIssue],
|
|
1416
|
+
issues: [timedOutIssue, normalIssue],
|
|
2046
1417
|
cacheUsed: false,
|
|
2047
1418
|
});
|
|
2048
1419
|
mockIssueCommentRepository.createComment.mockImplementation(
|
|
@@ -2067,18 +1438,18 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
2067
1438
|
);
|
|
2068
1439
|
});
|
|
2069
1440
|
|
|
2070
|
-
it('should skip an
|
|
1441
|
+
it('should skip an Awaiting Quality Check pull request whose updateStatus times out and continue with remaining pull requests', async () => {
|
|
2071
1442
|
const timedOutPullRequest = createMockPullRequest({
|
|
2072
1443
|
number: 1,
|
|
2073
1444
|
url: 'https://github.com/user/repo/pull/1',
|
|
2074
1445
|
itemId: 'timed-out-pr-item',
|
|
2075
|
-
status: '
|
|
1446
|
+
status: 'Awaiting Quality Check',
|
|
2076
1447
|
});
|
|
2077
1448
|
const normalPullRequest = createMockPullRequest({
|
|
2078
1449
|
number: 2,
|
|
2079
1450
|
url: 'https://github.com/user/repo/pull/2',
|
|
2080
1451
|
itemId: 'normal-pr-item',
|
|
2081
|
-
status: '
|
|
1452
|
+
status: 'Awaiting Quality Check',
|
|
2082
1453
|
});
|
|
2083
1454
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
2084
1455
|
project: mockProject,
|
|
@@ -2124,11 +1495,6 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
2124
1495
|
normalPullRequest,
|
|
2125
1496
|
'awaiting-workspace-id',
|
|
2126
1497
|
);
|
|
2127
|
-
expect(mockIssueRepository.updateStory).toHaveBeenCalledWith(
|
|
2128
|
-
expect.objectContaining({ id: 'project-1' }),
|
|
2129
|
-
normalPullRequest,
|
|
2130
|
-
'workflow-management-story-id',
|
|
2131
|
-
);
|
|
2132
1498
|
expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
|
|
2133
1499
|
normalPullRequest,
|
|
2134
1500
|
expect.stringContaining('Auto Status Check: REJECTED'),
|
|
@@ -2211,9 +1577,9 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
2211
1577
|
);
|
|
2212
1578
|
});
|
|
2213
1579
|
|
|
2214
|
-
it('should not revert a rejected
|
|
1580
|
+
it('should not revert a rejected Awaiting Quality Check pull request that is not assigned to the manager', async () => {
|
|
2215
1581
|
const pullRequest = createMockPullRequest({
|
|
2216
|
-
status: '
|
|
1582
|
+
status: 'Awaiting Quality Check',
|
|
2217
1583
|
assignees: ['other-user'],
|
|
2218
1584
|
});
|
|
2219
1585
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
@@ -2237,9 +1603,9 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
2237
1603
|
expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
|
|
2238
1604
|
});
|
|
2239
1605
|
|
|
2240
|
-
it('should revert a rejected
|
|
1606
|
+
it('should revert a rejected Awaiting Quality Check pull request that is assigned to the manager', async () => {
|
|
2241
1607
|
const pullRequest = createMockPullRequest({
|
|
2242
|
-
status: '
|
|
1608
|
+
status: 'Awaiting Quality Check',
|
|
2243
1609
|
assignees: ['manager-user'],
|
|
2244
1610
|
});
|
|
2245
1611
|
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
@@ -2335,37 +1701,6 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
|
|
|
2335
1701
|
expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
|
|
2336
1702
|
});
|
|
2337
1703
|
|
|
2338
|
-
it('includes the unread pull requests in the same batched call', async () => {
|
|
2339
|
-
const unreadPrUrl = 'https://github.com/user/repo/pull/400';
|
|
2340
|
-
const { boardIssues, relatedPrs } = buildAwaitingQualityCheckBoard(1);
|
|
2341
|
-
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
2342
|
-
project: mockProject,
|
|
2343
|
-
issues: [
|
|
2344
|
-
...boardIssues,
|
|
2345
|
-
createMockPullRequest({
|
|
2346
|
-
url: unreadPrUrl,
|
|
2347
|
-
number: 400,
|
|
2348
|
-
itemId: 'item-pr-unread',
|
|
2349
|
-
}),
|
|
2350
|
-
],
|
|
2351
|
-
cacheUsed: false,
|
|
2352
|
-
});
|
|
2353
|
-
resolveBatchFrom([...relatedPrs, createReadyPr(unreadPrUrl)]);
|
|
2354
|
-
|
|
2355
|
-
await useCase.run({
|
|
2356
|
-
projectUrl,
|
|
2357
|
-
manager: 'manager-user',
|
|
2358
|
-
allowedIssueAuthors: ['owner'],
|
|
2359
|
-
});
|
|
2360
|
-
|
|
2361
|
-
expect(mockIssueRepository.getOpenPullRequests).toHaveBeenCalledTimes(1);
|
|
2362
|
-
expect(mockIssueRepository.getOpenPullRequests).toHaveBeenCalledWith([
|
|
2363
|
-
relatedPrs[0].url,
|
|
2364
|
-
unreadPrUrl,
|
|
2365
|
-
]);
|
|
2366
|
-
expect(mockIssueRepository.getOpenPullRequest).not.toHaveBeenCalled();
|
|
2367
|
-
});
|
|
2368
|
-
|
|
2369
1704
|
it('falls back to the single pull request query only for a url the batch left unresolved', async () => {
|
|
2370
1705
|
const { boardIssues, relatedPrs } = buildAwaitingQualityCheckBoard(2);
|
|
2371
1706
|
const resolvedPr = relatedPrs[0];
|