github-issue-tower-defence-management 1.148.11 → 1.148.12

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 CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.148.12](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.148.11...v1.148.12) (2026-08-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **story:** log what the new story label handling found and did on each run ([#1491](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1491)) ([3199303](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/3199303e085e44c4e820564eeaaa8142a54a6bcc))
7
+
1
8
  ## [1.148.11](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.148.10...v1.148.11) (2026-08-10)
2
9
 
3
10
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CreateNewStoryByLabelUseCase = void 0;
4
+ const LOG_PREFIX = '[CreateNewStoryByLabel]';
4
5
  class CreateNewStoryByLabelUseCase {
5
6
  constructor(projectRepository, issueRepository) {
6
7
  this.projectRepository = projectRepository;
@@ -8,23 +9,41 @@ class CreateNewStoryByLabelUseCase {
8
9
  this.run = async (input) => {
9
10
  const projectStory = input.project.story;
10
11
  if (!projectStory) {
12
+ console.log(`${LOG_PREFIX} the project has no story field, so no labelled issue is evaluated. project=${input.project.url}`);
11
13
  return;
12
14
  }
13
15
  const newStoryIssues = this.findNewStoryIssues(input.storyObjectMap, input.issues);
16
+ console.log(`${LOG_PREFIX} found ${newStoryIssues.length} issues carrying the new story label. project=${input.project.url}`);
14
17
  if (newStoryIssues.length === 0) {
15
18
  return;
16
19
  }
20
+ console.log(`${LOG_PREFIX} labelled issues: ${newStoryIssues
21
+ .map((issue) => issue.url)
22
+ .join(', ')}`);
17
23
  const newStoryList = this.createNewStoryList(projectStory, input.storyObjectMap, input.issues);
18
- const savedNewStoryList = newStoryList.some((story) => story.id === null)
19
- ? await this.projectRepository.updateStoryList(input.project, newStoryList)
20
- : projectStory.stories;
24
+ const addedStories = newStoryList.filter((story) => story.id === null);
25
+ if (addedStories.length === 0) {
26
+ console.log(`${LOG_PREFIX} every labelled issue title already names a story option, so the option list is left unchanged`);
27
+ }
28
+ else {
29
+ console.log(`${LOG_PREFIX} submitting ${addedStories.length} new story options: ${addedStories
30
+ .map((story) => story.name)
31
+ .join(', ')}`);
32
+ }
33
+ const savedNewStoryList = addedStories.length === 0
34
+ ? projectStory.stories
35
+ : await this.projectRepository.updateStoryList(input.project, newStoryList);
36
+ console.log(`${LOG_PREFIX} the story option list holds ${savedNewStoryList.length} options`);
21
37
  for (const issue of newStoryIssues) {
22
38
  const linkedStory = savedNewStoryList.find((s) => s.name === issue.title);
23
39
  if (!linkedStory) {
40
+ console.log(`${LOG_PREFIX} no story option matches the title of ${issue.url}, so it keeps the new story label`);
24
41
  continue;
25
42
  }
26
43
  await this.issueRepository.updateStory({ ...input.project, story: projectStory }, issue, linkedStory.id);
44
+ console.log(`${LOG_PREFIX} linked ${issue.url} to the story option ${linkedStory.id}`);
27
45
  await this.issueRepository.updateLabels(issue, issue.labels.filter((label) => label.toLowerCase().replace('-', '') !== 'newstory'));
46
+ console.log(`${LOG_PREFIX} removed the new story label from ${issue.url}`);
28
47
  }
29
48
  };
30
49
  this.hasNewStoryLabel = (issue) => issue.labels?.some((label) => label.toLowerCase().replace('-', '') === 'newstory') ?? false;
@@ -1 +1 @@
1
- {"version":3,"file":"CreateNewStoryByLabelUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/CreateNewStoryByLabelUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CreateNewStoryByLabelUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/CreateNewStoryByLabelUseCase.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.148.11",
3
+ "version": "1.148.12",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -96,6 +96,222 @@ describe('CreateNewStoryByLabelUseCase', () => {
96
96
  );
97
97
  });
98
98
 
99
+ describe('logging', () => {
100
+ let logSpy: jest.SpyInstance;
101
+ const lines: string[] = [];
102
+
103
+ beforeEach(() => {
104
+ lines.length = 0;
105
+ logSpy = jest
106
+ .spyOn(console, 'log')
107
+ .mockImplementation((...args: unknown[]) => {
108
+ lines.push(args.map((arg) => String(arg)).join(' '));
109
+ });
110
+ });
111
+
112
+ afterEach(() => {
113
+ logSpy.mockRestore();
114
+ });
115
+
116
+ const loggedLines = (): string[] => lines;
117
+
118
+ it('should record that the option list was left unchanged because every labelled issue title already names a story option', async () => {
119
+ const projectWithExistingOption: Project = {
120
+ ...basicProject,
121
+ story: {
122
+ name: 'Story Field',
123
+ fieldId: 'storyFieldId',
124
+ databaseId: 123,
125
+ stories: [
126
+ {
127
+ id: 'existingNewStoryId',
128
+ name: 'New Feature Request',
129
+ color: 'RED',
130
+ description: '',
131
+ },
132
+ ],
133
+ workflowManagementStory: { id: 'workflow1', name: 'Workflow Story' },
134
+ },
135
+ };
136
+
137
+ await useCase.run({
138
+ project: projectWithExistingOption,
139
+ cacheUsed: false,
140
+ org: 'testOrg',
141
+ repo: 'testRepo',
142
+ storyObjectMap: new Map([
143
+ [
144
+ 'Story 1',
145
+ {
146
+ story: mock<StoryOption>(),
147
+ storyIssue: mock<Issue>(),
148
+ issues: [issueWithNewStoryLabel],
149
+ },
150
+ ],
151
+ ]),
152
+ issues: [],
153
+ });
154
+
155
+ expect(mockProjectRepository.updateStoryList).not.toHaveBeenCalled();
156
+ expect(
157
+ loggedLines().some((line) =>
158
+ line.includes(
159
+ 'every labelled issue title already names a story option',
160
+ ),
161
+ ),
162
+ ).toBe(true);
163
+ });
164
+
165
+ it('should record that the run found no labelled issue so that the absence of work is distinguishable from the step never running', async () => {
166
+ const storyObjectWithoutNewStoryIssues: StoryObject = {
167
+ story: mock<StoryOption>(),
168
+ storyIssue: mock<Issue>(),
169
+ issues: [regularIssue],
170
+ };
171
+
172
+ await useCase.run({
173
+ project: basicProject,
174
+ cacheUsed: false,
175
+ org: 'testOrg',
176
+ repo: 'testRepo',
177
+ storyObjectMap: new Map([
178
+ ['Story 1', storyObjectWithoutNewStoryIssues],
179
+ ]),
180
+ issues: [regularIssue],
181
+ });
182
+
183
+ expect(
184
+ loggedLines().some((line) =>
185
+ line.includes('found 0 issues carrying the new story label'),
186
+ ),
187
+ ).toBe(true);
188
+ });
189
+
190
+ it('should record the project having no story field', async () => {
191
+ await useCase.run({
192
+ project: { ...basicProject, story: null },
193
+ cacheUsed: false,
194
+ org: 'testOrg',
195
+ repo: 'testRepo',
196
+ storyObjectMap: new Map([['Story 1', storyObjectWithNewStoryIssues]]),
197
+ issues: [],
198
+ });
199
+
200
+ expect(
201
+ loggedLines().some((line) =>
202
+ line.includes('the project has no story field'),
203
+ ),
204
+ ).toBe(true);
205
+ });
206
+
207
+ it('should record the labelled issues, the submitted options, the story link and the label removal', async () => {
208
+ mockProjectRepository.updateStoryList.mockResolvedValue([
209
+ { id: 'story1', name: 'First Story', color: 'BLUE', description: '' },
210
+ {
211
+ id: 'newStoryId1',
212
+ name: 'New Feature Request',
213
+ color: 'RED',
214
+ description: '',
215
+ },
216
+ ]);
217
+ const storyObject: StoryObject = {
218
+ story: {
219
+ ...mock<StoryOption>(),
220
+ id: 'story1',
221
+ name: 'Existing Story',
222
+ color: 'BLUE',
223
+ },
224
+ storyIssue: mock<Issue>(),
225
+ issues: [issueWithNewStoryLabel],
226
+ };
227
+
228
+ await useCase.run({
229
+ project: basicProject,
230
+ cacheUsed: false,
231
+ org: 'testOrg',
232
+ repo: 'testRepo',
233
+ storyObjectMap: new Map([['Story 1', storyObject]]),
234
+ issues: [],
235
+ });
236
+
237
+ const lines = loggedLines();
238
+ expect(
239
+ lines.some((line) =>
240
+ line.includes('found 1 issues carrying the new story label'),
241
+ ),
242
+ ).toBe(true);
243
+ expect(
244
+ lines.some(
245
+ (line) =>
246
+ line.includes('labelled issues') &&
247
+ line.includes(issueWithNewStoryLabel.url),
248
+ ),
249
+ ).toBe(true);
250
+ expect(
251
+ lines.some(
252
+ (line) =>
253
+ line.includes('submitting 1 new story options') &&
254
+ line.includes('New Feature Request'),
255
+ ),
256
+ ).toBe(true);
257
+ expect(
258
+ lines.some(
259
+ (line) =>
260
+ line.includes('linked') &&
261
+ line.includes(issueWithNewStoryLabel.url) &&
262
+ line.includes('newStoryId1'),
263
+ ),
264
+ ).toBe(true);
265
+ expect(
266
+ lines.some(
267
+ (line) =>
268
+ line.includes('removed the new story label') &&
269
+ line.includes(issueWithNewStoryLabel.url),
270
+ ),
271
+ ).toBe(true);
272
+ });
273
+
274
+ it('should record that an issue kept its label because no story option matches its title', async () => {
275
+ const issueWithUnmatchedTitle: Issue = {
276
+ ...mock<Issue>(),
277
+ url: 'https://github.com/org/repo/issues/1401',
278
+ title: 'Unmatched Title',
279
+ number: 1401,
280
+ story: 'Existing Story',
281
+ labels: ['new-story'],
282
+ };
283
+ mockProjectRepository.updateStoryList.mockResolvedValue([
284
+ { id: 'story1', name: 'First Story', color: 'BLUE', description: '' },
285
+ ]);
286
+
287
+ await useCase.run({
288
+ project: basicProject,
289
+ cacheUsed: false,
290
+ org: 'testOrg',
291
+ repo: 'testRepo',
292
+ storyObjectMap: new Map([
293
+ [
294
+ 'Story 1',
295
+ {
296
+ story: mock<StoryOption>(),
297
+ storyIssue: mock<Issue>(),
298
+ issues: [issueWithUnmatchedTitle],
299
+ },
300
+ ],
301
+ ]),
302
+ issues: [],
303
+ });
304
+
305
+ expect(
306
+ loggedLines().some(
307
+ (line) =>
308
+ line.includes('no story option matches the title') &&
309
+ line.includes(issueWithUnmatchedTitle.url),
310
+ ),
311
+ ).toBe(true);
312
+ });
313
+ });
314
+
99
315
  describe('run', () => {
100
316
  it('should not process anything when project has no story field', async () => {
101
317
  const projectWithoutStory: Project = {
@@ -4,6 +4,8 @@ import { StoryObjectMap } from '../entities/StoryObjectMap';
4
4
  import { ProjectRepository } from './adapter-interfaces/ProjectRepository';
5
5
  import { Issue } from '../entities/Issue';
6
6
 
7
+ const LOG_PREFIX = '[CreateNewStoryByLabel]';
8
+
7
9
  export class CreateNewStoryByLabelUseCase {
8
10
  constructor(
9
11
  readonly projectRepository: Pick<ProjectRepository, 'updateStoryList'>,
@@ -23,30 +25,60 @@ export class CreateNewStoryByLabelUseCase {
23
25
  }): Promise<void> => {
24
26
  const projectStory = input.project.story;
25
27
  if (!projectStory) {
28
+ console.log(
29
+ `${LOG_PREFIX} the project has no story field, so no labelled issue is evaluated. project=${input.project.url}`,
30
+ );
26
31
  return;
27
32
  }
28
33
  const newStoryIssues = this.findNewStoryIssues(
29
34
  input.storyObjectMap,
30
35
  input.issues,
31
36
  );
37
+ console.log(
38
+ `${LOG_PREFIX} found ${newStoryIssues.length} issues carrying the new story label. project=${input.project.url}`,
39
+ );
32
40
  if (newStoryIssues.length === 0) {
33
41
  return;
34
42
  }
43
+ console.log(
44
+ `${LOG_PREFIX} labelled issues: ${newStoryIssues
45
+ .map((issue) => issue.url)
46
+ .join(', ')}`,
47
+ );
35
48
  const newStoryList = this.createNewStoryList(
36
49
  projectStory,
37
50
  input.storyObjectMap,
38
51
  input.issues,
39
52
  );
40
- const savedNewStoryList = newStoryList.some((story) => story.id === null)
41
- ? await this.projectRepository.updateStoryList(
42
- input.project,
43
- newStoryList,
44
- )
45
- : projectStory.stories;
53
+ const addedStories = newStoryList.filter((story) => story.id === null);
54
+ if (addedStories.length === 0) {
55
+ console.log(
56
+ `${LOG_PREFIX} every labelled issue title already names a story option, so the option list is left unchanged`,
57
+ );
58
+ } else {
59
+ console.log(
60
+ `${LOG_PREFIX} submitting ${addedStories.length} new story options: ${addedStories
61
+ .map((story) => story.name)
62
+ .join(', ')}`,
63
+ );
64
+ }
65
+ const savedNewStoryList =
66
+ addedStories.length === 0
67
+ ? projectStory.stories
68
+ : await this.projectRepository.updateStoryList(
69
+ input.project,
70
+ newStoryList,
71
+ );
72
+ console.log(
73
+ `${LOG_PREFIX} the story option list holds ${savedNewStoryList.length} options`,
74
+ );
46
75
 
47
76
  for (const issue of newStoryIssues) {
48
77
  const linkedStory = savedNewStoryList.find((s) => s.name === issue.title);
49
78
  if (!linkedStory) {
79
+ console.log(
80
+ `${LOG_PREFIX} no story option matches the title of ${issue.url}, so it keeps the new story label`,
81
+ );
50
82
  continue;
51
83
  }
52
84
  await this.issueRepository.updateStory(
@@ -54,12 +86,18 @@ export class CreateNewStoryByLabelUseCase {
54
86
  issue,
55
87
  linkedStory.id,
56
88
  );
89
+ console.log(
90
+ `${LOG_PREFIX} linked ${issue.url} to the story option ${linkedStory.id}`,
91
+ );
57
92
  await this.issueRepository.updateLabels(
58
93
  issue,
59
94
  issue.labels.filter(
60
95
  (label) => label.toLowerCase().replace('-', '') !== 'newstory',
61
96
  ),
62
97
  );
98
+ console.log(
99
+ `${LOG_PREFIX} removed the new story label from ${issue.url}`,
100
+ );
63
101
  }
64
102
  };
65
103
 
@@ -1 +1 @@
1
- {"version":3,"file":"CreateNewStoryByLabelUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/CreateNewStoryByLabelUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,qBAAa,4BAA4B;IAErC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IACtE,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,cAAc,GAAG,aAAa,CAC/B;gBAJQ,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,EAC7D,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,cAAc,GAAG,aAAa,CAC/B;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,cAAc,CAAC;QAC/B,MAAM,EAAE,KAAK,EAAE,CAAC;KACjB,KAAG,OAAO,CAAC,IAAI,CAAC,CAyCf;IAEF,gBAAgB,GAAI,OAAO,KAAK,KAAG,OAAO,CAG7B;IAEb,kBAAkB,GAChB,gBAAgB,cAAc,EAC9B,QAAQ,KAAK,EAAE,KACd,KAAK,EAAE,CAeR;IAEF,kBAAkB,GAChB,cAAc,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAC3C,gBAAgB,cAAc,EAC9B,QAAQ,KAAK,EAAE,KACd,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC,EAAE,CA8B/D;CACH"}
1
+ {"version":3,"file":"CreateNewStoryByLabelUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/CreateNewStoryByLabelUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C,qBAAa,4BAA4B;IAErC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IACtE,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,cAAc,GAAG,aAAa,CAC/B;gBAJQ,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,EAC7D,eAAe,EAAE,IAAI,CAC5B,eAAe,EACf,cAAc,GAAG,aAAa,CAC/B;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,cAAc,CAAC;QAC/B,MAAM,EAAE,KAAK,EAAE,CAAC;KACjB,KAAG,OAAO,CAAC,IAAI,CAAC,CA6Ef;IAEF,gBAAgB,GAAI,OAAO,KAAK,KAAG,OAAO,CAG7B;IAEb,kBAAkB,GAChB,gBAAgB,cAAc,EAC9B,QAAQ,KAAK,EAAE,KACd,KAAK,EAAE,CAeR;IAEF,kBAAkB,GAChB,cAAc,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAC3C,gBAAgB,cAAc,EAC9B,QAAQ,KAAK,EAAE,KACd,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC,EAAE,CA8B/D;CACH"}