github-issue-tower-defence-management 1.73.2 → 1.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +3 -0
- package/bin/adapter/entry-points/cli/index.js +3 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/cli/projectConfig.js +6 -0
- package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +8 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +8 -8
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +27 -7
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.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/SetDependedIssueUrlForOpenTaskPRsUseCase.js +6 -1
- package/bin/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +21 -5
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +2 -0
- package/src/adapter/entry-points/cli/index.ts +7 -0
- package/src/adapter/entry-points/cli/projectConfig.ts +8 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +3 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +114 -1
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +21 -11
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +103 -0
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +33 -9
- package/src/domain/usecases/HandleScheduledEventUseCase.ts +3 -0
- package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.test.ts +57 -0
- package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.ts +11 -5
- package/src/domain/usecases/StartPreparationUseCase.test.ts +409 -0
- package/src/domain/usecases/StartPreparationUseCase.ts +32 -4
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/cli/projectConfig.d.ts +1 -0
- package/types/adapter/entry-points/cli/projectConfig.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.map +1 -1
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +2 -2
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.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/SetDependedIssueUrlForOpenTaskPRsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts +2 -0
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
|
@@ -663,6 +663,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
663
663
|
};
|
|
664
664
|
fetchProjectItemByUrl = async (
|
|
665
665
|
issueUrl: string,
|
|
666
|
+
projectId?: string,
|
|
666
667
|
): Promise<ProjectItem | null> => {
|
|
667
668
|
const { owner, repo, issueNumber } = this.extractIssueFromUrl(issueUrl);
|
|
668
669
|
const graphql = `query GetIssueOrPullRequest($owner: String!, $repo: String!, $number: Int!) {
|
|
@@ -693,6 +694,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
693
694
|
projectItems(first: 10) {
|
|
694
695
|
nodes {
|
|
695
696
|
id
|
|
697
|
+
project {
|
|
698
|
+
id
|
|
699
|
+
}
|
|
696
700
|
fieldValues(first: 10) {
|
|
697
701
|
nodes {
|
|
698
702
|
... on ProjectV2ItemFieldTextValue {
|
|
@@ -767,6 +771,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
767
771
|
projectItems(first: 10) {
|
|
768
772
|
nodes {
|
|
769
773
|
id
|
|
774
|
+
project {
|
|
775
|
+
id
|
|
776
|
+
}
|
|
770
777
|
fieldValues(first: 10) {
|
|
771
778
|
nodes {
|
|
772
779
|
... on ProjectV2ItemFieldTextValue {
|
|
@@ -839,6 +846,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
839
846
|
projectItems: {
|
|
840
847
|
nodes: {
|
|
841
848
|
id: string;
|
|
849
|
+
project: { id: string } | null;
|
|
842
850
|
fieldValues: {
|
|
843
851
|
nodes: {
|
|
844
852
|
text: string;
|
|
@@ -883,9 +891,16 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
883
891
|
return null;
|
|
884
892
|
}
|
|
885
893
|
const projectItems = content.projectItems.nodes;
|
|
886
|
-
const item =
|
|
894
|
+
const item = projectId
|
|
895
|
+
? projectItems.find((node) => node.project?.id === projectId)
|
|
896
|
+
: projectItems[0];
|
|
887
897
|
if (!item) {
|
|
888
|
-
|
|
898
|
+
console.warn(
|
|
899
|
+
projectId
|
|
900
|
+
? `No project item found for issue ${issueUrl} on project ${projectId}`
|
|
901
|
+
: `No project item found for issue ${issueUrl}`,
|
|
902
|
+
);
|
|
903
|
+
return null;
|
|
889
904
|
}
|
|
890
905
|
return {
|
|
891
906
|
id: item.id,
|
|
@@ -1066,13 +1081,18 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
1066
1081
|
addIssueToProject = async (
|
|
1067
1082
|
projectId: string,
|
|
1068
1083
|
issueUrl: string,
|
|
1069
|
-
): Promise<
|
|
1084
|
+
): Promise<string> => {
|
|
1070
1085
|
const { owner, repo, issueNumber } = this.extractIssueFromUrl(issueUrl);
|
|
1071
1086
|
const nodeIdQuery = {
|
|
1072
|
-
query: `query
|
|
1087
|
+
query: `query GetContentNodeId($owner: String!, $repo: String!, $number: Int!) {
|
|
1073
1088
|
repository(owner: $owner, name: $repo) {
|
|
1074
|
-
|
|
1075
|
-
|
|
1089
|
+
issueOrPullRequest(number: $number) {
|
|
1090
|
+
... on Issue {
|
|
1091
|
+
id
|
|
1092
|
+
}
|
|
1093
|
+
... on PullRequest {
|
|
1094
|
+
id
|
|
1095
|
+
}
|
|
1076
1096
|
}
|
|
1077
1097
|
}
|
|
1078
1098
|
}`,
|
|
@@ -1088,9 +1108,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
1088
1108
|
.json<{
|
|
1089
1109
|
data: {
|
|
1090
1110
|
repository: {
|
|
1091
|
-
|
|
1111
|
+
issueOrPullRequest: {
|
|
1092
1112
|
id: string;
|
|
1093
|
-
};
|
|
1113
|
+
} | null;
|
|
1094
1114
|
};
|
|
1095
1115
|
};
|
|
1096
1116
|
errors?: { message: string }[];
|
|
@@ -1098,7 +1118,10 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
1098
1118
|
if (nodeIdRes.errors) {
|
|
1099
1119
|
throw new Error(nodeIdRes.errors.map((e) => e.message).join('\n'));
|
|
1100
1120
|
}
|
|
1101
|
-
const contentId = nodeIdRes.data.repository.
|
|
1121
|
+
const contentId = nodeIdRes.data.repository.issueOrPullRequest?.id;
|
|
1122
|
+
if (!contentId) {
|
|
1123
|
+
throw new Error(`Content not found for url ${issueUrl}`);
|
|
1124
|
+
}
|
|
1102
1125
|
|
|
1103
1126
|
const addQuery = {
|
|
1104
1127
|
query: `mutation AddIssueToProject($projectId: ID!, $contentId: ID!) {
|
|
@@ -1126,5 +1149,6 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
|
|
|
1126
1149
|
if (addRes.errors) {
|
|
1127
1150
|
throw new Error(addRes.errors.map((e) => e.message).join('\n'));
|
|
1128
1151
|
}
|
|
1152
|
+
return addRes.data.addProjectV2ItemById.item.id;
|
|
1129
1153
|
};
|
|
1130
1154
|
}
|
|
@@ -81,6 +81,7 @@ export class HandleScheduledEventUseCase {
|
|
|
81
81
|
startPreparation?: {
|
|
82
82
|
defaultAgentName: string;
|
|
83
83
|
defaultLlmModelName?: string | null;
|
|
84
|
+
fallbackLlmModelName?: string | null;
|
|
84
85
|
defaultLlmAgentName?: string | null;
|
|
85
86
|
configFilePath: string;
|
|
86
87
|
maximumPreparingIssuesCount: number | null;
|
|
@@ -309,6 +310,8 @@ ${JSON.stringify(e)}
|
|
|
309
310
|
projectUrl: input.projectUrl,
|
|
310
311
|
defaultAgentName: input.startPreparation.defaultAgentName,
|
|
311
312
|
defaultLlmModelName: input.startPreparation.defaultLlmModelName ?? null,
|
|
313
|
+
fallbackLlmModelName:
|
|
314
|
+
input.startPreparation.fallbackLlmModelName ?? null,
|
|
312
315
|
defaultLlmAgentName: input.startPreparation.defaultLlmAgentName ?? null,
|
|
313
316
|
configFilePath: input.startPreparation.configFilePath,
|
|
314
317
|
maximumPreparingIssuesCount:
|
|
@@ -211,4 +211,61 @@ describe('SetDependedIssueUrlForOpenTaskPRsUseCase', () => {
|
|
|
211
211
|
secondOpenTaskIssue.url,
|
|
212
212
|
);
|
|
213
213
|
});
|
|
214
|
+
|
|
215
|
+
it('should isolate a single PR failure, log it, and still process the remaining PRs without aborting the cycle', async () => {
|
|
216
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
217
|
+
const failingPrUrl = 'https://github.com/owner/repo/pull/100';
|
|
218
|
+
const succeedingPrUrl = 'https://github.com/owner/repo/pull/200';
|
|
219
|
+
|
|
220
|
+
mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([
|
|
221
|
+
{
|
|
222
|
+
url: failingPrUrl,
|
|
223
|
+
branchName: null,
|
|
224
|
+
createdAt: new Date(0),
|
|
225
|
+
isDraft: false,
|
|
226
|
+
isConflicted: false,
|
|
227
|
+
isPassedAllCiJob: true,
|
|
228
|
+
isCiStateSuccess: true,
|
|
229
|
+
isResolvedAllReviewComments: true,
|
|
230
|
+
isBranchOutOfDate: false,
|
|
231
|
+
missingRequiredCheckNames: [],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
url: succeedingPrUrl,
|
|
235
|
+
branchName: null,
|
|
236
|
+
createdAt: new Date(0),
|
|
237
|
+
isDraft: false,
|
|
238
|
+
isConflicted: false,
|
|
239
|
+
isPassedAllCiJob: true,
|
|
240
|
+
isCiStateSuccess: true,
|
|
241
|
+
isResolvedAllReviewComments: true,
|
|
242
|
+
isBranchOutOfDate: false,
|
|
243
|
+
missingRequiredCheckNames: [],
|
|
244
|
+
},
|
|
245
|
+
]);
|
|
246
|
+
mockIssueRepository.setDependedIssueUrl.mockImplementation(
|
|
247
|
+
async (prUrl) => {
|
|
248
|
+
if (prUrl === failingPrUrl) {
|
|
249
|
+
throw new Error('boom');
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
await expect(
|
|
255
|
+
useCase.run({
|
|
256
|
+
project: projectWithField,
|
|
257
|
+
issues: [openTaskIssue],
|
|
258
|
+
}),
|
|
259
|
+
).resolves.toBeUndefined();
|
|
260
|
+
|
|
261
|
+
expect(mockIssueRepository.setDependedIssueUrl).toHaveBeenCalledTimes(2);
|
|
262
|
+
expect(mockIssueRepository.setDependedIssueUrl).toHaveBeenCalledWith(
|
|
263
|
+
succeedingPrUrl,
|
|
264
|
+
projectWithField,
|
|
265
|
+
openTaskIssue.url,
|
|
266
|
+
);
|
|
267
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
268
|
+
|
|
269
|
+
warnSpy.mockRestore();
|
|
270
|
+
});
|
|
214
271
|
});
|
|
@@ -25,11 +25,17 @@ export class SetDependedIssueUrlForOpenTaskPRsUseCase {
|
|
|
25
25
|
issue.url,
|
|
26
26
|
);
|
|
27
27
|
for (const pr of relatedOpenPRs) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
try {
|
|
29
|
+
await this.issueRepository.setDependedIssueUrl(
|
|
30
|
+
pr.url,
|
|
31
|
+
input.project,
|
|
32
|
+
issue.url,
|
|
33
|
+
);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.warn(
|
|
36
|
+
`Failed to set depended issue URL for PR ${pr.url}, skipping and continuing with remaining PRs: ${error instanceof Error ? error.message : String(error)}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
};
|