github-issue-tower-defence-management 1.60.2 → 1.63.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.
Files changed (117) hide show
  1. package/.github/workflows/publish.yml +13 -0
  2. package/.github/workflows/test.yml +0 -4
  3. package/CHANGELOG.md +7 -0
  4. package/README.md +53 -10
  5. package/bin/adapter/entry-points/cli/index.js +11 -11
  6. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  7. package/bin/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.js +3 -22
  8. package/bin/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.js.map +1 -1
  9. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +8 -22
  10. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  11. package/bin/adapter/entry-points/handlers/rotationOrderFileWriter.js +56 -0
  12. package/bin/adapter/entry-points/handlers/rotationOrderFileWriter.js.map +1 -0
  13. package/bin/adapter/entry-points/handlers/situationFileWriter.js +5 -0
  14. package/bin/adapter/entry-points/handlers/situationFileWriter.js.map +1 -1
  15. package/bin/adapter/proxy/TokenListLoader.js +21 -6
  16. package/bin/adapter/proxy/TokenListLoader.js.map +1 -1
  17. package/bin/adapter/proxy/proxyEntry.js +1 -0
  18. package/bin/adapter/proxy/proxyEntry.js.map +1 -1
  19. package/bin/adapter/repositories/BaseGitHubRepository.js +1 -113
  20. package/bin/adapter/repositories/BaseGitHubRepository.js.map +1 -1
  21. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +5 -3
  22. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -1
  23. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +8 -7
  24. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  25. package/bin/domain/usecases/HandleScheduledEventUseCase.js +14 -3
  26. package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
  27. package/bin/domain/usecases/IssueRejectionEvaluator.js +8 -1
  28. package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -1
  29. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +5 -1
  30. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
  31. package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +1 -1
  32. package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
  33. package/bin/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.js +32 -1
  34. package/bin/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.js.map +1 -1
  35. package/bin/domain/usecases/StartPreparationUseCase.js +91 -12
  36. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  37. package/package.json +1 -4
  38. package/src/adapter/entry-points/cli/index.test.ts +16 -16
  39. package/src/adapter/entry-points/cli/index.ts +8 -11
  40. package/src/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.test.ts +2 -55
  41. package/src/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.ts +1 -11
  42. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.test.ts +6 -56
  43. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +7 -11
  44. package/src/adapter/entry-points/handlers/rotationOrderFileWriter.test.ts +177 -0
  45. package/src/adapter/entry-points/handlers/rotationOrderFileWriter.ts +20 -0
  46. package/src/adapter/entry-points/handlers/situationFileWriter.test.ts +36 -0
  47. package/src/adapter/entry-points/handlers/situationFileWriter.ts +8 -0
  48. package/src/adapter/proxy/TokenListLoader.test.ts +50 -1
  49. package/src/adapter/proxy/TokenListLoader.ts +25 -5
  50. package/src/adapter/proxy/proxyEntry.test.ts +270 -1
  51. package/src/adapter/proxy/proxyEntry.ts +2 -1
  52. package/src/adapter/repositories/BaseGitHubRepository.test.ts +1 -186
  53. package/src/adapter/repositories/BaseGitHubRepository.ts +1 -139
  54. package/src/adapter/repositories/GraphqlProjectRepository.errorHandling.test.ts +0 -1
  55. package/src/adapter/repositories/GraphqlProjectRepository.fetchProjectId.test.ts +4 -1
  56. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +60 -19
  57. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +6 -4
  58. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +23 -13
  59. package/src/adapter/repositories/issue/ApiV3IssueRepository.test.ts +0 -1
  60. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +0 -8
  61. package/src/adapter/repositories/issue/RestIssueRepository.test.ts +0 -1
  62. package/src/domain/entities/ClaudeTokenUsage.ts +1 -0
  63. package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +4 -0
  64. package/src/domain/usecases/HandleScheduledEventUseCase.ts +20 -5
  65. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +153 -0
  66. package/src/domain/usecases/IssueRejectionEvaluator.ts +8 -0
  67. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +175 -31
  68. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +7 -1
  69. package/src/domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase.test.ts +32 -0
  70. package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +39 -5
  71. package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +1 -1
  72. package/src/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.test.ts +139 -20
  73. package/src/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.ts +62 -2
  74. package/src/domain/usecases/StartPreparationUseCase.test.ts +404 -21
  75. package/src/domain/usecases/StartPreparationUseCase.ts +152 -16
  76. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +16 -0
  77. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  78. package/types/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.d.ts.map +1 -1
  79. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  80. package/types/adapter/entry-points/handlers/rotationOrderFileWriter.d.ts +3 -0
  81. package/types/adapter/entry-points/handlers/rotationOrderFileWriter.d.ts.map +1 -0
  82. package/types/adapter/entry-points/handlers/situationFileWriter.d.ts +1 -0
  83. package/types/adapter/entry-points/handlers/situationFileWriter.d.ts.map +1 -1
  84. package/types/adapter/proxy/TokenListLoader.d.ts +5 -0
  85. package/types/adapter/proxy/TokenListLoader.d.ts.map +1 -1
  86. package/types/adapter/proxy/proxyEntry.d.ts +2 -1
  87. package/types/adapter/proxy/proxyEntry.d.ts.map +1 -1
  88. package/types/adapter/repositories/BaseGitHubRepository.d.ts +1 -23
  89. package/types/adapter/repositories/BaseGitHubRepository.d.ts.map +1 -1
  90. package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -1
  91. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +14 -5
  92. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  93. package/types/domain/entities/ClaudeTokenUsage.d.ts +1 -0
  94. package/types/domain/entities/ClaudeTokenUsage.d.ts.map +1 -1
  95. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +5 -2
  96. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
  97. package/types/domain/usecases/IssueRejectionEvaluator.d.ts +1 -1
  98. package/types/domain/usecases/IssueRejectionEvaluator.d.ts.map +1 -1
  99. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
  100. package/types/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.d.ts +5 -2
  101. package/types/domain/usecases/SetWorkflowManagementIssueToStoryUseCase.d.ts.map +1 -1
  102. package/types/domain/usecases/StartPreparationUseCase.d.ts +15 -1
  103. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
  104. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +14 -0
  105. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
  106. package/bin/adapter/repositories/issue/CheerioIssueRepository.js +0 -136
  107. package/bin/adapter/repositories/issue/CheerioIssueRepository.js.map +0 -1
  108. package/bin/adapter/repositories/issue/InternalGraphqlIssueRepository.js +0 -1606
  109. package/bin/adapter/repositories/issue/InternalGraphqlIssueRepository.js.map +0 -1
  110. package/src/adapter/repositories/issue/CheerioIssueRepository.test.ts +0 -6552
  111. package/src/adapter/repositories/issue/CheerioIssueRepository.ts +0 -142
  112. package/src/adapter/repositories/issue/InternalGraphqlIssueRepository.test.ts +0 -118
  113. package/src/adapter/repositories/issue/InternalGraphqlIssueRepository.ts +0 -584
  114. package/types/adapter/repositories/issue/CheerioIssueRepository.d.ts +0 -40
  115. package/types/adapter/repositories/issue/CheerioIssueRepository.d.ts.map +0 -1
  116. package/types/adapter/repositories/issue/InternalGraphqlIssueRepository.d.ts +0 -220
  117. package/types/adapter/repositories/issue/InternalGraphqlIssueRepository.d.ts.map +0 -1
