github-issue-tower-defence-management 1.52.0 → 1.53.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 +19 -0
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +45 -31
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/repositories/GraphqlProjectRepository.js +31 -9
- package/bin/adapter/repositories/GraphqlProjectRepository.js.map +1 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +8 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/IssueRejectionEvaluator.js +80 -0
- package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -0
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +4 -67
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.js +42 -0
- package/bin/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +8 -0
- package/src/adapter/repositories/GraphqlProjectRepository.fetchProjectId.test.ts +251 -0
- package/src/adapter/repositories/GraphqlProjectRepository.ts +54 -25
- package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +58 -0
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +11 -0
- package/src/domain/usecases/IssueRejectionEvaluator.ts +114 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +15 -89
- package/src/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.test.ts +376 -0
- package/src/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.ts +88 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/repositories/GraphqlProjectRepository.d.ts +2 -0
- package/types/adapter/repositories/GraphqlProjectRepository.d.ts.map +1 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +6 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/IssueRejectionEvaluator.d.ts +20 -0
- package/types/domain/usecases/IssueRejectionEvaluator.d.ts.map +1 -0
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.d.ts +15 -0
- package/types/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.d.ts.map +1 -0
|
@@ -21,6 +21,7 @@ import { AssignNoAssigneeIssueToManagerUseCase } from './AssignNoAssigneeIssueTo
|
|
|
21
21
|
import { UpdateIssueStatusByLabelUseCase } from './UpdateIssueStatusByLabelUseCase';
|
|
22
22
|
import { StartPreparationUseCase } from './StartPreparationUseCase';
|
|
23
23
|
import { RevertOrphanedPreparationUseCase } from './RevertOrphanedPreparationUseCase';
|
|
24
|
+
import { RevertNotReadyAwaitingQualityCheckUseCase } from './RevertNotReadyAwaitingQualityCheckUseCase';
|
|
24
25
|
import { SetupTowerDefenceProjectUseCase } from './SetupTowerDefenceProjectUseCase';
|
|
25
26
|
|
|
26
27
|
describe('HandleScheduledEventUseCase', () => {
|
|
@@ -109,6 +110,8 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
109
110
|
const mockStartPreparationUseCase = mock<StartPreparationUseCase>();
|
|
110
111
|
const mockRevertOrphanedPreparationUseCase =
|
|
111
112
|
mock<RevertOrphanedPreparationUseCase>();
|
|
113
|
+
const mockRevertNotReadyAwaitingQualityCheckUseCase =
|
|
114
|
+
mock<RevertNotReadyAwaitingQualityCheckUseCase>();
|
|
112
115
|
const mockDateRepository = mock<DateRepository>();
|
|
113
116
|
const mockSpreadsheetRepository = mock<SpreadsheetRepository>();
|
|
114
117
|
const mockProjectRepository = mock<ProjectRepository>();
|
|
@@ -131,6 +134,7 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
131
134
|
mockUpdateIssueStatusByLabelUseCase,
|
|
132
135
|
mockStartPreparationUseCase,
|
|
133
136
|
mockRevertOrphanedPreparationUseCase,
|
|
137
|
+
mockRevertNotReadyAwaitingQualityCheckUseCase,
|
|
134
138
|
mockDateRepository,
|
|
135
139
|
mockSpreadsheetRepository,
|
|
136
140
|
mockProjectRepository,
|
|
@@ -309,6 +313,60 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
309
313
|
);
|
|
310
314
|
});
|
|
311
315
|
|
|
316
|
+
it('should invoke revertNotReadyAwaitingQualityCheckUseCase when notifyFinishedPreparation is configured', async () => {
|
|
317
|
+
const input = {
|
|
318
|
+
projectName: 'test-project',
|
|
319
|
+
org: 'test-org',
|
|
320
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
321
|
+
manager: 'test-manager',
|
|
322
|
+
workingReport: {
|
|
323
|
+
repo: 'test-repo',
|
|
324
|
+
members: ['member1'],
|
|
325
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
326
|
+
},
|
|
327
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
328
|
+
disabled: false,
|
|
329
|
+
allowIssueCacheMinutes: 60,
|
|
330
|
+
notifyFinishedPreparation: {},
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
mockProjectRepository.getProject.mockResolvedValue(mock<Project>());
|
|
334
|
+
await useCase.run(input);
|
|
335
|
+
|
|
336
|
+
expect(
|
|
337
|
+
mockRevertNotReadyAwaitingQualityCheckUseCase.run,
|
|
338
|
+
).toHaveBeenCalledWith(
|
|
339
|
+
expect.objectContaining({
|
|
340
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
341
|
+
allowIssueCacheMinutes: 60,
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should not invoke revertNotReadyAwaitingQualityCheckUseCase when notifyFinishedPreparation is absent', async () => {
|
|
347
|
+
const input = {
|
|
348
|
+
projectName: 'test-project',
|
|
349
|
+
org: 'test-org',
|
|
350
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
351
|
+
manager: 'test-manager',
|
|
352
|
+
workingReport: {
|
|
353
|
+
repo: 'test-repo',
|
|
354
|
+
members: ['member1'],
|
|
355
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
356
|
+
},
|
|
357
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
358
|
+
disabled: false,
|
|
359
|
+
allowIssueCacheMinutes: 60,
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
mockProjectRepository.getProject.mockResolvedValue(mock<Project>());
|
|
363
|
+
await useCase.run(input);
|
|
364
|
+
|
|
365
|
+
expect(
|
|
366
|
+
mockRevertNotReadyAwaitingQualityCheckUseCase.run,
|
|
367
|
+
).not.toHaveBeenCalled();
|
|
368
|
+
});
|
|
369
|
+
|
|
312
370
|
describe('story issue creation progress logs', () => {
|
|
313
371
|
const storyInput = {
|
|
314
372
|
projectName: 'test-project',
|
|
@@ -21,6 +21,7 @@ import { AssignNoAssigneeIssueToManagerUseCase } from './AssignNoAssigneeIssueTo
|
|
|
21
21
|
import { UpdateIssueStatusByLabelUseCase } from './UpdateIssueStatusByLabelUseCase';
|
|
22
22
|
import { StartPreparationUseCase } from './StartPreparationUseCase';
|
|
23
23
|
import { RevertOrphanedPreparationUseCase } from './RevertOrphanedPreparationUseCase';
|
|
24
|
+
import { RevertNotReadyAwaitingQualityCheckUseCase } from './RevertNotReadyAwaitingQualityCheckUseCase';
|
|
24
25
|
import { SetupTowerDefenceProjectUseCase } from './SetupTowerDefenceProjectUseCase';
|
|
25
26
|
|
|
26
27
|
export class ProjectNotFoundError extends Error {
|
|
@@ -50,6 +51,7 @@ export class HandleScheduledEventUseCase {
|
|
|
50
51
|
readonly updateIssueStatusByLabelUseCase: UpdateIssueStatusByLabelUseCase,
|
|
51
52
|
readonly startPreparationUseCase: StartPreparationUseCase,
|
|
52
53
|
readonly revertOrphanedPreparationUseCase: RevertOrphanedPreparationUseCase,
|
|
54
|
+
readonly revertNotReadyAwaitingQualityCheckUseCase: RevertNotReadyAwaitingQualityCheckUseCase,
|
|
53
55
|
readonly dateRepository: DateRepository,
|
|
54
56
|
readonly spreadsheetRepository: SpreadsheetRepository,
|
|
55
57
|
readonly projectRepository: ProjectRepository,
|
|
@@ -83,6 +85,9 @@ export class HandleScheduledEventUseCase {
|
|
|
83
85
|
awLogStaleThresholdMinutes?: number;
|
|
84
86
|
awaitingQualityCheckStatus?: string | null;
|
|
85
87
|
} | null;
|
|
88
|
+
notifyFinishedPreparation?: {
|
|
89
|
+
awaitingQualityCheckStatusName?: string | null;
|
|
90
|
+
} | null;
|
|
86
91
|
}): Promise<{
|
|
87
92
|
project: Project;
|
|
88
93
|
issues: Issue[];
|
|
@@ -252,6 +257,12 @@ ${JSON.stringify(e)}
|
|
|
252
257
|
storyObjectMap,
|
|
253
258
|
);
|
|
254
259
|
}
|
|
260
|
+
if (input.notifyFinishedPreparation) {
|
|
261
|
+
await this.revertNotReadyAwaitingQualityCheckUseCase.run({
|
|
262
|
+
projectUrl: input.projectUrl,
|
|
263
|
+
allowIssueCacheMinutes: input.allowIssueCacheMinutes,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
255
266
|
if (input.startPreparation) {
|
|
256
267
|
if (input.startPreparation.preparationProcessCheckCommand) {
|
|
257
268
|
await this.revertOrphanedPreparationUseCase.run({
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IssueRepository,
|
|
3
|
+
RelatedPullRequest,
|
|
4
|
+
} from './adapter-interfaces/IssueRepository';
|
|
5
|
+
|
|
6
|
+
export type PrRejectedReasonType =
|
|
7
|
+
| 'PULL_REQUEST_NOT_FOUND'
|
|
8
|
+
| 'MULTIPLE_PULL_REQUESTS_FOUND'
|
|
9
|
+
| 'PULL_REQUEST_CONFLICTED'
|
|
10
|
+
| 'ANY_CI_JOB_FAILED_OR_IN_PROGRESS'
|
|
11
|
+
| 'REQUIRED_CI_JOB_NEVER_STARTED'
|
|
12
|
+
| 'ANY_REVIEW_COMMENT_NOT_RESOLVED';
|
|
13
|
+
|
|
14
|
+
export type PrRejectionResult = {
|
|
15
|
+
rejections: { type: PrRejectedReasonType; detail: string }[];
|
|
16
|
+
approvedPrUrl: string | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class IssueRejectionEvaluator {
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly issueRepository: Pick<
|
|
22
|
+
IssueRepository,
|
|
23
|
+
'findRelatedOpenPRs' | 'getOpenPullRequest'
|
|
24
|
+
>,
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
evaluate = async (issue: {
|
|
28
|
+
url: string;
|
|
29
|
+
labels: string[];
|
|
30
|
+
isPr: boolean;
|
|
31
|
+
}): Promise<PrRejectionResult> => {
|
|
32
|
+
const rejections: { type: PrRejectedReasonType; detail: string }[] = [];
|
|
33
|
+
let approvedPrUrl: string | null = null;
|
|
34
|
+
|
|
35
|
+
const categoryLabels = issue.labels.filter((label) =>
|
|
36
|
+
label.startsWith('category:'),
|
|
37
|
+
);
|
|
38
|
+
const hasLlmAgentLabel = issue.labels.some(
|
|
39
|
+
(l) => l === 'llm-agent' || l.startsWith('llm-agent:'),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
!hasLlmAgentLabel &&
|
|
44
|
+
(categoryLabels.length <= 0 || categoryLabels.includes('category:e2e'))
|
|
45
|
+
) {
|
|
46
|
+
const prsToCheck = issue.isPr
|
|
47
|
+
? await this.resolveOpenPrsForPrItem(issue.url)
|
|
48
|
+
: await this.issueRepository.findRelatedOpenPRs(issue.url);
|
|
49
|
+
|
|
50
|
+
if (prsToCheck.length <= 0) {
|
|
51
|
+
rejections.push({
|
|
52
|
+
type: 'PULL_REQUEST_NOT_FOUND',
|
|
53
|
+
detail: 'PULL_REQUEST_NOT_FOUND',
|
|
54
|
+
});
|
|
55
|
+
} else if (prsToCheck.length > 1) {
|
|
56
|
+
rejections.push({
|
|
57
|
+
type: 'MULTIPLE_PULL_REQUESTS_FOUND',
|
|
58
|
+
detail: `MULTIPLE_PULL_REQUESTS_FOUND: ${prsToCheck.map((pr) => pr.url).join(', ')}`,
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
const pr = prsToCheck[0];
|
|
62
|
+
if (pr.isConflicted) {
|
|
63
|
+
rejections.push({
|
|
64
|
+
type: 'PULL_REQUEST_CONFLICTED',
|
|
65
|
+
detail: `PULL_REQUEST_CONFLICTED: ${pr.url}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (!pr.isPassedAllCiJob) {
|
|
69
|
+
const missingChecks = pr.missingRequiredCheckNames;
|
|
70
|
+
const missingSuffix =
|
|
71
|
+
missingChecks.length > 0
|
|
72
|
+
? ` (missing: ${missingChecks.join(', ')})`
|
|
73
|
+
: '';
|
|
74
|
+
if (pr.isCiStateSuccess && missingChecks.length > 0) {
|
|
75
|
+
rejections.push({
|
|
76
|
+
type: 'REQUIRED_CI_JOB_NEVER_STARTED',
|
|
77
|
+
detail: `REQUIRED_CI_JOB_NEVER_STARTED: ${pr.url}${missingSuffix}`,
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
rejections.push({
|
|
81
|
+
type: 'ANY_CI_JOB_FAILED_OR_IN_PROGRESS',
|
|
82
|
+
detail: `ANY_CI_JOB_FAILED_OR_IN_PROGRESS: ${pr.url}${missingSuffix}`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!pr.isResolvedAllReviewComments) {
|
|
87
|
+
rejections.push({
|
|
88
|
+
type: 'ANY_REVIEW_COMMENT_NOT_RESOLVED',
|
|
89
|
+
detail: `ANY_REVIEW_COMMENT_NOT_RESOLVED: ${pr.url}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
!pr.isConflicted &&
|
|
94
|
+
pr.isPassedAllCiJob &&
|
|
95
|
+
pr.isResolvedAllReviewComments
|
|
96
|
+
) {
|
|
97
|
+
approvedPrUrl = pr.url;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { rejections, approvedPrUrl };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
private resolveOpenPrsForPrItem = async (
|
|
106
|
+
prUrl: string,
|
|
107
|
+
): Promise<RelatedPullRequest[]> => {
|
|
108
|
+
const pr = await this.issueRepository.getOpenPullRequest(prUrl);
|
|
109
|
+
if (pr === null) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
return [pr];
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IssueRepository,
|
|
3
|
-
RelatedPullRequest,
|
|
4
|
-
} from './adapter-interfaces/IssueRepository';
|
|
1
|
+
import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
5
2
|
import { ProjectRepository } from './adapter-interfaces/ProjectRepository';
|
|
6
3
|
import { IssueCommentRepository } from './adapter-interfaces/IssueCommentRepository';
|
|
7
4
|
import { WebhookRepository } from './adapter-interfaces/WebhookRepository';
|
|
@@ -11,6 +8,10 @@ import {
|
|
|
11
8
|
FAILED_PREPARATION_STATUS_NAME,
|
|
12
9
|
PREPARATION_STATUS_NAME,
|
|
13
10
|
} from '../entities/WorkflowStatus';
|
|
11
|
+
import {
|
|
12
|
+
IssueRejectionEvaluator,
|
|
13
|
+
PrRejectedReasonType,
|
|
14
|
+
} from './IssueRejectionEvaluator';
|
|
14
15
|
|
|
15
16
|
export class IssueNotFoundError extends Error {
|
|
16
17
|
constructor(issueUrl: string) {
|
|
@@ -33,14 +34,11 @@ export class IllegalIssueStatusError extends Error {
|
|
|
33
34
|
type RejectedReasonType =
|
|
34
35
|
| 'NO_REPORT_FROM_AGENT_BOT'
|
|
35
36
|
| 'REPORT_HAS_NEXT_STEP'
|
|
36
|
-
|
|
|
37
|
-
| 'MULTIPLE_PULL_REQUESTS_FOUND'
|
|
38
|
-
| 'PULL_REQUEST_CONFLICTED'
|
|
39
|
-
| 'ANY_CI_JOB_FAILED_OR_IN_PROGRESS'
|
|
40
|
-
| 'REQUIRED_CI_JOB_NEVER_STARTED'
|
|
41
|
-
| 'ANY_REVIEW_COMMENT_NOT_RESOLVED';
|
|
37
|
+
| PrRejectedReasonType;
|
|
42
38
|
|
|
43
39
|
export class NotifyFinishedIssuePreparationUseCase {
|
|
40
|
+
private readonly issueRejectionEvaluator: IssueRejectionEvaluator;
|
|
41
|
+
|
|
44
42
|
constructor(
|
|
45
43
|
private readonly projectRepository: Pick<ProjectRepository, 'getByUrl'>,
|
|
46
44
|
private readonly issueRepository: Pick<
|
|
@@ -61,7 +59,9 @@ export class NotifyFinishedIssuePreparationUseCase {
|
|
|
61
59
|
WebhookRepository,
|
|
62
60
|
'sendGetRequest'
|
|
63
61
|
>,
|
|
64
|
-
) {
|
|
62
|
+
) {
|
|
63
|
+
this.issueRejectionEvaluator = new IssueRejectionEvaluator(issueRepository);
|
|
64
|
+
}
|
|
65
65
|
|
|
66
66
|
run = async (params: {
|
|
67
67
|
projectUrl: string;
|
|
@@ -257,7 +257,7 @@ export class NotifyFinishedIssuePreparationUseCase {
|
|
|
257
257
|
approvedPrUrl: string | null;
|
|
258
258
|
}> => {
|
|
259
259
|
const rejections: { type: RejectedReasonType; detail: string }[] = [];
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
const lastComment = comments[comments.length - 1];
|
|
262
262
|
if (!lastComment || !lastComment.content.startsWith('From:')) {
|
|
263
263
|
rejections.push({
|
|
@@ -271,83 +271,9 @@ export class NotifyFinishedIssuePreparationUseCase {
|
|
|
271
271
|
});
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const hasLlmAgentLabel = issue.labels.some(
|
|
278
|
-
(l) => l === 'llm-agent' || l.startsWith('llm-agent:'),
|
|
279
|
-
);
|
|
280
|
-
if (
|
|
281
|
-
!hasLlmAgentLabel &&
|
|
282
|
-
(categoryLabels.length <= 0 || categoryLabels.includes('category:e2e'))
|
|
283
|
-
) {
|
|
284
|
-
const prsToCheck = issue.isPr
|
|
285
|
-
? await this.resolveOpenPrsForPrItem(issue.url)
|
|
286
|
-
: await this.issueRepository.findRelatedOpenPRs(issue.url);
|
|
287
|
-
|
|
288
|
-
if (prsToCheck.length <= 0) {
|
|
289
|
-
rejections.push({
|
|
290
|
-
type: 'PULL_REQUEST_NOT_FOUND',
|
|
291
|
-
detail: 'PULL_REQUEST_NOT_FOUND',
|
|
292
|
-
});
|
|
293
|
-
} else if (prsToCheck.length > 1) {
|
|
294
|
-
rejections.push({
|
|
295
|
-
type: 'MULTIPLE_PULL_REQUESTS_FOUND',
|
|
296
|
-
detail: `MULTIPLE_PULL_REQUESTS_FOUND: ${prsToCheck.map((pr) => pr.url).join(', ')}`,
|
|
297
|
-
});
|
|
298
|
-
} else {
|
|
299
|
-
const pr = prsToCheck[0];
|
|
300
|
-
if (pr.isConflicted) {
|
|
301
|
-
rejections.push({
|
|
302
|
-
type: 'PULL_REQUEST_CONFLICTED',
|
|
303
|
-
detail: `PULL_REQUEST_CONFLICTED: ${pr.url}`,
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
if (!pr.isPassedAllCiJob) {
|
|
307
|
-
const missingChecks = pr.missingRequiredCheckNames;
|
|
308
|
-
const missingSuffix =
|
|
309
|
-
missingChecks.length > 0
|
|
310
|
-
? ` (missing: ${missingChecks.join(', ')})`
|
|
311
|
-
: '';
|
|
312
|
-
if (pr.isCiStateSuccess && missingChecks.length > 0) {
|
|
313
|
-
rejections.push({
|
|
314
|
-
type: 'REQUIRED_CI_JOB_NEVER_STARTED',
|
|
315
|
-
detail: `REQUIRED_CI_JOB_NEVER_STARTED: ${pr.url}${missingSuffix}`,
|
|
316
|
-
});
|
|
317
|
-
} else {
|
|
318
|
-
rejections.push({
|
|
319
|
-
type: 'ANY_CI_JOB_FAILED_OR_IN_PROGRESS',
|
|
320
|
-
detail: `ANY_CI_JOB_FAILED_OR_IN_PROGRESS: ${pr.url}${missingSuffix}`,
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
if (!pr.isResolvedAllReviewComments) {
|
|
325
|
-
rejections.push({
|
|
326
|
-
type: 'ANY_REVIEW_COMMENT_NOT_RESOLVED',
|
|
327
|
-
detail: `ANY_REVIEW_COMMENT_NOT_RESOLVED: ${pr.url}`,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
if (
|
|
331
|
-
!pr.isConflicted &&
|
|
332
|
-
pr.isPassedAllCiJob &&
|
|
333
|
-
pr.isResolvedAllReviewComments
|
|
334
|
-
) {
|
|
335
|
-
approvedPrUrl = pr.url;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return { rejections, approvedPrUrl };
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
private resolveOpenPrsForPrItem = async (
|
|
344
|
-
prUrl: string,
|
|
345
|
-
): Promise<RelatedPullRequest[]> => {
|
|
346
|
-
const pr = await this.issueRepository.getOpenPullRequest(prUrl);
|
|
347
|
-
if (pr === null) {
|
|
348
|
-
return [];
|
|
349
|
-
}
|
|
350
|
-
return [pr];
|
|
274
|
+
const { rejections: prRejections, approvedPrUrl } =
|
|
275
|
+
await this.issueRejectionEvaluator.evaluate(issue);
|
|
276
|
+
return { rejections: [...rejections, ...prRejections], approvedPrUrl };
|
|
351
277
|
};
|
|
352
278
|
|
|
353
279
|
private reportBodyHasNextStep = (body: string): boolean => {
|