github-issue-tower-defence-management 1.50.1 → 1.50.3

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/bin/adapter/repositories/GitHubIssueCommentRepository.js +5 -83
  3. package/bin/adapter/repositories/GitHubIssueCommentRepository.js.map +1 -1
  4. package/bin/adapter/repositories/GraphqlProjectRepository.js +12 -0
  5. package/bin/adapter/repositories/GraphqlProjectRepository.js.map +1 -1
  6. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +1 -1
  7. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  8. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +29 -0
  9. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
  10. package/bin/domain/usecases/StartPreparationUseCase.js +0 -1
  11. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/adapter/repositories/GitHubIssueCommentRepository.test.ts +102 -0
  14. package/src/adapter/repositories/GitHubIssueCommentRepository.ts +13 -134
  15. package/src/adapter/repositories/GraphqlProjectRepository.errorHandling.test.ts +112 -0
  16. package/src/adapter/repositories/GraphqlProjectRepository.ts +20 -2
  17. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +3 -1
  18. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +1 -1
  19. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +46 -3
  20. package/src/domain/usecases/StartPreparationUseCase.test.ts +21 -26
  21. package/src/domain/usecases/StartPreparationUseCase.ts +0 -1
  22. package/types/adapter/repositories/GitHubIssueCommentRepository.d.ts +0 -1
  23. package/types/adapter/repositories/GitHubIssueCommentRepository.d.ts.map +1 -1
  24. package/types/adapter/repositories/GraphqlProjectRepository.d.ts.map +1 -1
  25. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +1 -0
  26. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
  27. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
@@ -8,32 +8,6 @@ type RestCommentPayload = {
8
8
  created_at: string;
9
9
  };
10
10
 