@@ -1,584 +0,0 @@
1
- import ky from 'ky';
2
- import { BaseGitHubRepository } from '../BaseGitHubRepository';
3
- import typia from 'typia';
4
- import { Issue, IssueStatusTimeline } from './CheerioIssueRepository';
5
-
6
- type IssueTypeData = {
7
- name: string;
8
- color: string;
9
- id: string;
10
- isEnabled?: boolean;
11
- description?: string;
12
- };
13
-
14
- type TimelineActor = {
15
- __typename: 'User' | 'Bot' | 'Organization';
16
- login: string;
17
- id: string;
18
- __isActor: string;
19
- avatarUrl: string;
20
- profileResourcePath?: string;
21
- isCopilot?: boolean;
22
- };
23
-
24
- type BaseTimelineNode = {
25
- __typename: string;
26
- __isIssueTimelineItems: string;
27
- __isTimelineEvent?: string;
28
- databaseId: number;
29
- createdAt: string;
30
- actor: TimelineActor;
31
- __isNode: string;
32
- id: string;
33
- };
34
-
35
- type ProjectV2ItemStatusChangedEventNode = BaseTimelineNode & {
36
- __typename: 'ProjectV2ItemStatusChangedEvent';
37
- previousStatus: string;
38
- status: string;
39
- project: {
40
- title: string;
41
- url: string;
42
- id: string;
43
- };
44
- };
45
-
46
- type LabelNode = {
47
- id: string;
48
- color: string;
49
- name: string;
50
- nameHTML: string;
51
- description: string | null;
52
- url: string;
53
- __typename: string;
54
- };
55
- type TimelineItem = {
56
- id: string;
57
- __typename: string;
58
- };
59
-
60
- type IssueData = {
61
- id: string;
62
- updatedAt: string;
63
- title: string;
64
- number: number;
65
- repository: {
66
- nameWithOwner: string;
67
- id: string;
68
- name: string;
69
- owner: {
70
- __typename: 'User' | 'Organization';
71
- login: string;
72
- id: string;
73
- url: string;
74
- };
75
- isArchived: boolean;
76
- isPrivate: boolean;
77
- databaseId: number;
78
- slashCommandsEnabled: boolean;
79
- viewerCanInteract: boolean;
80
- viewerInteractionLimitReasonHTML: string;
81
- planFeatures?: {
82
- maximumAssignees: number;
83
- };
84
- visibility: string;
85
- pinnedIssues: {
86
- totalCount: number;
87
- };
88
- viewerCanPinIssues: boolean;
89
- issueTypes: null | {
90
- edges: Array<{
91
- node: {
92
- id: string;
93
- };
94
- }>;
95
- };
96
- };
97
- titleHTML: string;
98
- url: string;
99
- viewerCanUpdateNext: boolean;
100
- issueType: null | IssueTypeData;
101
- state: 'OPEN' | 'CLOSED';
102
- stateReason: string | null;
103
- linkedPullRequests: {
104
- nodes: Array<unknown>;
105
- };
106
- subIssuesSummary: {
107
- total: number;
108
- completed: number;
109
- };
110
- __isLabelable: string;
111
- labels: {
112
- edges: Array<{
113
- node: LabelNode;
114
- cursor: string;
115
- }>;
116
- pageInfo: {
117
- endCursor: string | null;
118
- hasNextPage: boolean;
119
- };
120
- };
121
- __isNode: string;
122
- databaseId: number;
123
- viewerDidAuthor: boolean;
124
- locked: boolean;
125
- author: {
126
- __typename: string;
127
- __isActor: string;
128
- login: string;
129
- id: string;
130
- profileUrl: string;
131
- avatarUrl: string;
132
- };
133
- __isComment: string;
134
- body: string;
135
- bodyHTML: string;
136
- bodyVersion: string;
137
- createdAt: string;
138
- __isReactable: string;
139
- reactionGroups: Array<{
140
- content: string;
141
- viewerHasReacted: boolean;
142
- reactors: {
143
- totalCount: number;
144
- nodes: Array<unknown>;
145
- };
146
- }>;
147
- viewerCanUpdateMetadata: boolean;
148
- viewerCanComment: boolean;
149
- viewerCanAssign: boolean;
150
- viewerCanLabel: boolean;
151
- __isIssueOrPullRequest: string;
152
- projectItemsNext?: {
153
- edges: Array<{
154
- node: {
155
- id: string;
156
- isArchived: boolean;
157
- project: {
158
- id: string;
159
- title: string;
160
- template: boolean;
161
- viewerCanUpdate: boolean;
162
- url: string;
163
- field: {
164
- __typename: string;
165
- id: string;
166
- name: string;
167
- options: Array<{
168
- id: string;
169
- optionId: string;
170
- name: string;
171
- nameHTML: string;
172
- color: string;
173
- descriptionHTML: string;
174
- description: string;
175
- }>;
176
- __isNode: string;
177
- };
178
- closed: boolean;
179
- number: number;
180
- hasReachedItemsLimit: boolean;
181
- __typename?: string;
182
- };
183
- fieldValueByName: {
184
- __typename: string;
185
- id: string;
186
- optionId: string;
187
- name: string;
188
- nameHTML: string;
189
- color: string;
190
- __isNode: string;
191
- } | null;
192
- __typename: string;
193
- };
194
- cursor: string;
195
- }>;
196
- pageInfo: {
197
- endCursor: string | null;
198
- hasNextPage: boolean;
199
- };
200
- };
201
- viewerCanSetMilestone: boolean;
202
- isPinned: boolean;
203
- viewerCanDelete: boolean;
204
- viewerCanTransfer: boolean;
205
- viewerCanConvertToDiscussion: boolean;
206
- viewerCanLock: boolean;
207
- viewerCanType: boolean;
208
- frontTimelineItems: {
209
- pageInfo: {
210
- hasNextPage: boolean;
211
- endCursor: string | null;
212
- };
213
- totalCount: number;
214
- edges: Array<{
215
- node: TimelineItem | null;
216
- cursor: string;
217
- }>;
218
- };
219
- backTimelineItems: {
220
- pageInfo: {
221
- hasPreviousPage: boolean;
222
- startCursor: string | null;
223
- };
224
- totalCount: number;
225
- edges: Array<{
226
- node: TimelineItem | null;
227
- cursor: string;
228
- }>;
229
- };
230
- assignedActors: {
231
- nodes: Array<{
232
- __typename: string;
233
- __isActor: string;
234
- id: string;
235
- login: string;
236
- name: string | null;
237
- profileResourcePath: string;
238
- avatarUrl: string;
239
- __isNode: string;
240
- }>;
241
- };
242
- };
243
-
244
- type GitHubIssueQuery = {
245
- queryId: string;
246
- queryName: string;
247
- variables: {
248
- id?: string;
249
- count?: number;
250
- number: number;
251
- owner: string;
252
- repo: string;
253
- };
254
- result: {
255
- data: {
256
- repository: {
257
- isOwnerEnterpriseManaged: boolean;
258
- issue: IssueData;
259
- id: string;
260
- };
261
- safeViewer: {
262
- isEnterpriseManagedUser: boolean;
263
- enterpriseManagedEnterpriseId: null;
264
- login: string;
265
- id: string;
266
- avatarUrl: string;
267
- __isActor: string;
268
- __typename: string;
269
- name: string | null;
270
- profileResourcePath: string;
271
- };
272
- };
273
- };
274
- timestamp: number;
275
- };
276
-
277
- type IssueUpdateSubscriptionResponse = {
278
- response: {
279
- data: {
280
- issueUpdated: {
281
- deletedCommentId: unknown;
282
- issueBodyUpdated: unknown;
283
- issueMetadataUpdated: unknown;
284
- issueStateUpdated: unknown;
285
- issueTimelineUpdated: unknown;
286
- issueTitleUpdated: unknown;
287
- issueReactionUpdated: unknown;
288
- issueTransferStateUpdated: unknown;
289
- issueTypeUpdated: unknown;
290
- commentReactionUpdated: unknown;
291
- commentUpdated: unknown;
292
- subIssuesUpdated: unknown;
293
- subIssuesSummaryUpdated: unknown;
294
- parentIssueUpdated: unknown;
295
- issueDependenciesSummaryUpdated: unknown;
296
- };
297
- };
298
- };
299
- subscriptionId: string;
300
- };
301
-
302
- type GitHubBetaFeatureViewData = {
303
- payload: {
304
- preloaded_records?: Record<string, unknown>;
305
- preloadedQueries: [GitHubIssueQuery];
306
- preloadedSubscriptions?: Record<
307
- string,
308
- Record<string, IssueUpdateSubscriptionResponse>
309
- >;
310
- };
311
- title?: unknown;
312
- appPayload?: {
313
- initial_view_content?: {
314
- team_id?: unknown;
315
- can_edit_view?: boolean;
316
- [key: string]: unknown;
317
- };
318
- current_user?: {
319
- id: string;
320
- login: string;
321
- avatarUrl: string;
322
- is_staff: boolean;
323
- is_emu: boolean;
324
- name?: unknown;
325
- [key: string]: unknown;
326
- };
327
- current_user_settings?: {
328
- use_monospace_font?: boolean;
329
- use_single_key_shortcut?: boolean;
330
- preferred_emoji_skin_tone?: number;
331
- copilot_show_functionality?: boolean;
332
- [key: string]: unknown;
333
- };
334
- paste_url_link_as_plain_text?: boolean;
335
- base_avatar_url?: string;
336
- help_url?: string;
337
- sso_organizations?: unknown;
338
- current_sso_orgs_match_dismissed_cookie?: unknown;
339
- multi_tenant?: boolean;
340
- tracing?: boolean;
341
- tracing_flamegraph?: boolean;
342
- catalog_service?: string;
343
- scoped_repository?: {
344
- id: string;
345
- owner: string;
346
- name: string;
347
- is_archived: boolean;
348
- [key: string]: unknown;
349
- };
350
- semantic_search_enrolled?: boolean;
351
- semantic_search_feedback_url?: unknown;
352
- copilot_api_url?: unknown;
353
- enabled_features?: Record<string, boolean>;
354
- [key: string]: unknown;
355
- };
356
- };
357
-
358
- type GraphqlResponse = {
359
- data: {
360
- node: {
361
- __typename: 'Issue';
362
- frontTimelineItems: IssueData['frontTimelineItems'];
363
- id: string;
364
- };
365
- };
366
- };
367
- export class InternalGraphqlIssueRepository extends BaseGitHubRepository {
368
- getFrontTimelineItems = async (
369
- issueUrl: string,
370
- cursor: string | null,
371
- issueId: string,
372
- maxCount: number = 9999,
373
- ): Promise<
374
- GraphqlResponse['data']['node']['frontTimelineItems']['edges']
375
- > => {
376
- const query = 'f6ff036f8e215bd07d00516664e8725c';
377
- const callQuery = async (
378
- query: string,
379
- count: number | null,
380
- cursor: string | null,
381
- issueId: string,
382
- ): Promise<GraphqlResponse['data']['node']['frontTimelineItems']> => {
383
- const requestBody = {
384
- query: query,
385
- variables: {
386
- cursor: cursor || '',
387
- count: count,
388
- id: issueId,
389
- },
390
- };
391
-
392
- const bodyParam = encodeURIComponent(JSON.stringify(requestBody));
393
- const url = `https://github.com/_graphql?body=${bodyParam}`;
394
-
395
- const headers = {
396
- accept: '*/*',
397
- 'accept-language': 'en-US,en;q=0.9,ja;q=0.8',
398
- 'cache-Control': 'no-cache',
399
- referer: issueUrl,
400
- 'sec-ch-ua':
401
- '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
402
- 'sec-ch-ua-mobile': '?0',
403
- 'sec-ch-ua-platform': '"Linux"',
404
- 'sec-fetch-dest': 'empty',
405
- 'sec-fetch-mode': 'cors',
406
- 'sec-fetch-site': 'same-origin',
407
- 'user-agent':
408
- 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
409
- 'x-requested-with': 'XMLHttpRequest',
410
- cookie: await this.getCookie(),
411
- };
412
-
413
- const maxRetries = 10;
414
- const getRetryDelay = (attempt: number): number => {
415
- const baseDelay = 5000;
416
- return baseDelay * Math.pow(2, attempt);
417
- };
418
-
419
- for (let i = 0; i < maxRetries; i++) {
420
- try {
421
- console.log(url);
422
- const kyResponse = await ky.get(url, {
423
- headers: headers,
424
- throwHttpErrors: false,
425
- });
426
- if (!kyResponse.ok) {
427
- throw new Error(`HTTP error ${kyResponse.status}`);
428
- }
429
- const rawResponse = await kyResponse.json<GraphqlResponse>();
430
- if (!rawResponse?.data?.node?.frontTimelineItems) {
431
- throw new Error(
432
- `No frontTimelineItems found. URL: ${issueUrl}, Response: ${JSON.stringify(
433
- rawResponse,
434
- )}`,
435
- );
436
- }
437
- await new Promise((resolve) => setTimeout(resolve, 2000));
438
- return rawResponse.data.node.frontTimelineItems;
439
- } catch (e) {
440
- const statusCode =
441
- e instanceof Error && e.message.startsWith('HTTP error ')
442
- ? parseInt(e.message.replace('HTTP error ', ''), 10)
443
- : null;
444
- const isRetryableError =
445
- statusCode !== null && [500, 502, 503, 504].includes(statusCode);
446
-
447
- if (i === maxRetries - 1) {
448
- throw e;
449
- }
450
-
451
- const delay = getRetryDelay(i);
452
- console.log(
453
- `Request failed (attempt ${i + 1}/${maxRetries}). ${isRetryableError ? `Status: ${statusCode}. ` : ''}Retrying in ${delay / 1000}s...`,
454
- );
455
- await new Promise((resolve) => setTimeout(resolve, delay));
456
- }
457
- }
458
- throw new Error('Unreachable');
459
- };
460
-
461
- const frontTimelineItems: GraphqlResponse['data']['node']['frontTimelineItems']['edges'] =
462
- [];
463
- let nextCursor = cursor;
464
- const maxCountPerRequest = 250;
465
- while (frontTimelineItems.length < maxCount) {
466
- const response = await callQuery(
467
- query,
468
- maxCountPerRequest,
469
- nextCursor,
470
- issueId,
471
- );
472
- for (const edge of response.edges) {
473
- frontTimelineItems.push(edge);
474
- if (frontTimelineItems.length >= maxCount) {
475
- return frontTimelineItems;
476
- }
477
- }
478
- nextCursor = response.pageInfo.endCursor;
479
- if (!response.pageInfo.hasNextPage) {
480
- break;
481
- }
482
- }
483
- return frontTimelineItems;
484
- };
485
- getIssueFromBetaFeatureView = async (
486
- issueUrl: string,
487
- html: string,
488
- ): Promise<Issue> => {
489
- const pattern =
490
- /<script type="application\/json" data-target="react-app\.embeddedData">([\s\S]*?)<\/script>/;
491
- const match = html.match(pattern);
492
-
493
- if (!match || !match[1]) {
494
- throw new Error(
495
- `No script content found. URL: ${issueUrl}, HTML: ${html}`,
496
- );
497
- }
498
- const scriptContent = match[1];
499
- if (!scriptContent) {
500
- throw new Error('No script content found');
501
- }
502
- const data: unknown = JSON.parse(scriptContent);
503
- const isValidStructure = (d: unknown): d is GitHubBetaFeatureViewData => {
504
- return (
505
- typeof d === 'object' &&
506
- d !== null &&
507
- 'payload' in d &&
508
- typeof d.payload === 'object' &&
509
- d.payload !== null &&
510
- 'preloadedQueries' in d.payload &&
511
- Array.isArray(d.payload.preloadedQueries) &&
512
- d.payload.preloadedQueries.length > 0
513
- );
514
- };
515
-
516
- if (!typia.is<GitHubBetaFeatureViewData>(data)) {
517
- if (!isValidStructure(data)) {
518
- const validateResult = typia.validate<GitHubBetaFeatureViewData>(data);
519
- throw new Error(
520
- `Invalid data: validateResult: ${JSON.stringify(validateResult)}, data: ${JSON.stringify(data)}`,
521
- );
522
- }
523
- }
524
-
525
- if (!isValidStructure(data)) {
526
- throw new Error('Data structure validation failed');
527
- }
528
-
529
- const issueData =
530
- data.payload.preloadedQueries[0].result.data.repository.issue;
531
- const issueRemainingCount =
532
- issueData.frontTimelineItems.totalCount -
533
- issueData.frontTimelineItems.edges.length -
534
- issueData.backTimelineItems.edges.length;
535
- const loadedMoreIssues = issueUrl.includes('/pull/')
536
- ? []
537
- : await this.getFrontTimelineItems(
538
- issueUrl,
539
- issueData.frontTimelineItems.pageInfo.endCursor,
540
- issueData.id,
541
- issueRemainingCount,
542
- );
543
- const statusTimeline = issueData.frontTimelineItems.edges
544
- .concat(loadedMoreIssues)
545
- .concat(issueData.backTimelineItems.edges)
546
- .filter(
547
- (edge, index, self) =>
548
- self.findIndex(
549
- (t) => !!t.node && !!edge.node && t.node.id === edge.node.id,
550
- ) === index,
551
- )
552
- .filter(
553
- (
554
- edge,
555
- ): edge is {
556
- node: ProjectV2ItemStatusChangedEventNode;
557
- cursor: string;
558
- } =>
559
- !!edge.node &&
560
- edge.node.__typename === 'ProjectV2ItemStatusChangedEvent',
561
- )
562
- .map(
563
- (edge): IssueStatusTimeline => ({
564
- time: edge.node.createdAt,
565
- author: edge.node.actor?.login || '',
566
- from: edge.node.previousStatus || '',
567
- to: edge.node.status || '',
568
- }),
569
- );
570
- return {
571
- url: issueUrl,
572
- title: issueData.title,
573
- status:
574
- statusTimeline.length > 0
575
- ? statusTimeline[statusTimeline.length - 1].to
576
- : '',
577
- assignees: issueData.assignedActors.nodes.map((node) => node.login),
578
- labels: issueData.labels.edges.map((edge) => edge.node.name),
579
- project: issueData.projectItemsNext?.edges[0]?.node.project.title ?? '',
580
- statusTimeline,
581
- createdAt: new Date(issueData.createdAt),
582
- };
583
- };
584
- }
@@ -1,40 +0,0 @@
1
- import * as cheerio from 'cheerio';
2
- import { BaseGitHubRepository } from '../BaseGitHubRepository';
3
- import { InternalGraphqlIssueRepository } from './InternalGraphqlIssueRepository';
4
- import { LocalStorageRepository } from '../LocalStorageRepository';
5
- export type IssueStatusTimeline = {
6
- time: string;
7
- author: string;
8
- from: string;
9
- to: string;
10
- };
11
- export type Issue = {
12
- url: string;
13
- title: string;
14
- status: string;
15
- assignees: string[];
16
- labels: string[];
17
- project: string;
18
- statusTimeline: IssueStatusTimeline[];
19
- createdAt: Date;
20
- };
21
- export declare class CheerioIssueRepository extends BaseGitHubRepository {
22
- readonly internalGraphqlIssueRepository: InternalGraphqlIssueRepository;
23
- readonly localStorageRepository: LocalStorageRepository;
24
- readonly jsonFilePath: string;
25
- readonly ghToken: string;
26
- readonly ghUserName: string | undefined;
27
- readonly ghUserPassword: string | undefined;
28
- readonly ghAuthenticatorKey: string | undefined;
29
- constructor(internalGraphqlIssueRepository: InternalGraphqlIssueRepository, localStorageRepository: LocalStorageRepository, jsonFilePath?: string, ghToken?: string, ghUserName?: string | undefined, ghUserPassword?: string | undefined, ghAuthenticatorKey?: string | undefined);
30
- getIssue: (issueUrl: string) => Promise<Issue>;
31
- getIssueFromNormalView: (issueUrl: string, $: cheerio.CheerioAPI) => Promise<Issue>;
32
- getStatusTimelineEvents: ($: cheerio.CheerioAPI) => Promise<IssueStatusTimeline[]>;
33
- protected getTitleFromCheerioObject: ($: cheerio.CheerioAPI) => string;
34
- protected getStatusFromCheerioObject: ($: cheerio.CheerioAPI) => string;
35
- protected getAssigneesFromCheerioObject: ($: cheerio.CheerioAPI) => string[];
36
- protected getLabelsFromCheerioObject: ($: cheerio.CheerioAPI) => string[];
37
- protected getProjectFromCheerioObject: ($: cheerio.CheerioAPI) => string;
38
- protected getStatusTimelineEventsFromCheerioObject: ($: cheerio.CheerioAPI) => IssueStatusTimeline[];
39
- }
40
- //# sourceMappingURL=CheerioIssueRepository.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CheerioIssueRepository.d.ts","sourceRoot":"","sources":["../../../../src/adapter/repositories/issue/CheerioIssueRepository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,mBAAmB,EAAE,CAAC;IACtC,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAEF,qBAAa,sBAAuB,SAAQ,oBAAoB;IAE5D,QAAQ,CAAC,8BAA8B,EAAE,8BAA8B;IACvE,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB;IACvD,QAAQ,CAAC,YAAY,EAAE,MAAM;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;IACvC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS;gBANtC,8BAA8B,EAAE,8BAA8B,EAC9D,sBAAsB,EAAE,sBAAsB,EAC9C,YAAY,GAAE,MAAwC,EACtD,OAAO,GAAE,MAAwC,EACjD,UAAU,GAAE,MAAM,GAAG,SAAoC,EACzD,cAAc,GAAE,MAAM,GAAG,SAAwC,EACjE,kBAAkB,GAAE,MAAM,GAAG,SACf;IAWzB,QAAQ,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CAgBjD;IACF,sBAAsB,GACpB,UAAU,MAAM,EAChB,GAAG,OAAO,CAAC,UAAU,KACpB,OAAO,CAAC,KAAK,CAAC,CAuBf;IACF,uBAAuB,GACrB,GAAG,OAAO,CAAC,UAAU,KACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAE/B;IACF,SAAS,CAAC,yBAAyB,GAAI,GAAG,OAAO,CAAC,UAAU,KAAG,MAAM,CAEnE;IACF,SAAS,CAAC,0BAA0B,GAAI,GAAG,OAAO,CAAC,UAAU,KAAG,MAAM,CAEpE;IACF,SAAS,CAAC,6BAA6B,GACrC,GAAG,OAAO,CAAC,UAAU,KACpB,MAAM,EAAE,CAKT;IACF,SAAS,CAAC,0BAA0B,GAAI,GAAG,OAAO,CAAC,UAAU,KAAG,MAAM,EAAE,CAItE;IACF,SAAS,CAAC,2BAA2B,GAAI,GAAG,OAAO,CAAC,UAAU,KAAG,MAAM,CAErE;IAEF,SAAS,CAAC,wCAAwC,GAChD,GAAG,OAAO,CAAC,UAAU,KACpB,mBAAmB,EAAE,CAsBtB;CACH"}