github-issue-tower-defence-management 1.69.2 → 1.69.4
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/.github/workflows/api-created_issue_pr.yml +3 -0
- package/.github/workflows/codeql.yml +3 -0
- package/.github/workflows/commit-lint.yml +3 -0
- package/.github/workflows/create-pr.yml +3 -0
- package/.github/workflows/empty-format-test-job.yml +6 -0
- package/.github/workflows/format.yml +3 -0
- package/.github/workflows/publish.yml +3 -0
- package/.github/workflows/test.yml +3 -0
- package/.github/workflows/umino-project.yml +6 -0
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/bin/adapter/entry-points/cli/index.js +1 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +7 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +2 -2
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -0
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +33 -9
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.ts +1 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +2 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +2 -2
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +2 -0
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +262 -2
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +71 -13
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +1 -0
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts +3 -2
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevertOrphanedPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/RevertOrphanedPreparationUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"RevertOrphanedPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/RevertOrphanedPreparationUseCase.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -258,6 +258,7 @@ program
|
|
|
258
258
|
projectUrl,
|
|
259
259
|
allowIssueCacheMinutes,
|
|
260
260
|
preparationProcessCheckCommand,
|
|
261
|
+
thresholdForAutoReject: config.thresholdForAutoReject ?? 3,
|
|
261
262
|
awLogDirectoryPath: config.awLogDirectoryPath,
|
|
262
263
|
awLogStaleThresholdMinutes: config.awLogStaleThresholdMinutes,
|
|
263
264
|
});
|
|
@@ -103,6 +103,8 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
103
103
|
claudeCodeOauthTokenListJsonPath:
|
|
104
104
|
readmeConfig.claudeCodeOauthTokenListJsonPath ??
|
|
105
105
|
input.claudeCodeOauthTokenListJsonPath,
|
|
106
|
+
thresholdForAutoReject:
|
|
107
|
+
readmeConfig.thresholdForAutoReject ?? input.thresholdForAutoReject,
|
|
106
108
|
startPreparation: input.startPreparation
|
|
107
109
|
? {
|
|
108
110
|
...input.startPreparation,
|
|
@@ -884,14 +884,14 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
884
884
|
const responseData: unknown = await response.json();
|
|
885
885
|
if (!isIssueTimelineResponse(responseData)) {
|
|
886
886
|
throw new Error(
|
|
887
|
-
|
|
887
|
+
`Unexpected response shape when fetching issue timeline: ${issueUrl}`,
|
|
888
888
|
);
|
|
889
889
|
}
|
|
890
890
|
|
|
891
891
|
const issueData = responseData.data?.repository?.issue;
|
|
892
892
|
if (!issueData) {
|
|
893
893
|
throw new Error(
|
|
894
|
-
|
|
894
|
+
`Issue not found when fetching timeline from GitHub GraphQL API: ${issueUrl}`,
|
|
895
895
|
);
|
|
896
896
|
}
|
|
897
897
|
|
|
@@ -94,6 +94,7 @@ export class HandleScheduledEventUseCase {
|
|
|
94
94
|
notifyFinishedPreparation?: {
|
|
95
95
|
awaitingQualityCheckStatusName?: string | null;
|
|
96
96
|
} | null;
|
|
97
|
+
thresholdForAutoReject?: number;
|
|
97
98
|
}): Promise<{
|
|
98
99
|
project: Project;
|
|
99
100
|
issues: Issue[];
|
|
@@ -297,6 +298,7 @@ ${JSON.stringify(e)}
|
|
|
297
298
|
allowIssueCacheMinutes: input.allowIssueCacheMinutes,
|
|
298
299
|
preparationProcessCheckCommand:
|
|
299
300
|
input.startPreparation.preparationProcessCheckCommand,
|
|
301
|
+
thresholdForAutoReject: input.thresholdForAutoReject ?? 3,
|
|
300
302
|
awLogDirectoryPath: input.startPreparation.awLogDirectoryPath,
|
|
301
303
|
awLogStaleThresholdMinutes:
|
|
302
304
|
input.startPreparation.awLogStaleThresholdMinutes,
|
|
@@ -53,6 +53,12 @@ const createMockProject = (): Project => ({
|
|
|
53
53
|
color: 'BLUE',
|
|
54
54
|
description: '',
|
|
55
55
|
},
|
|
56
|
+
{
|
|
57
|
+
id: '5',
|
|
58
|
+
name: 'Failed Preparation',
|
|
59
|
+
color: 'RED',
|
|
60
|
+
description: '',
|
|
61
|
+
},
|
|
56
62
|
],
|
|
57
63
|
},
|
|
58
64
|
nextActionDate: null,
|
|
@@ -107,7 +113,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
107
113
|
>
|
|
108
114
|
>;
|
|
109
115
|
let mockIssueCommentRepository: Mocked<
|
|
110
|
-
Pick<IssueCommentRepository, 'getCommentsFromIssue'>
|
|
116
|
+
Pick<IssueCommentRepository, 'getCommentsFromIssue' | 'createComment'>
|
|
111
117
|
>;
|
|
112
118
|
let mockLocalCommandRunner: Mocked<LocalCommandRunner>;
|
|
113
119
|
let mockProject: Project;
|
|
@@ -129,6 +135,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
129
135
|
};
|
|
130
136
|
mockIssueCommentRepository = {
|
|
131
137
|
getCommentsFromIssue: jest.fn().mockResolvedValue([]),
|
|
138
|
+
createComment: jest.fn().mockResolvedValue(undefined),
|
|
132
139
|
};
|
|
133
140
|
mockLocalCommandRunner = {
|
|
134
141
|
runCommand: jest.fn(),
|
|
@@ -161,6 +168,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
161
168
|
projectUrl: 'https://github.com/user/repo',
|
|
162
169
|
allowIssueCacheMinutes: 60,
|
|
163
170
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
171
|
+
thresholdForAutoReject: 3,
|
|
164
172
|
});
|
|
165
173
|
|
|
166
174
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -206,6 +214,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
206
214
|
projectUrl: 'https://github.com/user/repo',
|
|
207
215
|
allowIssueCacheMinutes: 60,
|
|
208
216
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
217
|
+
thresholdForAutoReject: 3,
|
|
209
218
|
});
|
|
210
219
|
|
|
211
220
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -244,6 +253,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
244
253
|
projectUrl: 'https://github.com/user/repo',
|
|
245
254
|
allowIssueCacheMinutes: 60,
|
|
246
255
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
256
|
+
thresholdForAutoReject: 3,
|
|
247
257
|
});
|
|
248
258
|
|
|
249
259
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -277,6 +287,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
277
287
|
projectUrl: 'https://github.com/user/repo',
|
|
278
288
|
allowIssueCacheMinutes: 60,
|
|
279
289
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
290
|
+
thresholdForAutoReject: 3,
|
|
280
291
|
});
|
|
281
292
|
|
|
282
293
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -310,6 +321,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
310
321
|
projectUrl: 'https://github.com/user/repo',
|
|
311
322
|
allowIssueCacheMinutes: 60,
|
|
312
323
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
324
|
+
thresholdForAutoReject: 3,
|
|
313
325
|
});
|
|
314
326
|
|
|
315
327
|
expect(mockIssueRepository.findRelatedOpenPRs.mock.calls).toHaveLength(0);
|
|
@@ -344,6 +356,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
344
356
|
projectUrl: 'https://github.com/user/repo',
|
|
345
357
|
allowIssueCacheMinutes: 60,
|
|
346
358
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
359
|
+
thresholdForAutoReject: 3,
|
|
347
360
|
});
|
|
348
361
|
|
|
349
362
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -377,13 +390,14 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
377
390
|
projectUrl: 'https://github.com/user/repo',
|
|
378
391
|
allowIssueCacheMinutes: 60,
|
|
379
392
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
393
|
+
thresholdForAutoReject: 3,
|
|
380
394
|
});
|
|
381
395
|
|
|
382
396
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
383
397
|
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('1');
|
|
384
398
|
});
|
|
385
399
|
|
|
386
|
-
it('should
|
|
400
|
+
it('should post Auto Status Check: REJECTED comment when orphan path reverts to Awaiting Workspace', async () => {
|
|
387
401
|
const stuckIssue = createMockIssue({
|
|
388
402
|
url: 'https://github.com/user/repo/issues/10',
|
|
389
403
|
status: 'Preparation',
|
|
@@ -403,9 +417,18 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
403
417
|
projectUrl: 'https://github.com/user/repo',
|
|
404
418
|
allowIssueCacheMinutes: 60,
|
|
405
419
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
420
|
+
thresholdForAutoReject: 3,
|
|
406
421
|
});
|
|
407
422
|
|
|
408
423
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
424
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('1');
|
|
425
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(1);
|
|
426
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][0]).toBe(
|
|
427
|
+
stuckIssue,
|
|
428
|
+
);
|
|
429
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][1]).toBe(
|
|
430
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
431
|
+
);
|
|
409
432
|
});
|
|
410
433
|
|
|
411
434
|
it('should leave in-flight Preparation issue untouched when check command exits zero', async () => {
|
|
@@ -427,6 +450,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
427
450
|
projectUrl: 'https://github.com/user/repo',
|
|
428
451
|
allowIssueCacheMinutes: 60,
|
|
429
452
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
453
|
+
thresholdForAutoReject: 3,
|
|
430
454
|
});
|
|
431
455
|
|
|
432
456
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(0);
|
|
@@ -459,6 +483,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
459
483
|
projectUrl: 'https://github.com/user/repo',
|
|
460
484
|
allowIssueCacheMinutes: 60,
|
|
461
485
|
preparationProcessCheckCommand: 'check {URL}',
|
|
486
|
+
thresholdForAutoReject: 3,
|
|
462
487
|
});
|
|
463
488
|
|
|
464
489
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
|
|
@@ -498,6 +523,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
498
523
|
projectUrl: 'https://github.com/user/repo',
|
|
499
524
|
allowIssueCacheMinutes: 60,
|
|
500
525
|
preparationProcessCheckCommand: 'check {URL}',
|
|
526
|
+
thresholdForAutoReject: 3,
|
|
501
527
|
});
|
|
502
528
|
|
|
503
529
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
@@ -512,6 +538,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
512
538
|
projectUrl: 'https://github.com/user/repo',
|
|
513
539
|
allowIssueCacheMinutes: 0,
|
|
514
540
|
preparationProcessCheckCommand: 'check {URL}',
|
|
541
|
+
thresholdForAutoReject: 3,
|
|
515
542
|
}),
|
|
516
543
|
).rejects.toThrow('Project not found');
|
|
517
544
|
});
|
|
@@ -525,6 +552,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
525
552
|
projectUrl: 'https://github.com/user/repo',
|
|
526
553
|
allowIssueCacheMinutes: 0,
|
|
527
554
|
preparationProcessCheckCommand: 'check {URL}',
|
|
555
|
+
thresholdForAutoReject: 3,
|
|
528
556
|
}),
|
|
529
557
|
).rejects.toThrow('Project not found. projectId: project-1');
|
|
530
558
|
});
|
|
@@ -560,6 +588,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
560
588
|
projectUrl: 'https://github.com/user/repo',
|
|
561
589
|
allowIssueCacheMinutes: 0,
|
|
562
590
|
preparationProcessCheckCommand: 'check {URL}',
|
|
591
|
+
thresholdForAutoReject: 3,
|
|
563
592
|
});
|
|
564
593
|
|
|
565
594
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(0);
|
|
@@ -578,6 +607,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
578
607
|
projectUrl: 'https://github.com/user/repo',
|
|
579
608
|
allowIssueCacheMinutes: 60,
|
|
580
609
|
preparationProcessCheckCommand: 'check {URL}',
|
|
610
|
+
thresholdForAutoReject: 3,
|
|
581
611
|
});
|
|
582
612
|
|
|
583
613
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(0);
|
|
@@ -614,6 +644,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
614
644
|
projectUrl: 'https://github.com/user/repo',
|
|
615
645
|
allowIssueCacheMinutes: 60,
|
|
616
646
|
preparationProcessCheckCommand: 'pgrep -fa "Please handover {URL}"',
|
|
647
|
+
thresholdForAutoReject: 3,
|
|
617
648
|
awLogDirectoryPath: '/home/user/logs-aw',
|
|
618
649
|
awLogStaleThresholdMinutes: 15,
|
|
619
650
|
});
|
|
@@ -676,6 +707,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
676
707
|
projectUrl: 'https://github.com/user/repo',
|
|
677
708
|
allowIssueCacheMinutes: 60,
|
|
678
709
|
preparationProcessCheckCommand: 'pgrep -fa "Please handover {URL}"',
|
|
710
|
+
thresholdForAutoReject: 3,
|
|
679
711
|
awLogDirectoryPath: '/home/user/logs-aw',
|
|
680
712
|
awLogStaleThresholdMinutes: 15,
|
|
681
713
|
});
|
|
@@ -710,6 +742,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
710
742
|
projectUrl: 'https://github.com/user/repo',
|
|
711
743
|
allowIssueCacheMinutes: 60,
|
|
712
744
|
preparationProcessCheckCommand: 'pgrep -fa "Please handover {URL}"',
|
|
745
|
+
thresholdForAutoReject: 3,
|
|
713
746
|
awLogDirectoryPath: '/home/user/logs-aw',
|
|
714
747
|
awLogStaleThresholdMinutes: 15,
|
|
715
748
|
});
|
|
@@ -740,6 +773,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
740
773
|
projectUrl: 'https://github.com/user/repo',
|
|
741
774
|
allowIssueCacheMinutes: 60,
|
|
742
775
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
776
|
+
thresholdForAutoReject: 3,
|
|
743
777
|
});
|
|
744
778
|
|
|
745
779
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(0);
|
|
@@ -769,6 +803,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
769
803
|
projectUrl: 'https://github.com/user/repo',
|
|
770
804
|
allowIssueCacheMinutes: 60,
|
|
771
805
|
preparationProcessCheckCommand: 'pgrep -fa "Please handover {URL}"',
|
|
806
|
+
thresholdForAutoReject: 3,
|
|
772
807
|
awLogDirectoryPath: '/home/user/logs-aw',
|
|
773
808
|
awLogStaleThresholdMinutes: 15,
|
|
774
809
|
});
|
|
@@ -796,6 +831,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
796
831
|
projectUrl: 'https://github.com/user/repo',
|
|
797
832
|
allowIssueCacheMinutes: 0,
|
|
798
833
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
834
|
+
thresholdForAutoReject: 3,
|
|
799
835
|
});
|
|
800
836
|
|
|
801
837
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
|
|
@@ -828,6 +864,7 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
828
864
|
projectUrl: 'https://github.com/user/repo',
|
|
829
865
|
allowIssueCacheMinutes: 60,
|
|
830
866
|
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
867
|
+
thresholdForAutoReject: 3,
|
|
831
868
|
});
|
|
832
869
|
|
|
833
870
|
expect(
|
|
@@ -837,4 +874,227 @@ describe('RevertOrphanedPreparationUseCase', () => {
|
|
|
837
874
|
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
838
875
|
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('4');
|
|
839
876
|
});
|
|
877
|
+
|
|
878
|
+
it('should transition orphaned issue to Failed Preparation when rejection threshold is met', async () => {
|
|
879
|
+
const stuckIssue = createMockIssue({
|
|
880
|
+
url: 'https://github.com/user/repo/issues/10',
|
|
881
|
+
status: 'Preparation',
|
|
882
|
+
});
|
|
883
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
884
|
+
issues: [stuckIssue],
|
|
885
|
+
cacheUsed: false,
|
|
886
|
+
});
|
|
887
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
888
|
+
stdout: '',
|
|
889
|
+
stderr: '',
|
|
890
|
+
exitCode: 1,
|
|
891
|
+
});
|
|
892
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
893
|
+
{
|
|
894
|
+
author: 'bot',
|
|
895
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
896
|
+
createdAt: new Date(),
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
author: 'bot',
|
|
900
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
901
|
+
createdAt: new Date(),
|
|
902
|
+
},
|
|
903
|
+
]);
|
|
904
|
+
|
|
905
|
+
await useCase.run({
|
|
906
|
+
projectUrl: 'https://github.com/user/repo',
|
|
907
|
+
allowIssueCacheMinutes: 60,
|
|
908
|
+
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
909
|
+
thresholdForAutoReject: 3,
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
913
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][0]).toBe(mockProject);
|
|
914
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][1]).toBe(stuckIssue);
|
|
915
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('5');
|
|
916
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(1);
|
|
917
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][0]).toBe(
|
|
918
|
+
stuckIssue,
|
|
919
|
+
);
|
|
920
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][1]).toBe(
|
|
921
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION\n\nFailed to pass the check automatically for 3 times',
|
|
922
|
+
);
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
it('should revert orphaned issue to Awaiting Workspace when rejection threshold is not yet met', async () => {
|
|
926
|
+
const stuckIssue = createMockIssue({
|
|
927
|
+
url: 'https://github.com/user/repo/issues/10',
|
|
928
|
+
status: 'Preparation',
|
|
929
|
+
});
|
|
930
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
931
|
+
issues: [stuckIssue],
|
|
932
|
+
cacheUsed: false,
|
|
933
|
+
});
|
|
934
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
935
|
+
stdout: '',
|
|
936
|
+
stderr: '',
|
|
937
|
+
exitCode: 1,
|
|
938
|
+
});
|
|
939
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
940
|
+
{
|
|
941
|
+
author: 'bot',
|
|
942
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
943
|
+
createdAt: new Date(),
|
|
944
|
+
},
|
|
945
|
+
]);
|
|
946
|
+
|
|
947
|
+
await useCase.run({
|
|
948
|
+
projectUrl: 'https://github.com/user/repo',
|
|
949
|
+
allowIssueCacheMinutes: 60,
|
|
950
|
+
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
951
|
+
thresholdForAutoReject: 3,
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
955
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('1');
|
|
956
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(1);
|
|
957
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][1]).toBe(
|
|
958
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
959
|
+
);
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
it('should not transition to Failed Preparation when an earlier escalation comment is already in the recent window', async () => {
|
|
963
|
+
const stuckIssue = createMockIssue({
|
|
964
|
+
url: 'https://github.com/user/repo/issues/10',
|
|
965
|
+
status: 'Preparation',
|
|
966
|
+
});
|
|
967
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
968
|
+
issues: [stuckIssue],
|
|
969
|
+
cacheUsed: false,
|
|
970
|
+
});
|
|
971
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
972
|
+
stdout: '',
|
|
973
|
+
stderr: '',
|
|
974
|
+
exitCode: 1,
|
|
975
|
+
});
|
|
976
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
977
|
+
{
|
|
978
|
+
author: 'bot',
|
|
979
|
+
content:
|
|
980
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION\n\nFailed to pass the check automatically for 3 times',
|
|
981
|
+
createdAt: new Date(),
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
author: 'bot',
|
|
985
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
986
|
+
createdAt: new Date(),
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
author: 'bot',
|
|
990
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
991
|
+
createdAt: new Date(),
|
|
992
|
+
},
|
|
993
|
+
]);
|
|
994
|
+
|
|
995
|
+
await useCase.run({
|
|
996
|
+
projectUrl: 'https://github.com/user/repo',
|
|
997
|
+
allowIssueCacheMinutes: 60,
|
|
998
|
+
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
999
|
+
thresholdForAutoReject: 3,
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
1003
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('1');
|
|
1004
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(1);
|
|
1005
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][1]).toBe(
|
|
1006
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
1007
|
+
);
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
it('should not post a rejection comment when orphaned issue advances to Awaiting Quality Check', async () => {
|
|
1011
|
+
const stuckIssue = createMockIssue({
|
|
1012
|
+
url: 'https://github.com/user/repo/issues/10',
|
|
1013
|
+
status: 'Preparation',
|
|
1014
|
+
});
|
|
1015
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1016
|
+
issues: [stuckIssue],
|
|
1017
|
+
cacheUsed: false,
|
|
1018
|
+
});
|
|
1019
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
1020
|
+
stdout: '',
|
|
1021
|
+
stderr: '',
|
|
1022
|
+
exitCode: 1,
|
|
1023
|
+
});
|
|
1024
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1025
|
+
{
|
|
1026
|
+
author: 'bot',
|
|
1027
|
+
content: 'From: :robot: agent report',
|
|
1028
|
+
createdAt: new Date(),
|
|
1029
|
+
},
|
|
1030
|
+
]);
|
|
1031
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
1032
|
+
createPassingPr(),
|
|
1033
|
+
]);
|
|
1034
|
+
|
|
1035
|
+
await useCase.run({
|
|
1036
|
+
projectUrl: 'https://github.com/user/repo',
|
|
1037
|
+
allowIssueCacheMinutes: 60,
|
|
1038
|
+
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
1039
|
+
thresholdForAutoReject: 3,
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
1043
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('4');
|
|
1044
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(0);
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
it('should revert to Awaiting Workspace when Failed Preparation status option is not present even at threshold', async () => {
|
|
1048
|
+
const projectWithoutFailedPreparation = {
|
|
1049
|
+
...mockProject,
|
|
1050
|
+
status: {
|
|
1051
|
+
...mockProject.status,
|
|
1052
|
+
statuses: mockProject.status.statuses.filter(
|
|
1053
|
+
(s) => s.name !== 'Failed Preparation',
|
|
1054
|
+
),
|
|
1055
|
+
},
|
|
1056
|
+
};
|
|
1057
|
+
mockProjectRepository.getProject.mockResolvedValue(
|
|
1058
|
+
projectWithoutFailedPreparation,
|
|
1059
|
+
);
|
|
1060
|
+
const stuckIssue = createMockIssue({
|
|
1061
|
+
url: 'https://github.com/user/repo/issues/10',
|
|
1062
|
+
status: 'Preparation',
|
|
1063
|
+
});
|
|
1064
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1065
|
+
issues: [stuckIssue],
|
|
1066
|
+
cacheUsed: false,
|
|
1067
|
+
});
|
|
1068
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
1069
|
+
stdout: '',
|
|
1070
|
+
stderr: '',
|
|
1071
|
+
exitCode: 1,
|
|
1072
|
+
});
|
|
1073
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1074
|
+
{
|
|
1075
|
+
author: 'bot',
|
|
1076
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
1077
|
+
createdAt: new Date(),
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
author: 'bot',
|
|
1081
|
+
content: 'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
1082
|
+
createdAt: new Date(),
|
|
1083
|
+
},
|
|
1084
|
+
]);
|
|
1085
|
+
|
|
1086
|
+
await useCase.run({
|
|
1087
|
+
projectUrl: 'https://github.com/user/repo',
|
|
1088
|
+
allowIssueCacheMinutes: 60,
|
|
1089
|
+
preparationProcessCheckCommand: 'pgrep -fa "claude-agent.*{URL}"',
|
|
1090
|
+
thresholdForAutoReject: 3,
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
|
|
1094
|
+
expect(mockIssueRepository.updateStatus.mock.calls[0][2]).toBe('1');
|
|
1095
|
+
expect(mockIssueCommentRepository.createComment.mock.calls).toHaveLength(1);
|
|
1096
|
+
expect(mockIssueCommentRepository.createComment.mock.calls[0][1]).toBe(
|
|
1097
|
+
'Auto Status Check: REJECTED\n- ORPHANED_PREPARATION',
|
|
1098
|
+
);
|
|
1099
|
+
});
|
|
840
1100
|
});
|