11
- type CreateCommentResponse = {
12
- data?: {
13
- addComment?: {
14
- commentEdge: {
15
- node: {
16
- id: string;
17
- };
18
- };
19
- };
20
- };
21
- errors?: Array<{ message: string }>;
22
- };
23
-
24
- type IssueIdResponse = {
25
- data?: {
26
- repository?: {
27
- issue?: {
28
- id: string;
29
- };
30
- pullRequest?: {
31
- id: string;
32
- };
33
- };
34
- };
35
- };
36
-
37
11
  function isRestCommentPayloadArray(
38
12
  value: unknown,
39
13
  ): value is RestCommentPayload[] {
@@ -41,18 +15,6 @@ function isRestCommentPayloadArray(
41
15
  return true;
42
16
  }
43
17
 
44
- function isCreateCommentResponse(
45
- value: unknown,
46
- ): value is CreateCommentResponse {
47
- if (typeof value !== 'object' || value === null) return false;
48
- return true;
49
- }
50
-
51
- function isIssueIdResponse(value: unknown): value is IssueIdResponse {
52
- if (typeof value !== 'object' || value === null) return false;
53
- return true;
54
- }
55
-
56
18
  export class GitHubIssueCommentRepository implements IssueCommentRepository {
57
19
  constructor(private readonly token: string) {}
58
20
 
@@ -122,108 +84,25 @@ export class GitHubIssueCommentRepository implements IssueCommentRepository {
122
84
  return comments;
123
85
  }
124
86
 
125
- private async getIssueNodeId(issue: Issue): Promise<string> {
126
- const { owner, repo, issueNumber, isPr } = this.parseIssueUrl(issue);
127
-
128
- const entityType = isPr ? 'pullRequest' : 'issue';
129
- const query = `
130
- query($owner: String!, $repo: String!, $issueNumber: Int!) {
131
- repository(owner: $owner, name: $repo) {
132
- ${entityType}(number: $issueNumber) {
133
- id
134
- }
135
- }
136
- }
137
- `;
138
-
139
- const response = await fetch('https://api.github.com/graphql', {
140
- method: 'POST',
141
- headers: {
142
- Authorization: `Bearer ${this.token}`,
143
- 'Content-Type': 'application/json',
144
- },
145
- body: JSON.stringify({
146
- query,
147
- variables: {
148
- owner,
149
- repo,
150
- issueNumber,
151
- },
152
- }),
153
- });
154
-
155
- if (!response.ok) {
156
- throw new Error(
157
- `Failed to fetch issue ID from GitHub GraphQL API: ${response.status} ${response.statusText}`,
158
- );
159
- }
160
-
161
- const responseData: unknown = await response.json();
162
- if (!isIssueIdResponse(responseData)) {
163
- throw new Error(
164
- 'Unexpected response shape when fetching issue ID from GitHub GraphQL API',
165
- );
166
- }
167
-
168
- const issueId = isPr
169
- ? responseData.data?.repository?.pullRequest?.id
170
- : responseData.data?.repository?.issue?.id;
171
- if (!issueId) {
172
- throw new Error(
173
- `${isPr ? 'Pull request' : 'Issue'} not found when fetching issue ID from GitHub GraphQL API`,
174
- );
175
- }
176
-
177
- return issueId;
178
- }
179
-
180
87
  async createComment(issue: Issue, commentContent: string): Promise<void> {
181
- const issueId = await this.getIssueNodeId(issue);
182
-
183
- const mutation = `
184
- mutation($issueId: ID!, $body: String!) {
185
- addComment(input: {
186
- subjectId: $issueId
187
- body: $body
188
- }) {
189
- commentEdge {
190
- node {
191
- id
192
- }
193
- }
194
- }
195
- }
196
- `;
88
+ const { owner, repo, issueNumber } = this.parseIssueUrl(issue);
197
89
 
198
- const response = await fetch('https://api.github.com/graphql', {
199
- method: 'POST',
200
- headers: {
201
- Authorization: `Bearer ${this.token}`,
202
- 'Content-Type': 'application/json',
203
- },
204
- body: JSON.stringify({
205
- query: mutation,
206
- variables: {
207
- issueId,
208
- body: commentContent,
90
+ const response = await fetch(
91
+ `https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
92
+ {
93
+ method: 'POST',
94
+ headers: {
95
+ Authorization: `Bearer ${this.token}`,
96
+ Accept: 'application/vnd.github+json',
97
+ 'Content-Type': 'application/json',
209
98
  },
210
- }),
211
- });
99
+ body: JSON.stringify({ body: commentContent }),
100
+ },
101
+ );
212
102
 
213
103
  if (!response.ok) {
214
104
  throw new Error(
215
- `Failed to create comment via GitHub GraphQL API: ${response.status} ${response.statusText}`,
216
- );
217
- }
218
-
219
- const responseData: unknown = await response.json();
220
- if (!isCreateCommentResponse(responseData)) {
221
- throw new Error('Invalid API response format when creating comment');
222
- }
223
-
224
- if (responseData.errors) {
225
- throw new Error(
226
- `GraphQL errors when creating comment: ${JSON.stringify(responseData.errors)}`,
105
+ `Failed to create comment via GitHub REST API: ${response.status} ${response.statusText}`,
227
106
  );
228
107
  }
229
108
  }
@@ -0,0 +1,112 @@
1
+ const mockPost = jest.fn();
2
+
3
+ jest.mock('ky', () => ({
4
+ default: {
5
+ post: mockPost,
6
+ get: jest.fn(),
7
+ put: jest.fn(),
8
+ patch: jest.fn(),
9
+ delete: jest.fn(),
10
+ extend: jest.fn(),
11
+ create: jest.fn(),
12
+ stop: jest.fn(),
13
+ },
14
+ __esModule: true,
15
+ }));
16
+
17
+ import { GraphqlProjectRepository } from './GraphqlProjectRepository';
18
+ import { LocalStorageRepository } from './LocalStorageRepository';
19
+
20
+ const mockJsonResponse = <T>(data: T) => ({
21
+ json: jest.fn().mockResolvedValue(data),
22
+ });
23
+
24
+ describe('GraphqlProjectRepository error handling', () => {
25
+ let repository: GraphqlProjectRepository;
26
+
27
+ beforeEach(() => {
28
+ mockPost.mockClear();
29
+ repository = new GraphqlProjectRepository(
30
+ new LocalStorageRepository(),
31
+ '',
32
+ 'dummy-token',
33
+ );
34
+ });
35
+
36
+ describe('fetchProjectId', () => {
37
+ it('should throw a descriptive error when response has no data field', async () => {
38
+ mockPost.mockReturnValueOnce(mockJsonResponse({}));
39
+
40
+ await expect(repository.fetchProjectId('someOrg', 1)).rejects.toThrow(
41
+ 'GitHub GraphQL API returned no data for fetchProjectId: no data field in response',
42
+ );
43
+ });
44
+
45
+ it('should throw with error messages when response contains only errors', async () => {
46
+ mockPost.mockReturnValueOnce(
47
+ mockJsonResponse({
48
+ errors: [
49
+ { message: 'was submitted too quickly' },
50
+ { message: 'secondary rate limit' },
51
+ ],
52
+ }),
53
+ );
54
+
55
+ await expect(repository.fetchProjectId('someOrg', 1)).rejects.toThrow(
56
+ 'GitHub GraphQL API returned no data for fetchProjectId: was submitted too quickly; secondary rate limit',
57
+ );
58
+ });
59
+
60
+ it('should return project ID when data is present for organization', async () => {
61
+ mockPost.mockReturnValueOnce(
62
+ mockJsonResponse({
63
+ data: {
64
+ organization: {
65
+ projectV2: { id: 'org-project-id', databaseId: 1 },
66
+ },
67
+ user: { projectV2: null },
68
+ },
69
+ }),
70
+ );
71
+
72
+ const result = await repository.fetchProjectId('someOrg', 1);
73
+ expect(result).toBe('org-project-id');
74
+ });
75
+
76
+ it('should return project ID when data is present for user', async () => {
77
+ mockPost.mockReturnValueOnce(
78
+ mockJsonResponse({
79
+ data: {
80
+ organization: { projectV2: null },
81
+ user: { projectV2: { id: 'user-project-id', databaseId: 2 } },
82
+ },
83
+ }),
84
+ );
85
+
86
+ const result = await repository.fetchProjectId('someUser', 2);
87
+ expect(result).toBe('user-project-id');
88
+ });
89
+ });
90
+
91
+ describe('getProject', () => {
92
+ it('should throw a descriptive error when response has no data field', async () => {
93
+ mockPost.mockReturnValueOnce(mockJsonResponse({}));
94
+
95
+ await expect(repository.getProject('project-id')).rejects.toThrow(
96
+ 'GitHub GraphQL API returned no data for getProject: no data field in response',
97
+ );
98
+ });
99
+
100
+ it('should throw with error messages when response contains only errors', async () => {
101
+ mockPost.mockReturnValueOnce(
102
+ mockJsonResponse({
103
+ errors: [{ message: 'abuse detection triggered' }],
104
+ }),
105
+ );
106
+
107
+ await expect(repository.getProject('project-id')).rejects.toThrow(
108
+ 'GitHub GraphQL API returned no data for getProject: abuse detection triggered',
109
+ );
110
+ });
111
+ });
112
+ });
@@ -61,7 +61,7 @@ export class GraphqlProjectRepository
61
61
  },
62
62
  })
63
63
  .json<{
64
- data: {
64
+ data?: {
65
65
  organization: {
66
66
  projectV2: {
67
67
  id: string;
@@ -75,8 +75,17 @@ export class GraphqlProjectRepository
75
75
  };
76
76
  };
77
77
  };
78
+ errors?: { message: string }[];
78
79
  }>();
79
80
 
81
+ if (!response.data) {
82
+ const errorMessages = response.errors
83
+ ? response.errors.map((e) => e.message).join('; ')
84
+ : 'no data field in response';
85
+ throw new Error(
86
+ `GitHub GraphQL API returned no data for fetchProjectId: ${errorMessages}`,
87
+ );
88
+ }
80
89
  const projectId =
81
90
  response.data.organization?.projectV2?.id ||
82
91
  response.data.user?.projectV2?.id;
@@ -156,7 +165,7 @@ export class GraphqlProjectRepository
156
165
  },
157
166
  })
158
167
  .json<{
159
- data: {
168
+ data?: {
160
169
  node: {
161
170
  id: string;
162
171
  databaseId: number;
@@ -191,7 +200,16 @@ export class GraphqlProjectRepository
191
200
  };
192
201
  };
193
202
  };
203
+ errors?: { message: string }[];
194
204
  }>();
205
+ if (!response.data) {
206
+ const errorMessages = response.errors
207
+ ? response.errors.map((e) => e.message).join('; ')
208
+ : 'no data field in response';
209
+ throw new Error(
210
+ `GitHub GraphQL API returned no data for getProject: ${errorMessages}`,
211
+ );
212
+ }
195
213
  const project = response.data.node;
196
214
  if (!project) {
197
215
  return null;
@@ -31,6 +31,7 @@ describe('ApiV3CheerioRestIssueRepository', () => {
31
31
  labels: [],
32
32
  assignees: [],
33
33
  createdAt: '2024-01-01T00:00:00Z',
34
+ author: 'test-author',
34
35
  customFields: [
35
36
  { name: 'nextActionDate', value: '2000-01-01' },
36
37
  { name: 'nextActionHour', value: '1' },
@@ -63,7 +64,7 @@ describe('ApiV3CheerioRestIssueRepository', () => {
63
64
  isInProgress: false,
64
65
  isClosed: false,
65
66
  createdAt: new Date('2024-01-01T00:00:00Z'),
66
- author: '',
67
+ author: 'test-author',
67
68
  },
68
69
  },
69
70
  {
@@ -80,6 +81,7 @@ describe('ApiV3CheerioRestIssueRepository', () => {
80
81
  labels: [],
81
82
  assignees: [],
82
83
  createdAt: '2024-01-01T00:00:00Z',
84
+ author: '',
83
85
  customFields: [
84
86
  {
85
87
  name: 'DependedIssueUrls',
@@ -376,7 +376,7 @@ export class ApiV3CheerioRestIssueRepository
376
376
  isInProgress: normalizeFieldName(status || '').includes('progress'),
377
377
  isClosed: item.state !== 'OPEN',
378
378
  createdAt: new Date(item.createdAt || '2000-01-01'),
379
- author: '',
379
+ author: item.author,
380
380
  };
381
381
  };
382
382
  getAllIssuesFromCache = async (
@@ -13,6 +13,7 @@ export type ProjectItem = {
13
13
  labels: string[];
14
14
  assignees: string[];
15
15
  createdAt: string;
16
+ author: string;
16
17
  customFields: {
17
18
  name: string;
18
19
  value: string | null;
@@ -58,7 +59,7 @@ export class GraphqlProjectItemRepository extends BaseGitHubRepository {
58
59
  },
59
60
  })
60
61
  .json<{
61
- data: {
62
+ data?: {
62
63
  repository: {
63
64
  issue: {
64
65
  projectItems: {
@@ -70,8 +71,17 @@ export class GraphqlProjectItemRepository extends BaseGitHubRepository {
70
71
  };
71
72
  };
72
73
  };
74
+ errors?: { message: string }[];
73
75
  }>();
74
76
 
77
+ if (!response.data) {
78
+ const errorMessages = response.errors
79
+ ? response.errors.map((e) => e.message).join('; ')
80
+ : 'no data field in response';
81
+ throw new Error(
82
+ `GitHub GraphQL API returned no data for fetchItemId: ${errorMessages}`,
83
+ );
84
+ }
75
85
  const projectItems: {
76
86
  id: string;
77
87
  project: { id: string };
@@ -150,6 +160,9 @@ query GetProjectItems($projectId: ID!, $after: String) {
150
160
  state
151
161
  url
152
162
  createdAt
163
+ author {
164
+ login
165
+ }
153
166
  labels(first: 100) {
154
167
  nodes {
155
168
  name
@@ -170,6 +183,9 @@ query GetProjectItems($projectId: ID!, $after: String) {
170
183
  state
171
184
  url
172
185
  createdAt
186
+ author {
187
+ login
188
+ }
173
189
  labels(first: 100) {
174
190
  nodes {
175
191
  name
@@ -222,6 +238,7 @@ query GetProjectItems($projectId: ID!, $after: String) {
222
238
  state: string;
223
239
  url: string;
224
240
  createdAt: string;
241
+ author: { login: string } | null;
225
242
  labels: { nodes: { name: string }[] };
226
243
  assignees: { nodes: { login: string }[] };
227
244
  };
@@ -272,6 +289,7 @@ query GetProjectItems($projectId: ID!, $after: String) {
272
289
  state: string;
273
290
  url: string;
274
291
  createdAt: string;
292
+ author: { login: string } | null;
275
293
  labels: { nodes: { name: string }[] };
276
294
  assignees: { nodes: { login: string }[] };
277
295
  };
@@ -338,6 +356,7 @@ query GetProjectItems($projectId: ID!, $after: String) {
338
356
  state: string;
339
357
  url: string;
340
358
  createdAt: string;
359
+ author: { login: string } | null;
341
360
  labels: { nodes: { name: string }[] };
342
361
  assignees: { nodes: { login: string }[] };
343
362
  };
@@ -357,6 +376,7 @@ query GetProjectItems($projectId: ID!, $after: String) {
357
376
  labels: item.content.labels?.nodes?.map((l) => l.name) || [],
358
377
  assignees: item.content.assignees?.nodes?.map((a) => a.login) || [],
359
378
  createdAt: item.content.createdAt || new Date().toISOString(),
379
+ author: item.content.author?.login || '',
360
380
  customFields: item.fieldValues.nodes
361
381
  .filter((field) => !!field.field)
362
382
  .map((field) => {
@@ -495,7 +515,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
495
515
  },
496
516
  })
497
517
  .json<{
498
- data: {
518
+ data?: {
499
519
  repository: {
500
520
  issue: {
501
521
  projectItems: {
@@ -517,8 +537,17 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
517
537
  };
518
538
  };
519
539
  };
540
+ errors?: { message: string }[];
520
541
  }>();
521
542
 
543
+ if (!response.data) {
544
+ const errorMessages = response.errors
545
+ ? response.errors.map((e) => e.message).join('; ')
546
+ : 'no data field in response';
547
+ throw new Error(
548
+ `GitHub GraphQL API returned no data for getProjectItemFields: ${errorMessages}`,
549
+ );
550
+ }
522
551
  const data = response.data;
523
552
  const issueFields: {
524
553
  fieldName: string;
@@ -569,6 +598,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
569
598
  url
570
599
  body
571
600
  createdAt
601
+ author {
602
+ login
603
+ }
572
604
  labels(first: 100) {
573
605
  nodes {
574
606
  name
@@ -651,7 +683,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
651
683
  },
652
684
  })
653
685
  .json<{
654
- data: {
686
+ data?: {
655
687
  repository: {
656
688
  issue: {
657
689
  number: number;
@@ -660,6 +692,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
660
692
  url: string;
661
693
  body: string;
662
694
  createdAt: string;
695
+ author: { login: string } | null;
663
696
  labels: { nodes: { name: string }[] };
664
697
  assignees: { nodes: { login: string }[] };
665
698
  repository: { nameWithOwner: string };
@@ -682,7 +715,16 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
682
715
  };
683
716
  };
684
717
  };
718
+ errors?: { message: string }[];
685
719
  }>();
720
+ if (!response.data) {
721
+ const errorMessages = response.errors
722
+ ? response.errors.map((e) => e.message).join('; ')
723
+ : 'no data field in response';
724
+ throw new Error(
725
+ `GitHub GraphQL API returned no data for fetchProjectItemByUrl: ${errorMessages}`,
726
+ );
727
+ }
686
728
  const data = response.data;
687
729
  if (!data.repository.issue) {
688
730
  return null;
@@ -717,6 +759,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
717
759
  assignees:
718
760
  data.repository.issue.assignees?.nodes?.map((a) => a.login) || [],
719
761
  createdAt: data.repository.issue.createdAt || new Date().toISOString(),
762
+ author: data.repository.issue.author?.login || '',
720
763
  customFields: item.fieldValues.nodes
721
764
  .filter((field) => !!field.field)
722
765
  .map((field) => {
@@ -2039,25 +2039,27 @@ describe('StartPreparationUseCase', () => {
2039
2039
  expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(2);
2040
2040
  });
2041
2041
 
2042
- it('should not skip issues with empty author (tower defence issues)', async () => {
2043
- const towerDefenceIssue = createMockIssue({
2042
+ it('should skip issues with empty author when allowedIssueAuthors is configured (deny-by-default)', async () => {
2043
+ const issueWithEmptyAuthor = createMockIssue({
2044
2044
  url: 'https://github.com/user/repo/issues/1',
2045
- title: 'Tower defence issue',
2045
+ title: 'Issue with empty author',
2046
2046
  labels: [],
2047
2047
  status: 'Awaiting Workspace',
2048
2048
  author: '',
2049
2049
  });
2050
- const normalIssue = createMockIssue({
2050
+ const issueWithKnownAuthor = createMockIssue({
2051
2051
  url: 'https://github.com/user/repo/issues/2',
2052
- title: 'Normal issue',
2052
+ title: 'Issue with known author',
2053
2053
  labels: [],
2054
2054
  status: 'Awaiting Workspace',
2055
2055
  author: 'user1',
2056
+ number: 2,
2057
+ itemId: 'item-2',
2056
2058
  });
2057
2059
 
2058
2060
  mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2059
2061
  mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2060
- createMockStoryObjectMap([towerDefenceIssue, normalIssue]),
2062
+ createMockStoryObjectMap([issueWithEmptyAuthor, issueWithKnownAuthor]),
2061
2063
  );
2062
2064
  mockLocalCommandRunner.runCommand.mockResolvedValue({
2063
2065
  stdout: '',
@@ -2078,33 +2080,26 @@ describe('StartPreparationUseCase', () => {
2078
2080
  allowIssueCacheMinutes: 0,
2079
2081
  });
2080
2082
 
2081
- expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(2);
2082
- expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(2);
2083
+ expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
2084
+ expect(mockIssueRepository.updateStatus.mock.calls[0][1]).toMatchObject({
2085
+ url: 'https://github.com/user/repo/issues/2',
2086
+ });
2087
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2083
2088
  });
2084
2089
 
2085
- it('should not skip issues without author property when allowedIssueAuthors is set', async () => {
2086
- const issueWithoutAuthor = createMockIssue({
2090
+ it('should skip issue with empty author when allowedIssueAuthors is set', async () => {
2091
+ const issueWithEmptyAuthor = createMockIssue({
2087
2092
  url: 'https://github.com/user/repo/issues/1',
2088
- title: 'Issue without author property',
2093
+ title: 'Issue with empty author',
2089
2094
  labels: [],
2090
2095
  status: 'Awaiting Workspace',
2091
2096
  author: '',
2092
2097
  });
2093
2098
 
2094
- const storyObjectMap: StoryObjectMap = new Map();
2095
- storyObjectMap.set('Default Story', {
2096
- story: {
2097
- id: 'story-1',
2098
- name: 'Default Story',
2099
- color: 'GRAY',
2100
- description: '',
2101
- },
2102
- storyIssue: null,
2103
- issues: [issueWithoutAuthor],
2104
- });
2105
-
2106
2099
  mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2107
- mockIssueRepository.getStoryObjectMap.mockResolvedValue(storyObjectMap);
2100
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2101
+ createMockStoryObjectMap([issueWithEmptyAuthor]),
2102
+ );
2108
2103
  mockLocalCommandRunner.runCommand.mockResolvedValue({
2109
2104
  stdout: '',
2110
2105
  stderr: '',
@@ -2124,8 +2119,8 @@ describe('StartPreparationUseCase', () => {
2124
2119
  allowIssueCacheMinutes: 0,
2125
2120
  });
2126
2121
 
2127
- expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(1);
2128
- expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2122
+ expect(mockIssueRepository.updateStatus.mock.calls).toHaveLength(0);
2123
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(0);
2129
2124
  });
2130
2125
 
2131
2126
  it('should not pass --codexHome when codexHomeCandidates is null', async () => {
@@ -149,7 +149,6 @@ export class StartPreparationUseCase {
149
149
  }
150
150
  if (
151
151
  params.allowedIssueAuthors !== null &&
152
- issue.author !== '' &&
153
152
  !params.allowedIssueAuthors.includes(issue.author)
154
153
  ) {
155
154
  continue;
@@ -6,7 +6,6 @@ export declare class GitHubIssueCommentRepository implements IssueCommentReposit
6
6
  constructor(token: string);
7
7
  private parseIssueUrl;
8
8
  getCommentsFromIssue(issue: Issue): Promise<Comment[]>;
9
- private getIssueNodeId;
10
9
  createComment(issue: Issue, commentContent: string): Promise<void>;
11
10
  }
12
11
  //# sourceMappingURL=GitHubIssueCommentRepository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubIssueCommentRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/GitHubIssueCommentRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAqDxD,qBAAa,4BAA6B,YAAW,sBAAsB;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,MAAM;IAE1C,OAAO,CAAC,aAAa;IAoBf,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YA8C9C,cAAc;IAuDtB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAkDzE"}
1
+ {"version":3,"file":"GitHubIssueCommentRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/GitHubIssueCommentRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAexD,qBAAa,4BAA6B,YAAW,sBAAsB;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,MAAM;IAE1C,OAAO,CAAC,aAAa;IAoBf,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IA8CtD,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAsBzE"}
@@ -1 +1 @@
1
- {"version":3,"file":"GraphqlProjectRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/GraphqlProjectRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAGrE,qBAAa,wBACX,SAAQ,oBACR,YACE,IAAI,CACF,iBAAiB,EACf,YAAY,GACZ,oBAAoB,GACpB,UAAU,GACV,iBAAiB,GACjB,kBAAkB,CACrB;IAEH,qBAAqB,GACnB,YAAY,MAAM,KACjB;QACD,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;KACvB,CAMC;IACF,cAAc,GACZ,OAAO,MAAM,EACb,eAAe,MAAM,KACpB,OAAO,CAAC,MAAM,CAAC,CAqDhB;IACF,kBAAkB,GAChB,YAAY,MAAM,KACjB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAG9B;IACF,UAAU,GAAU,WAAW,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAkNpE;IACF,QAAQ,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC,CAU9C;IACF,eAAe,GACb,SAAS,OAAO,EAChB,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QACvC,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KAC9B,CAAC,EAAE,KACH,OAAO,CAAC,WAAW,EAAE,CAAC,CA+CvB;IACF,gBAAgB,GACd,SAAS,OAAO,EAChB,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QACxC,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KAC9B,CAAC,EAAE,KACH,OAAO,CAAC,WAAW,EAAE,CAAC,CA4CvB;CACH"}
1
+ {"version":3,"file":"GraphqlProjectRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/GraphqlProjectRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAGrE,qBAAa,wBACX,SAAQ,oBACR,YACE,IAAI,CACF,iBAAiB,EACf,YAAY,GACZ,oBAAoB,GACpB,UAAU,GACV,iBAAiB,GACjB,kBAAkB,CACrB;IAEH,qBAAqB,GACnB,YAAY,MAAM,KACjB;QACD,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;KACvB,CAMC;IACF,cAAc,GACZ,OAAO,MAAM,EACb,eAAe,MAAM,KACpB,OAAO,CAAC,MAAM,CAAC,CA8DhB;IACF,kBAAkB,GAChB,YAAY,MAAM,KACjB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAG9B;IACF,UAAU,GAAU,WAAW,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA2NpE;IACF,QAAQ,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC,CAU9C;IACF,eAAe,GACb,SAAS,OAAO,EAChB,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QACvC,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KAC9B,CAAC,EAAE,KACH,OAAO,CAAC,WAAW,EAAE,CAAC,CA+CvB;IACF,gBAAgB,GACd,SAAS,OAAO,EAChB,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;QACxC,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KAC9B,CAAC,EAAE,KACH,OAAO,CAAC,WAAW,EAAE,CAAC,CA4CvB;CACH"}
@@ -12,6 +12,7 @@ export type ProjectItem = {
12
12
  labels: string[];
13
13
  assignees: string[];
14
14
  createdAt: string;
15
+ author: string;
15
16
  customFields: {
16
17
  name: string;
17
18
  value: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"GraphqlProjectItemRepository.d.ts","sourceRoot":"","sources":["../../../../src/adapter/repositories/issue/GraphqlProjectItemRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,EAAE,CAAC;CACL,CAAC;AACF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,qBAAa,4BAA6B,SAAQ,oBAAoB;IACpE,WAAW,GACT,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,KAClB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2D5B;IACF,iBAAiB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAoTnE;IACF,gCAAgC,GAC9B,UAAU,MAAM,KACf,OAAO,CACR;QACE,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CACJ,CAGC;IAEF,oBAAoB,GAClB,OAAO,MAAM,EACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,KAClB,OAAO,CACR;QACE,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CACJ,CA4IC;IACF,qBAAqB,GACnB,UAAU,MAAM,KACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA6K5B;IACF,iBAAiB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAQ/D;IAEF,kBAAkB,GAChB,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,QAAQ,MAAM,EACd,OACI;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAClB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,oBAAoB,EAAE,MAAM,CAAA;KAAE,KACnC,OAAO,CAAC,IAAI,CAAC,CAgCd;IAEF,iBAAiB,GACf,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,QAAQ,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CA+Bd;IACF,sBAAsB,GACpB,SAAS,OAAO,CAAC,IAAI,CAAC,EACtB,SAAS,MAAM,EACf,OAAO,KAAK,CAAC,QAAQ,CAAC,EACtB,MAAM,MAAM,KACX,OAAO,CAAC,IAAI,CAAC,CAEd;IAEF,qBAAqB,GACnB,WAAW,MAAM,EACjB,QAAQ,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAgCd;IAEF,+BAA+B,GAC7B,UAAU,MAAM,EAChB,WAAW,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,CASd;CACH"}
1
+ {"version":3,"file":"GraphqlProjectItemRepository.d.ts","sourceRoot":"","sources":["../../../../src/adapter/repositories/issue/GraphqlProjectItemRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,EAAE,CAAC;CACL,CAAC;AACF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,qBAAa,4BAA6B,SAAQ,oBAAoB;IACpE,WAAW,GACT,WAAW,MAAM,EACjB,OAAO,MAAM,EACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,KAClB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoE5B;IACF,iBAAiB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA8TnE;IACF,gCAAgC,GAC9B,UAAU,MAAM,KACf,OAAO,CACR;QACE,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CACJ,CAGC;IAEF,oBAAoB,GAClB,OAAO,MAAM,EACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,KAClB,OAAO,CACR;QACE,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CACJ,CAqJC;IACF,qBAAqB,GACnB,UAAU,MAAM,KACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA2L5B;IACF,iBAAiB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAQ/D;IAEF,kBAAkB,GAChB,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,QAAQ,MAAM,EACd,OACI;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAClB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,oBAAoB,EAAE,MAAM,CAAA;KAAE,KACnC,OAAO,CAAC,IAAI,CAAC,CAgCd;IAEF,iBAAiB,GACf,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,QAAQ,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CA+Bd;IACF,sBAAsB,GACpB,SAAS,OAAO,CAAC,IAAI,CAAC,EACtB,SAAS,MAAM,EACf,OAAO,KAAK,CAAC,QAAQ,CAAC,EACtB,MAAM,MAAM,KACX,OAAO,CAAC,IAAI,CAAC,CAEd;IAEF,qBAAqB,GACnB,WAAW,MAAM,EACjB,QAAQ,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAgCd;IAEF,+BAA+B,GAC7B,UAAU,MAAM,EAChB,WAAW,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,CASd;CACH"}