github-issue-tower-defence-management 1.166.0 → 1.166.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 +7 -0
- package/bin/domain/usecases/ClearDependedIssueURLUseCase.js +32 -24
- package/bin/domain/usecases/ClearDependedIssueURLUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/usecases/ClearDependedIssueURLUseCase.test.ts +80 -1
- package/src/domain/usecases/ClearDependedIssueURLUseCase.ts +45 -31
- package/types/domain/usecases/ClearDependedIssueURLUseCase.d.ts +1 -0
- package/types/domain/usecases/ClearDependedIssueURLUseCase.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.166.1](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.166.0...v1.166.1) (2026-08-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **depended-issue:** clear closed depended issue urls on every slow sweep ([#1647](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1647)) ([e796a40](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/e796a40514f53380c504e62930df9343fdfac2e2))
|
|
7
|
+
|
|
1
8
|
# [1.166.0](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.165.1...v1.166.0) (2026-08-21)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -6,47 +6,35 @@ class ClearDependedIssueURLUseCase {
|
|
|
6
6
|
this.issueRepository = issueRepository;
|
|
7
7
|
this.run = async (input) => {
|
|
8
8
|
const dependedIssueUrlSeparatedByComma = input.project.dependedIssueUrlSeparatedByComma;
|
|
9
|
-
if (!dependedIssueUrlSeparatedByComma
|
|
9
|
+
if (!dependedIssueUrlSeparatedByComma) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
+
const absentDependedIssueIsResolvable = !input.cacheUsed;
|
|
12
13
|
for (const issue of input.issues) {
|
|
13
14
|
if (issue.dependedIssueUrls.length <= 0 || issue.isClosed) {
|
|
14
15
|
continue;
|
|
15
16
|
}
|
|
16
|
-
const circularDependedIssueUrls =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const stack = [dependedIssueUrl];
|
|
20
|
-
while (stack.length > 0) {
|
|
21
|
-
const url = stack.pop();
|
|
22
|
-
if (!url) {
|
|
23
|
-
throw new Error('url is undefined');
|
|
24
|
-
}
|
|
25
|
-
if (circularDependedIssues.has(url)) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
circularDependedIssues.add(url);
|
|
29
|
-
const dependedIssue = input.issues.find((issue) => issue.url === url);
|
|
30
|
-
if (!dependedIssue) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
stack.push(...dependedIssue.dependedIssueUrls);
|
|
34
|
-
}
|
|
35
|
-
return circularDependedIssues.has(issue.url);
|
|
36
|
-
});
|
|
17
|
+
const circularDependedIssueUrls = absentDependedIssueIsResolvable
|
|
18
|
+
? this.findCircularDependedIssueUrls(issue, input.issues)
|
|
19
|
+
: [];
|
|
37
20
|
if (circularDependedIssueUrls.length > 0) {
|
|
38
21
|
await this.issueRepository.clearProjectField(input.project, dependedIssueUrlSeparatedByComma.fieldId, issue);
|
|
39
22
|
await this.issueRepository.createComment(issue, `Circular dependency removed:
|
|
40
23
|
${circularDependedIssueUrls.map((url) => `- ${url}`).join('\n')}`);
|
|
41
24
|
continue;
|
|
42
25
|
}
|
|
43
|
-
const notFoundDependedIssueUrls =
|
|
44
|
-
|
|
26
|
+
const notFoundDependedIssueUrls = absentDependedIssueIsResolvable
|
|
27
|
+
? issue.dependedIssueUrls.filter((dependedIssueUrl) => !input.issues.some((depIssue) => depIssue.url === dependedIssueUrl))
|
|
28
|
+
: [];
|
|
29
|
+
const openDependedIssueUrls = issue.dependedIssueUrls.filter((dependedIssueUrl) => input.issues.some((depIssue) => depIssue.url === dependedIssueUrl && !depIssue.isClosed));
|
|
45
30
|
const closedDependedIssueUrls = issue.dependedIssueUrls.filter((dependedIssueUrl) => input.issues.some((depIssue) => depIssue.url === dependedIssueUrl && depIssue.isClosed));
|
|
46
31
|
if (notFoundDependedIssueUrls.length === 0 &&
|
|
47
32
|
closedDependedIssueUrls.length === 0) {
|
|
48
33
|
continue;
|
|
49
34
|
}
|
|
35
|
+
const remainingDependedIssueUrls = absentDependedIssueIsResolvable
|
|
36
|
+
? openDependedIssueUrls
|
|
37
|
+
: issue.dependedIssueUrls.filter((dependedIssueUrl) => !closedDependedIssueUrls.includes(dependedIssueUrl));
|
|
50
38
|
if (remainingDependedIssueUrls.length === 0) {
|
|
51
39
|
await this.issueRepository.clearProjectField(input.project, dependedIssueUrlSeparatedByComma.fieldId, issue);
|
|
52
40
|
}
|
|
@@ -65,6 +53,26 @@ ${notFoundDependedIssueUrls.map((url) => `- ${url}`).join('\n')}`);
|
|
|
65
53
|
}
|
|
66
54
|
}
|
|
67
55
|
};
|
|
56
|
+
this.findCircularDependedIssueUrls = (issue, issues) => issue.dependedIssueUrls.filter((dependedIssueUrl) => {
|
|
57
|
+
const reachableIssueUrls = new Set();
|
|
58
|
+
const stack = [dependedIssueUrl];
|
|
59
|
+
while (stack.length > 0) {
|
|
60
|
+
const url = stack.pop();
|
|
61
|
+
if (!url) {
|
|
62
|
+
throw new Error('url is undefined');
|
|
63
|
+
}
|
|
64
|
+
if (reachableIssueUrls.has(url)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
reachableIssueUrls.add(url);
|
|
68
|
+
const dependedIssue = issues.find((candidate) => candidate.url === url);
|
|
69
|
+
if (!dependedIssue) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
stack.push(...dependedIssue.dependedIssueUrls);
|
|
73
|
+
}
|
|
74
|
+
return reachableIssueUrls.has(issue.url);
|
|
75
|
+
});
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
exports.ClearDependedIssueURLUseCase = ClearDependedIssueURLUseCase;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClearDependedIssueURLUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ClearDependedIssueURLUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,4BAA4B;IACvC,YACW,eAGR;QAHQ,oBAAe,GAAf,eAAe,CAGvB;QAGH,QAAG,GAAG,KAAK,EAAE,KAIZ,EAAiB,EAAE;YAClB,MAAM,gCAAgC,GACpC,KAAK,CAAC,OAAO,CAAC,gCAAgC,CAAC;YACjD,IAAI,CAAC,gCAAgC,
|
|
1
|
+
{"version":3,"file":"ClearDependedIssueURLUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ClearDependedIssueURLUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,4BAA4B;IACvC,YACW,eAGR;QAHQ,oBAAe,GAAf,eAAe,CAGvB;QAGH,QAAG,GAAG,KAAK,EAAE,KAIZ,EAAiB,EAAE;YAClB,MAAM,gCAAgC,GACpC,KAAK,CAAC,OAAO,CAAC,gCAAgC,CAAC;YACjD,IAAI,CAAC,gCAAgC,EAAE,CAAC;gBACtC,OAAO;YACT,CAAC;YACD,MAAM,+BAA+B,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;YACzD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBAC1D,SAAS;gBACX,CAAC;gBACD,MAAM,yBAAyB,GAAG,+BAA+B;oBAC/D,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC;oBACzD,CAAC,CAAC,EAAE,CAAC;gBACP,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAC1C,KAAK,CAAC,OAAO,EACb,gCAAgC,CAAC,OAAO,EACxC,KAAK,CACN,CAAC;oBACF,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACtC,KAAK,EACL;EACR,yBAAyB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxD,CAAC;oBACF,SAAS;gBACX,CAAC;gBACD,MAAM,yBAAyB,GAAG,+BAA+B;oBAC/D,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAC5B,CAAC,gBAAgB,EAAE,EAAE,CACnB,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAChB,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,gBAAgB,CAChD,CACJ;oBACH,CAAC,CAAC,EAAE,CAAC;gBACP,MAAM,qBAAqB,GAAG,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAC1D,CAAC,gBAAgB,EAAE,EAAE,CACnB,KAAK,CAAC,MAAM,CAAC,IAAI,CACf,CAAC,QAAQ,EAAE,EAAE,CACX,QAAQ,CAAC,GAAG,KAAK,gBAAgB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAC1D,CACJ,CAAC;gBACF,MAAM,uBAAuB,GAAG,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAC5D,CAAC,gBAAgB,EAAE,EAAE,CACnB,KAAK,CAAC,MAAM,CAAC,IAAI,CACf,CAAC,QAAQ,EAAE,EAAE,CACX,QAAQ,CAAC,GAAG,KAAK,gBAAgB,IAAI,QAAQ,CAAC,QAAQ,CACzD,CACJ,CAAC;gBACF,IACE,yBAAyB,CAAC,MAAM,KAAK,CAAC;oBACtC,uBAAuB,CAAC,MAAM,KAAK,CAAC,EACpC,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,MAAM,0BAA0B,GAAG,+BAA+B;oBAChE,CAAC,CAAC,qBAAqB;oBACvB,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAC5B,CAAC,gBAAgB,EAAE,EAAE,CACnB,CAAC,uBAAuB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACtD,CAAC;gBACN,IAAI,0BAA0B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC5C,MAAM,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAC1C,KAAK,CAAC,OAAO,EACb,gCAAgC,CAAC,OAAO,EACxC,KAAK,CACN,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,eAAe,CAAC,sBAAsB,CAC/C,KAAK,CAAC,OAAO,EACb,gCAAgC,CAAC,OAAO,EACxC,KAAK,EACL,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CACrC,CAAC;gBACJ,CAAC;gBACD,IAAI,uBAAuB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvC,MAAM,UAAU,GACd,0BAA0B,CAAC,MAAM,KAAK,CAAC;wBACvC,yBAAyB,CAAC,MAAM,KAAK,CAAC,CAAC;oBACzC,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACtC,KAAK,EACL,GAAG,UAAU,CAAC,CAAC,CAAC,kEAAkE,CAAC,CAAC,CAAC,wEAAwE;EACrK,uBAAuB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;gBACJ,CAAC;gBACD,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACtC,KAAK,EACL;EACR,yBAAyB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxD,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEM,kCAA6B,GAAG,CACtC,KAAY,EACZ,MAAe,EACL,EAAE,CACZ,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,gBAAgB,EAAE,EAAE;YAClD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;YAC7C,MAAM,KAAK,GAAG,CAAC,gBAAgB,CAAC,CAAC;YACjC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACxB,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBACtC,CAAC;gBACD,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,SAAS;gBACX,CAAC;gBACD,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC5B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;gBACxE,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,SAAS;gBACX,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;YACjD,CAAC;YACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IA5HF,CAAC;CA6HL;AAnID,oEAmIC"}
|
package/package.json
CHANGED
|
@@ -259,12 +259,91 @@ describe('ClearDependedIssueURLUseCase', () => {
|
|
|
259
259
|
],
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
|
-
name: 'should
|
|
262
|
+
name: 'should call clearProjectField and createComment when dependedIssue is closed and the issue list came from the incremental cache',
|
|
263
263
|
input: {
|
|
264
264
|
project: basicProject,
|
|
265
265
|
issues: [basicIssueOne, basicIssueTwo, basicIssueThree],
|
|
266
266
|
cacheUsed: true,
|
|
267
267
|
},
|
|
268
|
+
expectedIssueRepositoryClearProjectFieldCalls: [
|
|
269
|
+
[basicProject, 'fieldId', basicIssueTwo],
|
|
270
|
+
],
|
|
271
|
+
expectedIssueRepositoryUpdateTextFieldCalls: [
|
|
272
|
+
[basicProject, 'fieldId', basicIssueThree, 'url2'],
|
|
273
|
+
],
|
|
274
|
+
expectedIssueRepositoryCreateCommentCalls: [
|
|
275
|
+
[
|
|
276
|
+
basicIssueTwo,
|
|
277
|
+
'All depended issues are already closed, dependency field cleared:\n- url1',
|
|
278
|
+
],
|
|
279
|
+
[
|
|
280
|
+
basicIssueThree,
|
|
281
|
+
'Some depended issues are already closed, removed from dependency field:\n- url1',
|
|
282
|
+
],
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'should not call clearProjectField and createComment when dependedIssue is not found and the issue list came from the incremental cache',
|
|
287
|
+
input: {
|
|
288
|
+
project: basicProject,
|
|
289
|
+
issues: [
|
|
290
|
+
basicIssueOne,
|
|
291
|
+
{
|
|
292
|
+
...basicIssueTwo,
|
|
293
|
+
dependedIssueUrls: ['url4'],
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
cacheUsed: true,
|
|
297
|
+
},
|
|
298
|
+
expectedIssueRepositoryClearProjectFieldCalls: [],
|
|
299
|
+
expectedIssueRepositoryUpdateTextFieldCalls: [],
|
|
300
|
+
expectedIssueRepositoryCreateCommentCalls: [],
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'should keep a dependedIssue that is absent from the incremental cache and remove only the closed one',
|
|
304
|
+
input: {
|
|
305
|
+
project: basicProject,
|
|
306
|
+
issues: [
|
|
307
|
+
basicIssueOne,
|
|
308
|
+
{
|
|
309
|
+
...basicIssueThree,
|
|
310
|
+
dependedIssueUrls: ['url1', 'url4'],
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
cacheUsed: true,
|
|
314
|
+
},
|
|
315
|
+
expectedIssueRepositoryClearProjectFieldCalls: [],
|
|
316
|
+
expectedIssueRepositoryUpdateTextFieldCalls: [
|
|
317
|
+
[
|
|
318
|
+
basicProject,
|
|
319
|
+
'fieldId',
|
|
320
|
+
{ ...basicIssueThree, dependedIssueUrls: ['url1', 'url4'] },
|
|
321
|
+
'url4',
|
|
322
|
+
],
|
|
323
|
+
],
|
|
324
|
+
expectedIssueRepositoryCreateCommentCalls: [
|
|
325
|
+
[
|
|
326
|
+
{ ...basicIssueThree, dependedIssueUrls: ['url1', 'url4'] },
|
|
327
|
+
'Some depended issues are already closed, removed from dependency field:\n- url1',
|
|
328
|
+
],
|
|
329
|
+
],
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: 'should not call clearProjectField and createComment for a circular dependency when the issue list came from the incremental cache',
|
|
333
|
+
input: {
|
|
334
|
+
project: basicProject,
|
|
335
|
+
issues: [
|
|
336
|
+
{
|
|
337
|
+
...basicIssueTwo,
|
|
338
|
+
dependedIssueUrls: ['url3'],
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
...basicIssueThree,
|
|
342
|
+
dependedIssueUrls: ['url2'],
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
cacheUsed: true,
|
|
346
|
+
},
|
|
268
347
|
expectedIssueRepositoryClearProjectFieldCalls: [],
|
|
269
348
|
expectedIssueRepositoryUpdateTextFieldCalls: [],
|
|
270
349
|
expectedIssueRepositoryCreateCommentCalls: [],
|
|
@@ -17,38 +17,17 @@ export class ClearDependedIssueURLUseCase {
|
|
|
17
17
|
}): Promise<void> => {
|
|
18
18
|
const dependedIssueUrlSeparatedByComma =
|
|
19
19
|
input.project.dependedIssueUrlSeparatedByComma;
|
|
20
|
-
if (!dependedIssueUrlSeparatedByComma
|
|
20
|
+
if (!dependedIssueUrlSeparatedByComma) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
+
const absentDependedIssueIsResolvable = !input.cacheUsed;
|
|
23
24
|
for (const issue of input.issues) {
|
|
24
25
|
if (issue.dependedIssueUrls.length <= 0 || issue.isClosed) {
|
|
25
26
|
continue;
|
|
26
27
|
}
|
|
27
|
-
const circularDependedIssueUrls =
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
const circularDependedIssues = new Set<string>();
|
|
31
|
-
const stack = [dependedIssueUrl];
|
|
32
|
-
while (stack.length > 0) {
|
|
33
|
-
const url = stack.pop();
|
|
34
|
-
if (!url) {
|
|
35
|
-
throw new Error('url is undefined');
|
|
36
|
-
}
|
|
37
|
-
if (circularDependedIssues.has(url)) {
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
circularDependedIssues.add(url);
|
|
41
|
-
const dependedIssue = input.issues.find(
|
|
42
|
-
(issue) => issue.url === url,
|
|
43
|
-
);
|
|
44
|
-
if (!dependedIssue) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
stack.push(...dependedIssue.dependedIssueUrls);
|
|
48
|
-
}
|
|
49
|
-
return circularDependedIssues.has(issue.url);
|
|
50
|
-
},
|
|
51
|
-
);
|
|
28
|
+
const circularDependedIssueUrls = absentDependedIssueIsResolvable
|
|
29
|
+
? this.findCircularDependedIssueUrls(issue, input.issues)
|
|
30
|
+
: [];
|
|
52
31
|
if (circularDependedIssueUrls.length > 0) {
|
|
53
32
|
await this.issueRepository.clearProjectField(
|
|
54
33
|
input.project,
|
|
@@ -62,11 +41,15 @@ ${circularDependedIssueUrls.map((url) => `- ${url}`).join('\n')}`,
|
|
|
62
41
|
);
|
|
63
42
|
continue;
|
|
64
43
|
}
|
|
65
|
-
const notFoundDependedIssueUrls =
|
|
66
|
-
(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
44
|
+
const notFoundDependedIssueUrls = absentDependedIssueIsResolvable
|
|
45
|
+
? issue.dependedIssueUrls.filter(
|
|
46
|
+
(dependedIssueUrl) =>
|
|
47
|
+
!input.issues.some(
|
|
48
|
+
(depIssue) => depIssue.url === dependedIssueUrl,
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
: [];
|
|
52
|
+
const openDependedIssueUrls = issue.dependedIssueUrls.filter(
|
|
70
53
|
(dependedIssueUrl) =>
|
|
71
54
|
input.issues.some(
|
|
72
55
|
(depIssue) =>
|
|
@@ -86,6 +69,12 @@ ${circularDependedIssueUrls.map((url) => `- ${url}`).join('\n')}`,
|
|
|
86
69
|
) {
|
|
87
70
|
continue;
|
|
88
71
|
}
|
|
72
|
+
const remainingDependedIssueUrls = absentDependedIssueIsResolvable
|
|
73
|
+
? openDependedIssueUrls
|
|
74
|
+
: issue.dependedIssueUrls.filter(
|
|
75
|
+
(dependedIssueUrl) =>
|
|
76
|
+
!closedDependedIssueUrls.includes(dependedIssueUrl),
|
|
77
|
+
);
|
|
89
78
|
if (remainingDependedIssueUrls.length === 0) {
|
|
90
79
|
await this.issueRepository.clearProjectField(
|
|
91
80
|
input.project,
|
|
@@ -119,4 +108,29 @@ ${notFoundDependedIssueUrls.map((url) => `- ${url}`).join('\n')}`,
|
|
|
119
108
|
}
|
|
120
109
|
}
|
|
121
110
|
};
|
|
111
|
+
|
|
112
|
+
private findCircularDependedIssueUrls = (
|
|
113
|
+
issue: Issue,
|
|
114
|
+
issues: Issue[],
|
|
115
|
+
): string[] =>
|
|
116
|
+
issue.dependedIssueUrls.filter((dependedIssueUrl) => {
|
|
117
|
+
const reachableIssueUrls = new Set<string>();
|
|
118
|
+
const stack = [dependedIssueUrl];
|
|
119
|
+
while (stack.length > 0) {
|
|
120
|
+
const url = stack.pop();
|
|
121
|
+
if (!url) {
|
|
122
|
+
throw new Error('url is undefined');
|
|
123
|
+
}
|
|
124
|
+
if (reachableIssueUrls.has(url)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
reachableIssueUrls.add(url);
|
|
128
|
+
const dependedIssue = issues.find((candidate) => candidate.url === url);
|
|
129
|
+
if (!dependedIssue) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
stack.push(...dependedIssue.dependedIssueUrls);
|
|
133
|
+
}
|
|
134
|
+
return reachableIssueUrls.has(issue.url);
|
|
135
|
+
});
|
|
122
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClearDependedIssueURLUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ClearDependedIssueURLUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,qBAAa,4BAA4B;IAErC,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,mBAAmB,GAAG,eAAe,GAAG,wBAAwB,CACjE;gBAHQ,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,mBAAmB,GAAG,eAAe,GAAG,wBAAwB,CACjE;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;KACpB,KAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"ClearDependedIssueURLUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ClearDependedIssueURLUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,qBAAa,4BAA4B;IAErC,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,mBAAmB,GAAG,eAAe,GAAG,wBAAwB,CACjE;gBAHQ,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,mBAAmB,GAAG,eAAe,GAAG,wBAAwB,CACjE;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;KACpB,KAAG,OAAO,CAAC,IAAI,CAAC,CA6Ff;IAEF,OAAO,CAAC,6BAA6B,CAuBhC;CACN"}
|