github-issue-tower-defence-management 1.172.2 → 1.173.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +2 -0
- package/bin/adapter/entry-points/console/consoleReadApi.js +126 -48
- package/bin/adapter/entry-points/console/consoleReadApi.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-ZYMkO0fm.js → index-BcnLfodS.js} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +3 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +19 -17
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/githubRateLimitRetry.js +8 -1
- package/bin/adapter/repositories/issue/githubRateLimitRetry.js.map +1 -1
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +17 -3
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/QualityCheckAdvanceUseCase.js +50 -0
- package/bin/domain/usecases/QualityCheckAdvanceUseCase.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/console/consoleReadApi.test.ts +254 -0
- package/src/adapter/entry-points/console/consoleReadApi.ts +133 -55
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +10 -0
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +14 -1
- package/src/adapter/entry-points/console/ui-dist/assets/{index-ZYMkO0fm.js → index-BcnLfodS.js} +1 -1
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/console/webServer.test.ts +35 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +6 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +47 -19
- package/src/adapter/repositories/issue/githubRateLimitRetry.ts +4 -0
- package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +116 -0
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +21 -0
- package/src/domain/usecases/QualityCheckAdvanceUseCase.test.ts +387 -0
- package/src/domain/usecases/QualityCheckAdvanceUseCase.ts +75 -0
- package/types/adapter/entry-points/console/consoleReadApi.d.ts +2 -0
- package/types/adapter/entry-points/console/consoleReadApi.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +1 -0
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/adapter/repositories/issue/githubRateLimitRetry.d.ts +3 -0
- package/types/adapter/repositories/issue/githubRateLimitRetry.d.ts.map +1 -1
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +5 -2
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/QualityCheckAdvanceUseCase.d.ts +14 -0
- package/types/domain/usecases/QualityCheckAdvanceUseCase.d.ts.map +1 -0
|
@@ -74,6 +74,7 @@ import { GitHubIssueCommentRepository } from '../../repositories/GitHubIssueComm
|
|
|
74
74
|
import { ProjectRequiredFieldCreateUseCase } from '../../../domain/usecases/ProjectRequiredFieldCreateUseCase';
|
|
75
75
|
import { SetupTowerDefenceProjectUseCase } from '../../../domain/usecases/SetupTowerDefenceProjectUseCase';
|
|
76
76
|
import { DailySecurityScanUseCase } from '../../../domain/usecases/DailySecurityScanUseCase';
|
|
77
|
+
import { QualityCheckAdvanceUseCase } from '../../../domain/usecases/QualityCheckAdvanceUseCase';
|
|
77
78
|
import { KyHttpRepository } from '../../repositories/KyHttpRepository';
|
|
78
79
|
import { FileSystemKevReportWatermarkRepository } from '../../repositories/FileSystemKevReportWatermarkRepository';
|
|
79
80
|
import {
|
|
@@ -507,6 +508,10 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
507
508
|
)
|
|
508
509
|
: null;
|
|
509
510
|
|
|
511
|
+
const qualityCheckAdvanceUseCase = new QualityCheckAdvanceUseCase(
|
|
512
|
+
issueRepository,
|
|
513
|
+
);
|
|
514
|
+
|
|
510
515
|
const handleScheduledEventUseCase = new HandleScheduledEventUseCase(
|
|
511
516
|
projectRequiredFieldCreateUseCase,
|
|
512
517
|
setupTowerDefenceProjectUseCase,
|
|
@@ -531,6 +536,7 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
531
536
|
agentDesignationLabelAdoptUseCase,
|
|
532
537
|
updateRateLimitCacheUseCase,
|
|
533
538
|
dailySecurityScanUseCase,
|
|
539
|
+
qualityCheckAdvanceUseCase,
|
|
534
540
|
systemDateRepository,
|
|
535
541
|
googleSpreadsheetRepository,
|
|
536
542
|
projectRepository,
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
fetchWithGitHubRateLimitRetry,
|
|
41
41
|
computeRateLimitResetIso,
|
|
42
42
|
hasRateLimitSignals,
|
|
43
|
+
GitHubRateLimitError,
|
|
43
44
|
} from './githubRateLimitRetry';
|
|
44
45
|
|
|
45
46
|
export const FULL_ISSUE_FETCH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -593,6 +594,24 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
593
594
|
request: () => Promise<Response>,
|
|
594
595
|
): Promise<Response> => fetchWithGitHubRateLimitRetry(request, this.sleep);
|
|
595
596
|
|
|
597
|
+
private throwGitHubError = async (
|
|
598
|
+
prefix: string,
|
|
599
|
+
response: Response,
|
|
600
|
+
): Promise<never> => {
|
|
601
|
+
const bodyText = await response.clone().text();
|
|
602
|
+
const isRateLimit = hasRateLimitSignals(
|
|
603
|
+
response.status,
|
|
604
|
+
response.headers,
|
|
605
|
+
bodyText,
|
|
606
|
+
);
|
|
607
|
+
const formatted = await this.formatGitHubErrorWithStatus(response);
|
|
608
|
+
const message = `${prefix}: ${formatted}`;
|
|
609
|
+
if (isRateLimit) {
|
|
610
|
+
throw new GitHubRateLimitError(message);
|
|
611
|
+
}
|
|
612
|
+
throw new Error(message);
|
|
613
|
+
};
|
|
614
|
+
|
|
596
615
|
updateStatus: (
|
|
597
616
|
project: Project,
|
|
598
617
|
issue: Issue,
|
|
@@ -1786,8 +1805,9 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
1786
1805
|
);
|
|
1787
1806
|
|
|
1788
1807
|
if (!response.ok) {
|
|
1789
|
-
|
|
1790
|
-
|
|
1808
|
+
await this.throwGitHubError(
|
|
1809
|
+
'Failed to fetch issue timeline from GitHub GraphQL API',
|
|
1810
|
+
response,
|
|
1791
1811
|
);
|
|
1792
1812
|
}
|
|
1793
1813
|
|
|
@@ -1992,9 +2012,9 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
1992
2012
|
return null;
|
|
1993
2013
|
}
|
|
1994
2014
|
if (!response.ok) {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
2015
|
+
await this.throwGitHubError(
|
|
2016
|
+
`Failed to fetch pull request status for ${prUrl}`,
|
|
2017
|
+
response,
|
|
1998
2018
|
);
|
|
1999
2019
|
}
|
|
2000
2020
|
const body: unknown = await response.json();
|
|
@@ -2747,8 +2767,7 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
2747
2767
|
getIssueOrPullRequestBody = async (url: string): Promise<string> => {
|
|
2748
2768
|
const response = await this.fetchIssueBodyResponse(url);
|
|
2749
2769
|
if (!response.ok) {
|
|
2750
|
-
|
|
2751
|
-
throw new Error(`Failed to fetch body for ${url}: ${reason}`);
|
|
2770
|
+
await this.throwGitHubError(`Failed to fetch body for ${url}`, response);
|
|
2752
2771
|
}
|
|
2753
2772
|
return this.parseIssueBodyResponse(url, response);
|
|
2754
2773
|
};
|
|
@@ -2787,8 +2806,10 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
2787
2806
|
),
|
|
2788
2807
|
);
|
|
2789
2808
|
if (!response.ok) {
|
|
2790
|
-
|
|
2791
|
-
|
|
2809
|
+
await this.throwGitHubError(
|
|
2810
|
+
`Failed to fetch comments for ${url}`,
|
|
2811
|
+
response,
|
|
2812
|
+
);
|
|
2792
2813
|
}
|
|
2793
2814
|
const body: unknown = await response.json();
|
|
2794
2815
|
if (!isIssueCommentsResponse(body)) {
|
|
@@ -2837,8 +2858,10 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
2837
2858
|
),
|
|
2838
2859
|
);
|
|
2839
2860
|
if (!detailResponse.ok) {
|
|
2840
|
-
|
|
2841
|
-
|
|
2861
|
+
await this.throwGitHubError(
|
|
2862
|
+
`Failed to fetch detail for PR ${prUrl}`,
|
|
2863
|
+
detailResponse,
|
|
2864
|
+
);
|
|
2842
2865
|
}
|
|
2843
2866
|
const detailBody: unknown = await detailResponse.json();
|
|
2844
2867
|
if (!isPullRequestDetailResponse(detailBody)) {
|
|
@@ -2891,8 +2914,10 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
2891
2914
|
),
|
|
2892
2915
|
);
|
|
2893
2916
|
if (!response.ok) {
|
|
2894
|
-
|
|
2895
|
-
|
|
2917
|
+
await this.throwGitHubError(
|
|
2918
|
+
`Failed to fetch files for PR ${prUrl}`,
|
|
2919
|
+
response,
|
|
2920
|
+
);
|
|
2896
2921
|
}
|
|
2897
2922
|
const body: unknown = await response.json();
|
|
2898
2923
|
if (!isPullRequestDetailFilesResponse(body)) {
|
|
@@ -2952,8 +2977,10 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
2952
2977
|
),
|
|
2953
2978
|
);
|
|
2954
2979
|
if (!response.ok) {
|
|
2955
|
-
|
|
2956
|
-
|
|
2980
|
+
await this.throwGitHubError(
|
|
2981
|
+
`Failed to fetch commits for PR ${prUrl}`,
|
|
2982
|
+
response,
|
|
2983
|
+
);
|
|
2957
2984
|
}
|
|
2958
2985
|
const body: unknown = await response.json();
|
|
2959
2986
|
if (!isPullRequestCommitsResponse(body)) {
|
|
@@ -3001,8 +3028,10 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
3001
3028
|
),
|
|
3002
3029
|
);
|
|
3003
3030
|
if (!response.ok) {
|
|
3004
|
-
|
|
3005
|
-
|
|
3031
|
+
await this.throwGitHubError(
|
|
3032
|
+
`Failed to fetch state for ${url}`,
|
|
3033
|
+
response,
|
|
3034
|
+
);
|
|
3006
3035
|
}
|
|
3007
3036
|
const body: unknown = await response.json();
|
|
3008
3037
|
if (!isPullRequestDetailResponse(body)) {
|
|
@@ -3030,8 +3059,7 @@ export class ApiV3CheerioRestIssueRepository
|
|
|
3030
3059
|
),
|
|
3031
3060
|
);
|
|
3032
3061
|
if (!response.ok) {
|
|
3033
|
-
|
|
3034
|
-
throw new Error(`Failed to fetch state for ${url}: ${reason}`);
|
|
3062
|
+
await this.throwGitHubError(`Failed to fetch state for ${url}`, response);
|
|
3035
3063
|
}
|
|
3036
3064
|
const body: unknown = await response.json();
|
|
3037
3065
|
if (!isIssueOrPullRequestStateResponse(body)) {
|
|
@@ -29,6 +29,7 @@ import { ProjectRequiredFieldCreateUseCase } from './ProjectRequiredFieldCreateU
|
|
|
29
29
|
import { SetupTowerDefenceProjectUseCase } from './SetupTowerDefenceProjectUseCase';
|
|
30
30
|
import { UpdateRateLimitCacheUseCase } from './UpdateRateLimitCacheUseCase';
|
|
31
31
|
import { DailySecurityScanUseCase } from './DailySecurityScanUseCase';
|
|
32
|
+
import { QualityCheckAdvanceUseCase } from './QualityCheckAdvanceUseCase';
|
|
32
33
|
|
|
33
34
|
describe('HandleScheduledEventUseCase', () => {
|
|
34
35
|
describe('createTargetDateTimes', () => {
|
|
@@ -128,6 +129,7 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
128
129
|
mock<AgentDesignationLabelAdoptUseCase>();
|
|
129
130
|
const mockUpdateRateLimitCacheUseCase = mock<UpdateRateLimitCacheUseCase>();
|
|
130
131
|
const mockDailySecurityScanUseCase = mock<DailySecurityScanUseCase>();
|
|
132
|
+
const mockAdvanceQualityCheckUseCase = mock<QualityCheckAdvanceUseCase>();
|
|
131
133
|
const mockDateRepository = mock<DateRepository>();
|
|
132
134
|
const mockSpreadsheetRepository = mock<SpreadsheetRepository>();
|
|
133
135
|
const mockProjectRepository = mock<ProjectRepository>();
|
|
@@ -157,6 +159,7 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
157
159
|
mockAgentDesignationLabelAdoptUseCase,
|
|
158
160
|
mockUpdateRateLimitCacheUseCase,
|
|
159
161
|
mockDailySecurityScanUseCase,
|
|
162
|
+
mockAdvanceQualityCheckUseCase,
|
|
160
163
|
mockDateRepository,
|
|
161
164
|
mockSpreadsheetRepository,
|
|
162
165
|
mockProjectRepository,
|
|
@@ -1473,5 +1476,118 @@ describe('HandleScheduledEventUseCase', () => {
|
|
|
1473
1476
|
expect(lastExecutionWrite).toBeUndefined();
|
|
1474
1477
|
});
|
|
1475
1478
|
});
|
|
1479
|
+
|
|
1480
|
+
describe('autoAdvanceQualityCheckEnabled', () => {
|
|
1481
|
+
const baseInput = {
|
|
1482
|
+
projectName: 'test-project',
|
|
1483
|
+
org: 'test-org',
|
|
1484
|
+
projectUrl: 'https://github.com/test-org/test-project',
|
|
1485
|
+
manager: 'test-manager',
|
|
1486
|
+
workingReport: {
|
|
1487
|
+
repo: 'test-repo',
|
|
1488
|
+
members: ['member1'],
|
|
1489
|
+
spreadsheetUrl: 'https://docs.google.com/spreadsheets/test',
|
|
1490
|
+
},
|
|
1491
|
+
urlOfStoryView: 'https://github.com/test-org/test-project/issues',
|
|
1492
|
+
disabled: false,
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1495
|
+
it('does not call advanceQualityCheckUseCase when autoAdvanceQualityCheckEnabled is absent', async () => {
|
|
1496
|
+
await useCase.run(baseInput);
|
|
1497
|
+
|
|
1498
|
+
expect(mockAdvanceQualityCheckUseCase.run).not.toHaveBeenCalled();
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
it('does not call advanceQualityCheckUseCase when autoAdvanceQualityCheckEnabled is false', async () => {
|
|
1502
|
+
await useCase.run({
|
|
1503
|
+
...baseInput,
|
|
1504
|
+
startPreparation: {
|
|
1505
|
+
defaultAgentName: 'agent1',
|
|
1506
|
+
configFilePath: '/path/to/config.yml',
|
|
1507
|
+
maximumPreparingIssuesCount: null,
|
|
1508
|
+
autoAdvanceQualityCheckEnabled: false,
|
|
1509
|
+
},
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
expect(mockAdvanceQualityCheckUseCase.run).not.toHaveBeenCalled();
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
it('calls advanceQualityCheckUseCase when autoAdvanceQualityCheckEnabled is true', async () => {
|
|
1516
|
+
const mockProject = mock<Project>();
|
|
1517
|
+
const mockIssues: Issue[] = [];
|
|
1518
|
+
const fixedNow = new Date('2024-06-15T12:00:00Z');
|
|
1519
|
+
mockDateRepository.now.mockResolvedValue(fixedNow);
|
|
1520
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1521
|
+
issues: mockIssues,
|
|
1522
|
+
project: mockProject,
|
|
1523
|
+
cacheUsed: false,
|
|
1524
|
+
});
|
|
1525
|
+
|
|
1526
|
+
await useCase.run({
|
|
1527
|
+
...baseInput,
|
|
1528
|
+
startPreparation: {
|
|
1529
|
+
defaultAgentName: 'agent1',
|
|
1530
|
+
configFilePath: '/path/to/config.yml',
|
|
1531
|
+
maximumPreparingIssuesCount: null,
|
|
1532
|
+
autoAdvanceQualityCheckEnabled: true,
|
|
1533
|
+
},
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
expect(mockAdvanceQualityCheckUseCase.run).toHaveBeenCalledWith(
|
|
1537
|
+
expect.objectContaining({
|
|
1538
|
+
project: mockProject,
|
|
1539
|
+
issues: mockIssues,
|
|
1540
|
+
evaluatedAt: fixedNow,
|
|
1541
|
+
}),
|
|
1542
|
+
);
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
it('passes awaitingQualityCheckStatus to advanceQualityCheckUseCase when configured', async () => {
|
|
1546
|
+
const mockProject = mock<Project>();
|
|
1547
|
+
mockIssueRepository.getAllIssues.mockResolvedValue({
|
|
1548
|
+
issues: [],
|
|
1549
|
+
project: mockProject,
|
|
1550
|
+
cacheUsed: false,
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
await useCase.run({
|
|
1554
|
+
...baseInput,
|
|
1555
|
+
startPreparation: {
|
|
1556
|
+
defaultAgentName: 'agent1',
|
|
1557
|
+
configFilePath: '/path/to/config.yml',
|
|
1558
|
+
maximumPreparingIssuesCount: null,
|
|
1559
|
+
autoAdvanceQualityCheckEnabled: true,
|
|
1560
|
+
awaitingQualityCheckStatus: 'Custom Review Status',
|
|
1561
|
+
},
|
|
1562
|
+
});
|
|
1563
|
+
|
|
1564
|
+
expect(mockAdvanceQualityCheckUseCase.run).toHaveBeenCalledWith(
|
|
1565
|
+
expect.objectContaining({
|
|
1566
|
+
awaitingQualityCheckStatusName: 'Custom Review Status',
|
|
1567
|
+
}),
|
|
1568
|
+
);
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
it('continues to startPreparationUseCase when qualityCheckAdvanceUseCase.run rejects', async () => {
|
|
1572
|
+
mockAdvanceQualityCheckUseCase.run.mockRejectedValue(
|
|
1573
|
+
new AggregateError(
|
|
1574
|
+
[new Error('GitHub API rate limit')],
|
|
1575
|
+
'Failed to advance 1 issue(s) from Awaiting Quality Check to Done',
|
|
1576
|
+
),
|
|
1577
|
+
);
|
|
1578
|
+
|
|
1579
|
+
await useCase.run({
|
|
1580
|
+
...baseInput,
|
|
1581
|
+
startPreparation: {
|
|
1582
|
+
defaultAgentName: 'agent1',
|
|
1583
|
+
configFilePath: '/path/to/config.yml',
|
|
1584
|
+
maximumPreparingIssuesCount: null,
|
|
1585
|
+
autoAdvanceQualityCheckEnabled: true,
|
|
1586
|
+
},
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
expect(mockStartPreparationUseCase.run).toHaveBeenCalled();
|
|
1590
|
+
});
|
|
1591
|
+
});
|
|
1476
1592
|
});
|
|
1477
1593
|
});
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
DailySecurityScanConfig,
|
|
38
38
|
DailySecurityScanUseCase,
|
|
39
39
|
} from './DailySecurityScanUseCase';
|
|
40
|
+
import { QualityCheckAdvanceUseCase } from './QualityCheckAdvanceUseCase';
|
|
40
41
|
|
|
41
42
|
export class ProjectNotFoundError extends Error {
|
|
42
43
|
constructor(message: string) {
|
|
@@ -139,6 +140,7 @@ export class HandleScheduledEventUseCase {
|
|
|
139
140
|
readonly agentDesignationLabelAdoptUseCase: AgentDesignationLabelAdoptUseCase,
|
|
140
141
|
readonly updateRateLimitCacheUseCase: UpdateRateLimitCacheUseCase | null,
|
|
141
142
|
readonly dailySecurityScanUseCase: DailySecurityScanUseCase | null,
|
|
143
|
+
readonly qualityCheckAdvanceUseCase: QualityCheckAdvanceUseCase,
|
|
142
144
|
readonly dateRepository: DateRepository,
|
|
143
145
|
readonly spreadsheetRepository: SpreadsheetRepository,
|
|
144
146
|
readonly projectRepository: ProjectRepository,
|
|
@@ -177,6 +179,7 @@ export class HandleScheduledEventUseCase {
|
|
|
177
179
|
awLogDirectoryPath?: string;
|
|
178
180
|
awLogStaleThresholdMinutes?: number;
|
|
179
181
|
awaitingQualityCheckStatus?: string | null;
|
|
182
|
+
autoAdvanceQualityCheckEnabled?: boolean;
|
|
180
183
|
labelsAsLlmAgentName?: string[] | null;
|
|
181
184
|
} | null;
|
|
182
185
|
thresholdForAutoReject?: number;
|
|
@@ -333,6 +336,7 @@ export class HandleScheduledEventUseCase {
|
|
|
333
336
|
targetDateTimes,
|
|
334
337
|
storyIssues,
|
|
335
338
|
runSlowSweep,
|
|
339
|
+
now,
|
|
336
340
|
);
|
|
337
341
|
rotationOrder = useCaseResult.rotationOrder;
|
|
338
342
|
} catch (e) {
|
|
@@ -392,6 +396,7 @@ ${JSON.stringify(e)}
|
|
|
392
396
|
targetDateTimes: Date[],
|
|
393
397
|
storyObjectMap: StoryObjectMap,
|
|
394
398
|
runSlowSweep: boolean,
|
|
399
|
+
now: Date,
|
|
395
400
|
): Promise<{ rotationOrder: RotationOrderEntry[] | null }> => {
|
|
396
401
|
if (runSlowSweep) {
|
|
397
402
|
await this.runSlowSweepUseCases(
|
|
@@ -462,6 +467,22 @@ ${JSON.stringify(e)}
|
|
|
462
467
|
allowedIssueAuthors,
|
|
463
468
|
});
|
|
464
469
|
}
|
|
470
|
+
if (input.startPreparation.autoAdvanceQualityCheckEnabled) {
|
|
471
|
+
try {
|
|
472
|
+
await this.qualityCheckAdvanceUseCase.run({
|
|
473
|
+
project,
|
|
474
|
+
issues,
|
|
475
|
+
awaitingQualityCheckStatusName:
|
|
476
|
+
input.startPreparation.awaitingQualityCheckStatus ?? undefined,
|
|
477
|
+
evaluatedAt: now,
|
|
478
|
+
});
|
|
479
|
+
} catch (advanceError) {
|
|
480
|
+
console.error(
|
|
481
|
+
`[HandleScheduledEvent] Failed to advance quality check items for project ${project.url}: ${advanceError instanceof Error ? advanceError.message : String(advanceError)}`,
|
|
482
|
+
advanceError,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
465
486
|
const preparationResult = await this.startPreparationUseCase.run({
|
|
466
487
|
projectUrl: input.projectUrl,
|
|
467
488
|
defaultAgentName: input.startPreparation.defaultAgentName,
|