npm-cli-gh-issue-preparator 1.21.0 → 1.22.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 +8 -0
- package/bin/adapter/entry-points/cli/index.js +15 -1
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/repositories/FetchWebhookRepository.js +15 -0
- package/bin/adapter/repositories/FetchWebhookRepository.js.map +1 -0
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +25 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +0 -28
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/adapter-interfaces/WebhookRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/WebhookRepository.js.map +1 -0
- package/config.example.yml +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +96 -0
- package/src/adapter/entry-points/cli/index.ts +33 -1
- package/src/adapter/repositories/FetchWebhookRepository.test.ts +50 -0
- package/src/adapter/repositories/FetchWebhookRepository.ts +12 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +336 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +51 -1
- package/src/domain/usecases/StartPreparationUseCase.test.ts +6 -324
- package/src/domain/usecases/StartPreparationUseCase.ts +0 -49
- package/src/domain/usecases/adapter-interfaces/WebhookRepository.ts +3 -0
- package/types/adapter/entry-points/cli/index.d.ts +1 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/repositories/FetchWebhookRepository.d.ts +5 -0
- package/types/adapter/repositories/FetchWebhookRepository.d.ts.map +1 -0
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +5 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts +0 -5
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/WebhookRepository.d.ts +4 -0
- package/types/domain/usecases/adapter-interfaces/WebhookRepository.d.ts.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.22.1](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.22.0...v1.22.1) (2026-03-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **core:** remove workflow blocker issue skipping from StartPreparationUseCase ([a6f4b2d](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/a6f4b2db9406f35628d954f1e1958a4513295b73))
|
|
7
|
+
|
|
8
|
+
# [1.22.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.21.0...v1.22.0) (2026-03-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **core:** send webhook notification when workflow blocker issue status changes to awaiting quality check ([1269936](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/1269936add37747b524cc151524c81aadd6c17e8))
|
|
14
|
+
|
|
1
15
|
# [1.21.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.20.0...v1.21.0) (2026-03-09)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -50,6 +50,14 @@ npx npm-cli-gh-issue-preparator startDaemon --configFilePath ./config.yml --proj
|
|
|
50
50
|
npx npm-cli-gh-issue-preparator notifyFinishedIssuePreparation --configFilePath ./config.yml --issueUrl <issueUrl>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### Notify finished issue preparation with webhook notification
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
npx npm-cli-gh-issue-preparator notifyFinishedIssuePreparation --configFilePath ./config.yml --issueUrl <issueUrl> --workflowBlockerResolvedWebhookUrl 'https://example.com/webhook?url={URL}&message={MESSAGE}'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
When a workflow blocker issue's status changes to awaiting quality check, a GET request is sent to the specified webhook URL. The `{URL}` and `{MESSAGE}` placeholders are replaced with URL-encoded values.
|
|
60
|
+
|
|
53
61
|
## Contributing
|
|
54
62
|
|
|
55
63
|
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
@@ -51,6 +51,7 @@ const TowerDefenceProjectRepository_1 = require("../../repositories/TowerDefence
|
|
|
51
51
|
const GitHubIssueCommentRepository_1 = require("../../repositories/GitHubIssueCommentRepository");
|
|
52
52
|
const NodeLocalCommandRunner_1 = require("../../repositories/NodeLocalCommandRunner");
|
|
53
53
|
const OauthAPIClaudeRepository_1 = require("../../repositories/OauthAPIClaudeRepository");
|
|
54
|
+
const FetchWebhookRepository_1 = require("../../repositories/FetchWebhookRepository");
|
|
54
55
|
const getStringValue = (obj, key) => {
|
|
55
56
|
const value = obj[key];
|
|
56
57
|
return typeof value === 'string' ? value : undefined;
|
|
@@ -78,6 +79,7 @@ const loadConfigFile = (configFilePath) => {
|
|
|
78
79
|
allowedIssueAuthors: getStringValue(parsed, 'allowedIssueAuthors'),
|
|
79
80
|
awaitingQualityCheckStatus: getStringValue(parsed, 'awaitingQualityCheckStatus'),
|
|
80
81
|
thresholdForAutoReject: getNumberValue(parsed, 'thresholdForAutoReject'),
|
|
82
|
+
workflowBlockerResolvedWebhookUrl: getStringValue(parsed, 'workflowBlockerResolvedWebhookUrl'),
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
catch (error) {
|
|
@@ -198,6 +200,7 @@ program
|
|
|
198
200
|
.option('--awaitingWorkspaceStatus <status>', 'Status for issues awaiting workspace')
|
|
199
201
|
.option('--awaitingQualityCheckStatus <status>', 'Status for issues awaiting quality check')
|
|
200
202
|
.option('--thresholdForAutoReject <count>', 'Threshold for auto-escalation after consecutive rejections (default: 3)')
|
|
203
|
+
.option('--workflowBlockerResolvedWebhookUrl <url>', 'Webhook URL to notify when a workflow blocker issue status changes to awaiting quality check. Supports {URL} and {MESSAGE} placeholders.')
|
|
201
204
|
.action(async (options) => {
|
|
202
205
|
const token = process.env.GH_TOKEN;
|
|
203
206
|
if (!token) {
|
|
@@ -225,10 +228,20 @@ program
|
|
|
225
228
|
console.error('awaitingQualityCheckStatus is required. Provide via --awaitingQualityCheckStatus or config file.');
|
|
226
229
|
process.exit(1);
|
|
227
230
|
}
|
|
231
|
+
const workflowBlockerResolvedWebhookUrl = options.workflowBlockerResolvedWebhookUrl ??
|
|
232
|
+
config.workflowBlockerResolvedWebhookUrl ??
|
|
233
|
+
null;
|
|
228
234
|
const projectRepository = new TowerDefenceProjectRepository_1.TowerDefenceProjectRepository(options.configFilePath, token);
|
|
235
|
+
const towerDefenceIssueRepository = new TowerDefenceIssueRepository_1.TowerDefenceIssueRepository(options.configFilePath, token);
|
|
229
236
|
const graphqlIssueRepository = new GraphqlIssueRepository_1.GraphqlIssueRepository(token);
|
|
230
237
|
const issueCommentRepository = new GitHubIssueCommentRepository_1.GitHubIssueCommentRepository(token);
|
|
231
|
-
const
|
|
238
|
+
const webhookRepository = new FetchWebhookRepository_1.FetchWebhookRepository();
|
|
239
|
+
const useCase = new NotifyFinishedIssuePreparationUseCase_1.NotifyFinishedIssuePreparationUseCase(projectRepository, {
|
|
240
|
+
get: graphqlIssueRepository.get.bind(graphqlIssueRepository),
|
|
241
|
+
update: graphqlIssueRepository.update.bind(graphqlIssueRepository),
|
|
242
|
+
findRelatedOpenPRs: graphqlIssueRepository.findRelatedOpenPRs.bind(graphqlIssueRepository),
|
|
243
|
+
getStoryObjectMap: towerDefenceIssueRepository.getStoryObjectMap.bind(towerDefenceIssueRepository),
|
|
244
|
+
}, issueCommentRepository, webhookRepository);
|
|
232
245
|
let thresholdForAutoReject = 3;
|
|
233
246
|
const rawThreshold = options.thresholdForAutoReject ?? config.thresholdForAutoReject;
|
|
234
247
|
if (rawThreshold !== undefined) {
|
|
@@ -248,6 +261,7 @@ program
|
|
|
248
261
|
awaitingWorkspaceStatus,
|
|
249
262
|
awaitingQualityCheckStatus,
|
|
250
263
|
thresholdForAutoReject,
|
|
264
|
+
workflowBlockerResolvedWebhookUrl,
|
|
251
265
|
});
|
|
252
266
|
});
|
|
253
267
|
/* istanbul ignore next */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,oDAA4B;AAC5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,uCAAyB;AACzB,8CAAgC;AAChC,yCAAoC;AACpC,8FAA2F;AAC3F,0HAAuH;AACvH,gGAA6F;AAC7F,sFAAmF;AACnF,oGAAiG;AACjG,kGAA+F;AAC/F,sFAAmF;AACnF,0FAAuF;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FetchWebhookRepository = void 0;
|
|
4
|
+
class FetchWebhookRepository {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.sendGetRequest = async (url) => {
|
|
7
|
+
const response = await fetch(url);
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`Webhook request failed with status ${response.status}: ${response.statusText}`);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.FetchWebhookRepository = FetchWebhookRepository;
|
|
15
|
+
//# sourceMappingURL=FetchWebhookRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FetchWebhookRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FetchWebhookRepository.ts"],"names":[],"mappings":";;;AAEA,MAAa,sBAAsB;IAAnC;QACE,mBAAc,GAAG,KAAK,EAAE,GAAW,EAAiB,EAAE;YACpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,sCAAsC,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAChF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;CAAA;AATD,wDASC"}
|
|
@@ -16,10 +16,11 @@ class IllegalIssueStatusError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
exports.IllegalIssueStatusError = IllegalIssueStatusError;
|
|
18
18
|
class NotifyFinishedIssuePreparationUseCase {
|
|
19
|
-
constructor(projectRepository, issueRepository, issueCommentRepository) {
|
|
19
|
+
constructor(projectRepository, issueRepository, issueCommentRepository, webhookRepository) {
|
|
20
20
|
this.projectRepository = projectRepository;
|
|
21
21
|
this.issueRepository = issueRepository;
|
|
22
22
|
this.issueCommentRepository = issueCommentRepository;
|
|
23
|
+
this.webhookRepository = webhookRepository;
|
|
23
24
|
this.run = async (params) => {
|
|
24
25
|
let project = await this.projectRepository.getByUrl(params.projectUrl);
|
|
25
26
|
project = await this.projectRepository.prepareStatus(params.preparationStatus, project);
|
|
@@ -39,6 +40,7 @@ class NotifyFinishedIssuePreparationUseCase {
|
|
|
39
40
|
issue.status = params.awaitingQualityCheckStatus;
|
|
40
41
|
await this.issueRepository.update(issue, project);
|
|
41
42
|
await this.issueCommentRepository.createComment(issue, `Failed to pass the check autimatically for ${params.thresholdForAutoReject} times`);
|
|
43
|
+
await this.sendWorkflowBlockerNotification(params.issueUrl, params.workflowBlockerResolvedWebhookUrl, project);
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
46
|
const rejections = [];
|
|
@@ -101,12 +103,34 @@ class NotifyFinishedIssuePreparationUseCase {
|
|
|
101
103
|
if (rejections.length <= 0) {
|
|
102
104
|
issue.status = params.awaitingQualityCheckStatus;
|
|
103
105
|
await this.issueRepository.update(issue, project);
|
|
106
|
+
await this.sendWorkflowBlockerNotification(params.issueUrl, params.workflowBlockerResolvedWebhookUrl, project);
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
109
|
issue.status = params.awaitingWorkspaceStatus;
|
|
107
110
|
await this.issueRepository.update(issue, project);
|
|
108
111
|
await this.issueCommentRepository.createComment(issue, `Auto Status Check: REJECTED\n${rejections.map((r) => `- ${r.detail}`).join('\n')}`);
|
|
109
112
|
};
|
|
113
|
+
this.sendWorkflowBlockerNotification = async (issueUrl, webhookUrlTemplate, project) => {
|
|
114
|
+
if (webhookUrlTemplate === null) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const storyObjectMap = await this.issueRepository.getStoryObjectMap(project);
|
|
119
|
+
const isWorkflowBlocker = Array.from(storyObjectMap.entries()).some(([storyName, storyObject]) => storyName.toLowerCase().includes('workflow blocker') &&
|
|
120
|
+
storyObject.issues.some((issue) => issue.url === issueUrl));
|
|
121
|
+
if (!isWorkflowBlocker) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const message = `Workflow blocker resolved: ${issueUrl}`;
|
|
125
|
+
const webhookUrl = webhookUrlTemplate
|
|
126
|
+
.replace('{URL}', encodeURIComponent(issueUrl))
|
|
127
|
+
.replace('{MESSAGE}', encodeURIComponent(message));
|
|
128
|
+
await this.webhookRepository.sendGetRequest(webhookUrl);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.warn('Failed to send workflow blocker notification:', error);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
110
134
|
}
|
|
111
135
|
}
|
|
112
136
|
exports.NotifyFinishedIssuePreparationUseCase = NotifyFinishedIssuePreparationUseCase;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifyFinishedIssuePreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"NotifyFinishedIssuePreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,6 @@ class StartPreparationUseCase {
|
|
|
24
24
|
project = await this.projectRepository.prepareStatus(params.preparationStatus, project);
|
|
25
25
|
const storyObjectMap = await this.issueRepository.getStoryObjectMap(project);
|
|
26
26
|
const allIssues = await this.issueRepository.getAllOpened(project);
|
|
27
|
-
const repositoryBlockerIssues = this.createWorkflowBockerIsues(storyObjectMap);
|
|
28
27
|
const awaitingWorkspaceIssues = Array.from(storyObjectMap.values())
|
|
29
28
|
.map((storyObject) => storyObject.issues)
|
|
30
29
|
.flat()
|
|
@@ -44,11 +43,6 @@ class StartPreparationUseCase {
|
|
|
44
43
|
for (let i = 0; i < awaitingWorkspaceIssues.length &&
|
|
45
44
|
updatedCurrentPreparationIssueCount < maximumPreparingIssuesCount; i++) {
|
|
46
45
|
const issue = awaitingWorkspaceIssues[i];
|
|
47
|
-
const blockerIssueUrls = repositoryBlockerIssues.find((blocker) => issue.url.includes(blocker.orgRepo))?.blockerIssueUrls || [];
|
|
48
|
-
if (blockerIssueUrls.length > 0 &&
|
|
49
|
-
!blockerIssueUrls.includes(issue.url)) {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
46
|
if (issue.dependedIssueUrls.length > 0) {
|
|
53
47
|
continue;
|
|
54
48
|
}
|
|
@@ -77,28 +71,6 @@ class StartPreparationUseCase {
|
|
|
77
71
|
updatedCurrentPreparationIssueCount++;
|
|
78
72
|
}
|
|
79
73
|
};
|
|
80
|
-
this.createWorkflowBockerIsues = (storyObjectMap) => {
|
|
81
|
-
const workflowBlockerStory = Array.from(storyObjectMap.keys()).filter((storyName) => storyName.toLowerCase().includes('workflow blocker'));
|
|
82
|
-
if (workflowBlockerStory.length === 0) {
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
const aggregated = new Map();
|
|
86
|
-
workflowBlockerStory.forEach((storyName) => {
|
|
87
|
-
const issues = storyObjectMap
|
|
88
|
-
.get(storyName)
|
|
89
|
-
?.issues.filter((issue) => issue.state === 'OPEN') || [];
|
|
90
|
-
issues.forEach((issue) => {
|
|
91
|
-
const orgRepo = issue.url.split('/issues')[0].split('github.com/')[1];
|
|
92
|
-
const existing = aggregated.get(orgRepo) || [];
|
|
93
|
-
existing.push(issue.url);
|
|
94
|
-
aggregated.set(orgRepo, existing);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
return Array.from(aggregated.entries()).map(([orgRepo, blockerIssueUrls]) => ({
|
|
98
|
-
orgRepo,
|
|
99
|
-
blockerIssueUrls,
|
|
100
|
-
}));
|
|
101
|
-
};
|
|
102
74
|
}
|
|
103
75
|
}
|
|
104
76
|
exports.StartPreparationUseCase = StartPreparationUseCase;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhookRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/WebhookRepository.ts"],"names":[],"mappings":""}
|
package/config.example.yml
CHANGED
package/package.json
CHANGED
|
@@ -29,6 +29,11 @@ jest.mock('../../repositories/OauthAPIClaudeRepository', () => ({
|
|
|
29
29
|
isClaudeAvailable: jest.fn(),
|
|
30
30
|
})),
|
|
31
31
|
}));
|
|
32
|
+
jest.mock('../../repositories/FetchWebhookRepository', () => ({
|
|
33
|
+
FetchWebhookRepository: jest.fn().mockImplementation(() => ({
|
|
34
|
+
sendGetRequest: jest.fn(),
|
|
35
|
+
})),
|
|
36
|
+
}));
|
|
32
37
|
|
|
33
38
|
describe('CLI', () => {
|
|
34
39
|
const originalEnv = process.env;
|
|
@@ -90,6 +95,7 @@ describe('CLI', () => {
|
|
|
90
95
|
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
91
96
|
thresholdForAutoReject: 5,
|
|
92
97
|
allowedIssueAuthors: 'user1,user2',
|
|
98
|
+
workflowBlockerResolvedWebhookUrl: 'https://example.com/webhook',
|
|
93
99
|
};
|
|
94
100
|
writeConfig(config);
|
|
95
101
|
|
|
@@ -1073,6 +1079,7 @@ describe('CLI', () => {
|
|
|
1073
1079
|
awaitingWorkspaceStatus: 'Awaiting',
|
|
1074
1080
|
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
1075
1081
|
thresholdForAutoReject: 3,
|
|
1082
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
1076
1083
|
});
|
|
1077
1084
|
});
|
|
1078
1085
|
|
|
@@ -1111,6 +1118,7 @@ describe('CLI', () => {
|
|
|
1111
1118
|
awaitingWorkspaceStatus: 'Awaiting',
|
|
1112
1119
|
awaitingQualityCheckStatus: 'Override QC',
|
|
1113
1120
|
thresholdForAutoReject: 3,
|
|
1121
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
1114
1122
|
});
|
|
1115
1123
|
});
|
|
1116
1124
|
|
|
@@ -1151,6 +1159,7 @@ describe('CLI', () => {
|
|
|
1151
1159
|
awaitingWorkspaceStatus: 'Awaiting',
|
|
1152
1160
|
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
1153
1161
|
thresholdForAutoReject: 5,
|
|
1162
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
1154
1163
|
});
|
|
1155
1164
|
});
|
|
1156
1165
|
|
|
@@ -1193,6 +1202,7 @@ describe('CLI', () => {
|
|
|
1193
1202
|
awaitingWorkspaceStatus: 'Awaiting',
|
|
1194
1203
|
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
1195
1204
|
thresholdForAutoReject: 7,
|
|
1205
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
1196
1206
|
});
|
|
1197
1207
|
});
|
|
1198
1208
|
|
|
@@ -1400,5 +1410,91 @@ describe('CLI', () => {
|
|
|
1400
1410
|
consoleErrorSpy.mockRestore();
|
|
1401
1411
|
processExitSpy.mockRestore();
|
|
1402
1412
|
});
|
|
1413
|
+
|
|
1414
|
+
it('should pass workflowBlockerResolvedWebhookUrl from config file', async () => {
|
|
1415
|
+
const configWithWebhook = {
|
|
1416
|
+
...defaultConfig,
|
|
1417
|
+
workflowBlockerResolvedWebhookUrl:
|
|
1418
|
+
'https://example.com/webhook?url={URL}',
|
|
1419
|
+
};
|
|
1420
|
+
writeConfig(configWithWebhook);
|
|
1421
|
+
|
|
1422
|
+
const mockRun = jest.fn().mockResolvedValue(undefined);
|
|
1423
|
+
const MockedNotifyFinishedUseCase = jest.mocked(
|
|
1424
|
+
NotifyFinishedIssuePreparationUseCase,
|
|
1425
|
+
);
|
|
1426
|
+
|
|
1427
|
+
MockedNotifyFinishedUseCase.mockImplementation(function (
|
|
1428
|
+
this: NotifyFinishedIssuePreparationUseCase,
|
|
1429
|
+
) {
|
|
1430
|
+
this.run = mockRun;
|
|
1431
|
+
return this;
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
await program.parseAsync([
|
|
1435
|
+
'node',
|
|
1436
|
+
'test',
|
|
1437
|
+
'notifyFinishedIssuePreparation',
|
|
1438
|
+
'--configFilePath',
|
|
1439
|
+
configFilePath,
|
|
1440
|
+
'--issueUrl',
|
|
1441
|
+
'https://github.com/test/issue/1',
|
|
1442
|
+
]);
|
|
1443
|
+
|
|
1444
|
+
expect(mockRun).toHaveBeenCalledTimes(1);
|
|
1445
|
+
expect(mockRun).toHaveBeenCalledWith({
|
|
1446
|
+
projectUrl: 'https://github.com/test/project',
|
|
1447
|
+
issueUrl: 'https://github.com/test/issue/1',
|
|
1448
|
+
preparationStatus: 'Preparing',
|
|
1449
|
+
awaitingWorkspaceStatus: 'Awaiting',
|
|
1450
|
+
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
1451
|
+
thresholdForAutoReject: 3,
|
|
1452
|
+
workflowBlockerResolvedWebhookUrl:
|
|
1453
|
+
'https://example.com/webhook?url={URL}',
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
it('should pass workflowBlockerResolvedWebhookUrl from CLI overriding config', async () => {
|
|
1458
|
+
const configWithWebhook = {
|
|
1459
|
+
...defaultConfig,
|
|
1460
|
+
workflowBlockerResolvedWebhookUrl: 'https://example.com/config-webhook',
|
|
1461
|
+
};
|
|
1462
|
+
writeConfig(configWithWebhook);
|
|
1463
|
+
|
|
1464
|
+
const mockRun = jest.fn().mockResolvedValue(undefined);
|
|
1465
|
+
const MockedNotifyFinishedUseCase = jest.mocked(
|
|
1466
|
+
NotifyFinishedIssuePreparationUseCase,
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
MockedNotifyFinishedUseCase.mockImplementation(function (
|
|
1470
|
+
this: NotifyFinishedIssuePreparationUseCase,
|
|
1471
|
+
) {
|
|
1472
|
+
this.run = mockRun;
|
|
1473
|
+
return this;
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
await program.parseAsync([
|
|
1477
|
+
'node',
|
|
1478
|
+
'test',
|
|
1479
|
+
'notifyFinishedIssuePreparation',
|
|
1480
|
+
'--configFilePath',
|
|
1481
|
+
configFilePath,
|
|
1482
|
+
'--issueUrl',
|
|
1483
|
+
'https://github.com/test/issue/1',
|
|
1484
|
+
'--workflowBlockerResolvedWebhookUrl',
|
|
1485
|
+
'https://example.com/cli-webhook',
|
|
1486
|
+
]);
|
|
1487
|
+
|
|
1488
|
+
expect(mockRun).toHaveBeenCalledTimes(1);
|
|
1489
|
+
expect(mockRun).toHaveBeenCalledWith({
|
|
1490
|
+
projectUrl: 'https://github.com/test/project',
|
|
1491
|
+
issueUrl: 'https://github.com/test/issue/1',
|
|
1492
|
+
preparationStatus: 'Preparing',
|
|
1493
|
+
awaitingWorkspaceStatus: 'Awaiting',
|
|
1494
|
+
awaitingQualityCheckStatus: 'Awaiting QC',
|
|
1495
|
+
thresholdForAutoReject: 3,
|
|
1496
|
+
workflowBlockerResolvedWebhookUrl: 'https://example.com/cli-webhook',
|
|
1497
|
+
});
|
|
1498
|
+
});
|
|
1403
1499
|
});
|
|
1404
1500
|
});
|
|
@@ -13,6 +13,7 @@ import { TowerDefenceProjectRepository } from '../../repositories/TowerDefencePr
|
|
|
13
13
|
import { GitHubIssueCommentRepository } from '../../repositories/GitHubIssueCommentRepository';
|
|
14
14
|
import { NodeLocalCommandRunner } from '../../repositories/NodeLocalCommandRunner';
|
|
15
15
|
import { OauthAPIClaudeRepository } from '../../repositories/OauthAPIClaudeRepository';
|
|
16
|
+
import { FetchWebhookRepository } from '../../repositories/FetchWebhookRepository';
|
|
16
17
|
|
|
17
18
|
type ConfigFile = {
|
|
18
19
|
projectUrl?: string;
|
|
@@ -25,6 +26,7 @@ type ConfigFile = {
|
|
|
25
26
|
allowedIssueAuthors?: string;
|
|
26
27
|
awaitingQualityCheckStatus?: string;
|
|
27
28
|
thresholdForAutoReject?: number;
|
|
29
|
+
workflowBlockerResolvedWebhookUrl?: string;
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
type StartDaemonOptions = {
|
|
@@ -46,6 +48,7 @@ type NotifyFinishedOptions = {
|
|
|
46
48
|
awaitingWorkspaceStatus?: string;
|
|
47
49
|
awaitingQualityCheckStatus?: string;
|
|
48
50
|
thresholdForAutoReject?: string;
|
|
51
|
+
workflowBlockerResolvedWebhookUrl?: string;
|
|
49
52
|
configFilePath: string;
|
|
50
53
|
};
|
|
51
54
|
|
|
@@ -98,6 +101,10 @@ const loadConfigFile = (configFilePath: string): ConfigFile => {
|
|
|
98
101
|
'awaitingQualityCheckStatus',
|
|
99
102
|
),
|
|
100
103
|
thresholdForAutoReject: getNumberValue(parsed, 'thresholdForAutoReject'),
|
|
104
|
+
workflowBlockerResolvedWebhookUrl: getStringValue(
|
|
105
|
+
parsed,
|
|
106
|
+
'workflowBlockerResolvedWebhookUrl',
|
|
107
|
+
),
|
|
101
108
|
};
|
|
102
109
|
} catch (error) {
|
|
103
110
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -294,6 +301,10 @@ program
|
|
|
294
301
|
'--thresholdForAutoReject <count>',
|
|
295
302
|
'Threshold for auto-escalation after consecutive rejections (default: 3)',
|
|
296
303
|
)
|
|
304
|
+
.option(
|
|
305
|
+
'--workflowBlockerResolvedWebhookUrl <url>',
|
|
306
|
+
'Webhook URL to notify when a workflow blocker issue status changes to awaiting quality check. Supports {URL} and {MESSAGE} placeholders.',
|
|
307
|
+
)
|
|
297
308
|
.action(async (options: NotifyFinishedOptions) => {
|
|
298
309
|
const token = process.env.GH_TOKEN;
|
|
299
310
|
if (!token) {
|
|
@@ -336,17 +347,37 @@ program
|
|
|
336
347
|
process.exit(1);
|
|
337
348
|
}
|
|
338
349
|
|
|
350
|
+
const workflowBlockerResolvedWebhookUrl: string | null =
|
|
351
|
+
options.workflowBlockerResolvedWebhookUrl ??
|
|
352
|
+
config.workflowBlockerResolvedWebhookUrl ??
|
|
353
|
+
null;
|
|
354
|
+
|
|
339
355
|
const projectRepository = new TowerDefenceProjectRepository(
|
|
340
356
|
options.configFilePath,
|
|
341
357
|
token,
|
|
342
358
|
);
|
|
359
|
+
const towerDefenceIssueRepository = new TowerDefenceIssueRepository(
|
|
360
|
+
options.configFilePath,
|
|
361
|
+
token,
|
|
362
|
+
);
|
|
343
363
|
const graphqlIssueRepository = new GraphqlIssueRepository(token);
|
|
344
364
|
const issueCommentRepository = new GitHubIssueCommentRepository(token);
|
|
365
|
+
const webhookRepository = new FetchWebhookRepository();
|
|
345
366
|
|
|
346
367
|
const useCase = new NotifyFinishedIssuePreparationUseCase(
|
|
347
368
|
projectRepository,
|
|
348
|
-
|
|
369
|
+
{
|
|
370
|
+
get: graphqlIssueRepository.get.bind(graphqlIssueRepository),
|
|
371
|
+
update: graphqlIssueRepository.update.bind(graphqlIssueRepository),
|
|
372
|
+
findRelatedOpenPRs: graphqlIssueRepository.findRelatedOpenPRs.bind(
|
|
373
|
+
graphqlIssueRepository,
|
|
374
|
+
),
|
|
375
|
+
getStoryObjectMap: towerDefenceIssueRepository.getStoryObjectMap.bind(
|
|
376
|
+
towerDefenceIssueRepository,
|
|
377
|
+
),
|
|
378
|
+
},
|
|
349
379
|
issueCommentRepository,
|
|
380
|
+
webhookRepository,
|
|
350
381
|
);
|
|
351
382
|
|
|
352
383
|
let thresholdForAutoReject = 3;
|
|
@@ -374,6 +405,7 @@ program
|
|
|
374
405
|
awaitingWorkspaceStatus,
|
|
375
406
|
awaitingQualityCheckStatus,
|
|
376
407
|
thresholdForAutoReject,
|
|
408
|
+
workflowBlockerResolvedWebhookUrl,
|
|
377
409
|
});
|
|
378
410
|
});
|
|
379
411
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { FetchWebhookRepository } from './FetchWebhookRepository';
|
|
2
|
+
|
|
3
|
+
describe('FetchWebhookRepository', () => {
|
|
4
|
+
let repository: FetchWebhookRepository;
|
|
5
|
+
const originalFetch = global.fetch;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
repository = new FetchWebhookRepository();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
global.fetch = originalFetch;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should send GET request to the provided URL', async () => {
|
|
16
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
17
|
+
ok: true,
|
|
18
|
+
status: 200,
|
|
19
|
+
});
|
|
20
|
+
global.fetch = mockFetch;
|
|
21
|
+
|
|
22
|
+
await repository.sendGetRequest('https://example.com/webhook');
|
|
23
|
+
|
|
24
|
+
expect(mockFetch).toHaveBeenCalledWith('https://example.com/webhook');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should throw error when response is not ok', async () => {
|
|
28
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
29
|
+
ok: false,
|
|
30
|
+
status: 500,
|
|
31
|
+
statusText: 'Internal Server Error',
|
|
32
|
+
});
|
|
33
|
+
global.fetch = mockFetch;
|
|
34
|
+
|
|
35
|
+
await expect(
|
|
36
|
+
repository.sendGetRequest('https://example.com/webhook'),
|
|
37
|
+
).rejects.toThrow(
|
|
38
|
+
'Webhook request failed with status 500: Internal Server Error',
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should propagate network errors', async () => {
|
|
43
|
+
const mockFetch = jest.fn().mockRejectedValue(new Error('Network error'));
|
|
44
|
+
global.fetch = mockFetch;
|
|
45
|
+
|
|
46
|
+
await expect(
|
|
47
|
+
repository.sendGetRequest('https://example.com/webhook'),
|
|
48
|
+
).rejects.toThrow('Network error');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { WebhookRepository } from '../../domain/usecases/adapter-interfaces/WebhookRepository';
|
|
2
|
+
|
|
3
|
+
export class FetchWebhookRepository implements WebhookRepository {
|
|
4
|
+
sendGetRequest = async (url: string): Promise<void> => {
|
|
5
|
+
const response = await fetch(url);
|
|
6
|
+
if (!response.ok) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
`Webhook request failed with status ${response.status}: ${response.statusText}`,
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|