github-issue-tower-defence-management 2.154.9 → 2.155.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -1
- package/bin/adapter/entry-points/cli/fleetConfig.js +33 -1
- package/bin/adapter/entry-points/cli/fleetConfig.js.map +1 -1
- package/bin/adapter/entry-points/cli/index.js +159 -51
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/cli/notifyFinishedIssuePreparationRetry.js +27 -0
- package/bin/adapter/entry-points/cli/notifyFinishedIssuePreparationRetry.js.map +1 -0
- package/bin/adapter/entry-points/cli/projectConfig.js +5 -0
- package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
- package/bin/adapter/entry-points/cli/resumableSessionSelect.js +45 -0
- package/bin/adapter/entry-points/cli/resumableSessionSelect.js.map +1 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-B_lVAA3P.css +2 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-CN6FXgfc.js +93 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/bin/adapter/entry-points/console/webServer.js +20 -0
- package/bin/adapter/entry-points/console/webServer.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +30 -6
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/proxy/TokenListLoader.js +3 -2
- package/bin/adapter/proxy/TokenListLoader.js.map +1 -1
- package/bin/adapter/repositories/FileSystemResumableSessionTranscriptRepository.js +188 -0
- package/bin/adapter/repositories/FileSystemResumableSessionTranscriptRepository.js.map +1 -0
- package/bin/adapter/repositories/FileSystemWorkerSessionFailureStreakRepository.js +98 -0
- package/bin/adapter/repositories/FileSystemWorkerSessionFailureStreakRepository.js.map +1 -0
- package/bin/adapter/repositories/FileSystemWorkerSessionLogRepository.js +57 -0
- package/bin/adapter/repositories/FileSystemWorkerSessionLogRepository.js.map +1 -0
- package/bin/adapter/repositories/GitHubIssueCommentRepository.js +15 -2
- package/bin/adapter/repositories/GitHubIssueCommentRepository.js.map +1 -1
- package/bin/adapter/repositories/LocalStorageUrgentStoryLaunchHoldRepository.js +245 -0
- package/bin/adapter/repositories/LocalStorageUrgentStoryLaunchHoldRepository.js.map +1 -0
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +110 -19
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/RestIssueRepository.js +1 -0
- package/bin/adapter/repositories/issue/RestIssueRepository.js.map +1 -1
- package/bin/domain/entities/WorkerRequestText.js +6 -0
- package/bin/domain/entities/WorkerRequestText.js.map +1 -0
- package/bin/domain/entities/WorkerSessionFailureStreak.js +3 -0
- package/bin/domain/entities/WorkerSessionFailureStreak.js.map +1 -0
- package/bin/domain/services/commentCreateWithDedupRetry.js +46 -0
- package/bin/domain/services/commentCreateWithDedupRetry.js.map +1 -0
- package/bin/domain/usecases/AssignNoAssigneeIssueToManagerUseCase.js +2 -1
- package/bin/domain/usecases/AssignNoAssigneeIssueToManagerUseCase.js.map +1 -1
- package/bin/domain/usecases/CloseIssueAsRequestApplier.js +29 -0
- package/bin/domain/usecases/CloseIssueAsRequestApplier.js.map +1 -0
- package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -0
- package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +61 -15
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/ResumableSessionSelectUseCase.js +153 -0
- package/bin/domain/usecases/ResumableSessionSelectUseCase.js.map +1 -0
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +12 -7
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +59 -21
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +157 -3
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/WorkerSessionEndClassifyUseCase.js +225 -0
- package/bin/domain/usecases/WorkerSessionEndClassifyUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/ResumableSessionTranscriptRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/ResumableSessionTranscriptRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/UrgentStoryLaunchHoldRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/UrgentStoryLaunchHoldRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/WorkerSessionFailureStreakRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/WorkerSessionFailureStreakRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/WorkerSessionLogRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/WorkerSessionLogRepository.js.map +1 -0
- package/bin/domain/usecases/extractCloseIssueAs.js +24 -0
- package/bin/domain/usecases/extractCloseIssueAs.js.map +1 -0
- package/bin/domain/usecases/findLastAgentReport.js +9 -3
- package/bin/domain/usecases/findLastAgentReport.js.map +1 -1
- package/bin/domain/usecases/isTransientApiError.js +3 -1
- package/bin/domain/usecases/isTransientApiError.js.map +1 -1
- package/bin/domain/usecases/urgentStoryLaunchHoldDecide.js +76 -0
- package/bin/domain/usecases/urgentStoryLaunchHoldDecide.js.map +1 -0
- package/package.json +1 -1
- package/types/adapter/entry-points/cli/fleetConfig.d.ts +3 -0
- package/types/adapter/entry-points/cli/fleetConfig.d.ts.map +1 -1
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/cli/notifyFinishedIssuePreparationRetry.d.ts +8 -0
- package/types/adapter/entry-points/cli/notifyFinishedIssuePreparationRetry.d.ts.map +1 -0
- package/types/adapter/entry-points/cli/projectConfig.d.ts +3 -0
- package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
- package/types/adapter/entry-points/cli/resumableSessionSelect.d.ts +12 -0
- package/types/adapter/entry-points/cli/resumableSessionSelect.d.ts.map +1 -0
- package/types/adapter/entry-points/console/webServer.d.ts +1 -0
- package/types/adapter/entry-points/console/webServer.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts +3 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/proxy/TokenListLoader.d.ts +1 -0
- package/types/adapter/proxy/TokenListLoader.d.ts.map +1 -1
- package/types/adapter/repositories/FileSystemResumableSessionTranscriptRepository.d.ts +13 -0
- package/types/adapter/repositories/FileSystemResumableSessionTranscriptRepository.d.ts.map +1 -0
- package/types/adapter/repositories/FileSystemWorkerSessionFailureStreakRepository.d.ts +12 -0
- package/types/adapter/repositories/FileSystemWorkerSessionFailureStreakRepository.d.ts.map +1 -0
- package/types/adapter/repositories/FileSystemWorkerSessionLogRepository.d.ts +5 -0
- package/types/adapter/repositories/FileSystemWorkerSessionLogRepository.d.ts.map +1 -0
- package/types/adapter/repositories/GitHubIssueCommentRepository.d.ts +5 -0
- package/types/adapter/repositories/GitHubIssueCommentRepository.d.ts.map +1 -1
- package/types/adapter/repositories/LocalStorageUrgentStoryLaunchHoldRepository.d.ts +30 -0
- package/types/adapter/repositories/LocalStorageUrgentStoryLaunchHoldRepository.d.ts.map +1 -0
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +3 -1
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/adapter/repositories/issue/RestIssueRepository.d.ts.map +1 -1
- package/types/domain/entities/Comment.d.ts +1 -0
- package/types/domain/entities/Comment.d.ts.map +1 -1
- package/types/domain/entities/SearchedIssue.d.ts +1 -0
- package/types/domain/entities/SearchedIssue.d.ts.map +1 -1
- package/types/domain/entities/WorkerRequestText.d.ts +2 -0
- package/types/domain/entities/WorkerRequestText.d.ts.map +1 -0
- package/types/domain/entities/WorkerSessionFailureStreak.d.ts +5 -0
- package/types/domain/entities/WorkerSessionFailureStreak.d.ts.map +1 -0
- package/types/domain/services/commentCreateWithDedupRetry.d.ts +11 -0
- package/types/domain/services/commentCreateWithDedupRetry.d.ts.map +1 -0
- package/types/domain/usecases/AssignNoAssigneeIssueToManagerUseCase.d.ts.map +1 -1
- package/types/domain/usecases/CloseIssueAsRequestApplier.d.ts +16 -0
- package/types/domain/usecases/CloseIssueAsRequestApplier.d.ts.map +1 -0
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +1 -0
- package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +4 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/ResumableSessionSelectUseCase.d.ts +35 -0
- package/types/domain/usecases/ResumableSessionSelectUseCase.d.ts.map +1 -0
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts +3 -1
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts +5 -2
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts +12 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/WorkerSessionEndClassifyUseCase.d.ts +27 -0
- package/types/domain/usecases/WorkerSessionEndClassifyUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/ResumableSessionTranscriptRepository.d.ts +22 -0
- package/types/domain/usecases/adapter-interfaces/ResumableSessionTranscriptRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/UrgentStoryLaunchHoldRepository.d.ts +11 -0
- package/types/domain/usecases/adapter-interfaces/UrgentStoryLaunchHoldRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/WorkerSessionFailureStreakRepository.d.ts +7 -0
- package/types/domain/usecases/adapter-interfaces/WorkerSessionFailureStreakRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/WorkerSessionLogRepository.d.ts +11 -0
- package/types/domain/usecases/adapter-interfaces/WorkerSessionLogRepository.d.ts.map +1 -0
- package/types/domain/usecases/extractCloseIssueAs.d.ts +12 -0
- package/types/domain/usecases/extractCloseIssueAs.d.ts.map +1 -0
- package/types/domain/usecases/findLastAgentReport.d.ts +1 -0
- package/types/domain/usecases/findLastAgentReport.d.ts.map +1 -1
- package/types/domain/usecases/isTransientApiError.d.ts.map +1 -1
- package/types/domain/usecases/urgentStoryLaunchHoldDecide.d.ts +48 -0
- package/types/domain/usecases/urgentStoryLaunchHoldDecide.d.ts.map +1 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-BCjejjC0.css +0 -2
- package/bin/adapter/entry-points/console/ui-dist/assets/index-CcgrBS5P.js +0 -93
|
@@ -9,6 +9,7 @@ const BaseGitHubRepository_1 = require("../BaseGitHubRepository");
|
|
|
9
9
|
const githubGraphqlClient_1 = require("../githubGraphqlClient");
|
|
10
10
|
const utils_1 = require("../utils");
|
|
11
11
|
const localStorageCacheDirectory_1 = require("../localStorageCacheDirectory");
|
|
12
|
+
const isTransientApiError_1 = require("../../../domain/usecases/isTransientApiError");
|
|
12
13
|
const githubRateLimitRetry_1 = require("./githubRateLimitRetry");
|
|
13
14
|
const githubRestClient_1 = require("../githubRestClient");
|
|
14
15
|
const githubSecondaryRateLimitBreaker_1 = require("./githubSecondaryRateLimitBreaker");
|
|
@@ -79,6 +80,7 @@ const RELATED_OPEN_PULL_REQUEST_URLS_BATCH_SIZE = 100;
|
|
|
79
80
|
const RELATED_OPEN_PULL_REQUEST_URLS_TIMELINE_PAGE_SIZE = 100;
|
|
80
81
|
const ISSUE_EVENTS_PAGE_SIZE = 100;
|
|
81
82
|
const ISSUE_EVENT_COUNT_AT_WHICH_GITHUB_STOPS_LISTING_ISSUE_EVENTS = 310;
|
|
83
|
+
const REOPENED_TIMELINE_ITEM_COUNT_AT_WHICH_GITHUB_STOPS_LISTING_REOPENED_TIMELINE_ITEMS = 310;
|
|
82
84
|
function isIssueTimelineResponse(value) {
|
|
83
85
|
if (typeof value !== 'object' || value === null)
|
|
84
86
|
return false;
|
|
@@ -163,9 +165,22 @@ function isIssueLatestReopenedTimelineItemResponse(value) {
|
|
|
163
165
|
if (!isRecord(timelineItems))
|
|
164
166
|
return false;
|
|
165
167
|
const nodes = timelineItems.nodes;
|
|
166
|
-
return (
|
|
168
|
+
return (typeof timelineItems.totalCount === 'number' &&
|
|
169
|
+
Array.isArray(nodes) &&
|
|
167
170
|
nodes.every((node) => isRecord(node) && typeof node.createdAt === 'string'));
|
|
168
171
|
}
|
|
172
|
+
function isRepositoryIssueEventFeedResponseItem(value) {
|
|
173
|
+
if (!isRecord(value))
|
|
174
|
+
return false;
|
|
175
|
+
const issue = value.issue;
|
|
176
|
+
return (typeof value.event === 'string' &&
|
|
177
|
+
typeof value.created_at === 'string' &&
|
|
178
|
+
isRecord(issue) &&
|
|
179
|
+
typeof issue.number === 'number');
|
|
180
|
+
}
|
|
181
|
+
function isRepositoryIssueEventFeedResponse(value) {
|
|
182
|
+
return (Array.isArray(value) && value.every(isRepositoryIssueEventFeedResponseItem));
|
|
183
|
+
}
|
|
169
184
|
function listGraphqlResponseErrors(value) {
|
|
170
185
|
if (!isRecord(value))
|
|
171
186
|
return [];
|
|
@@ -537,7 +552,7 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
537
552
|
project = freshProject;
|
|
538
553
|
}
|
|
539
554
|
catch (error) {
|
|
540
|
-
if (!isFullFetch
|
|
555
|
+
if (cache !== null && (!isFullFetch || (0, isTransientApiError_1.isTransientApiError)(error))) {
|
|
541
556
|
console.warn(`Failed to refresh project metadata, using cached. projectId: ${projectId}, error: ${String(error)}`);
|
|
542
557
|
project = cache.project;
|
|
543
558
|
}
|
|
@@ -557,6 +572,7 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
557
572
|
storyOptionsChanged ||
|
|
558
573
|
cacheHasIssuesMissingStoryOptionIdSchema;
|
|
559
574
|
if (effectiveIsFullFetch) {
|
|
575
|
+
const projectMetadataFellBackToCache = cache !== null && project === cache.project;
|
|
560
576
|
const itemIdsKnownBeforeFetch = new Set(cache?.issues.map((issue) => issue.itemId) ?? []);
|
|
561
577
|
const items = await this.graphqlProjectItemRepository.fetchProjectItems(projectId);
|
|
562
578
|
const cachedIssuesKnownBeforeFetch = cache?.issues ?? [];
|
|
@@ -584,7 +600,11 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
584
600
|
return { mergedIssues: reconciledIssues, mergedProject };
|
|
585
601
|
});
|
|
586
602
|
this.lastIssuesFetchedAtByProjectId.set(projectId, nowIso);
|
|
587
|
-
return {
|
|
603
|
+
return {
|
|
604
|
+
issues,
|
|
605
|
+
project: mergedProject,
|
|
606
|
+
cacheUsed: projectMetadataFellBackToCache,
|
|
607
|
+
};
|
|
588
608
|
}
|
|
589
609
|
const itemIdsKnownBeforeFetch = new Set(cache.issues.map((issue) => issue.itemId));
|
|
590
610
|
const lastFetchedAt = new Date(cache.lastFetchedAt);
|
|
@@ -1699,21 +1719,33 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
1699
1719
|
const resolved = new Map();
|
|
1700
1720
|
for (let start = 0; start < references.length; start += RELATED_OPEN_PULL_REQUEST_URLS_BATCH_SIZE) {
|
|
1701
1721
|
const batchReferences = references.slice(start, start + RELATED_OPEN_PULL_REQUEST_URLS_BATCH_SIZE);
|
|
1702
|
-
|
|
1703
|
-
try {
|
|
1704
|
-
prUrlsByIssueUrl =
|
|
1705
|
-
await this.fetchRelatedOpenPrUrlsInOneQuery(batchReferences);
|
|
1706
|
-
}
|
|
1707
|
-
catch (error) {
|
|
1708
|
-
console.warn(`ApiV3CheerioRestIssueRepository: batched related open pull request query failed, leaving ${batchReferences.length} issue(s) to per-issue resolution. error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1709
|
-
continue;
|
|
1710
|
-
}
|
|
1722
|
+
const prUrlsByIssueUrl = await this.resolveRelatedOpenPrUrlsByBisectingFailedBatches(batchReferences);
|
|
1711
1723
|
for (const [issueUrl, prUrls] of prUrlsByIssueUrl) {
|
|
1712
1724
|
resolved.set(issueUrl, prUrls);
|
|
1713
1725
|
}
|
|
1714
1726
|
}
|
|
1715
1727
|
return resolved;
|
|
1716
1728
|
};
|
|
1729
|
+
this.resolveRelatedOpenPrUrlsByBisectingFailedBatches = async (references) => {
|
|
1730
|
+
try {
|
|
1731
|
+
return await this.fetchRelatedOpenPrUrlsInOneQuery(references);
|
|
1732
|
+
}
|
|
1733
|
+
catch (error) {
|
|
1734
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1735
|
+
if (references.length === 1) {
|
|
1736
|
+
console.warn(`ApiV3CheerioRestIssueRepository: related open pull request query failed for issue ${references[0].issueUrl}, leaving it unresolved. error: ${errorMessage}`);
|
|
1737
|
+
return new Map();
|
|
1738
|
+
}
|
|
1739
|
+
const splitPoint = Math.ceil(references.length / 2);
|
|
1740
|
+
const firstHalfResolved = await this.resolveRelatedOpenPrUrlsByBisectingFailedBatches(references.slice(0, splitPoint));
|
|
1741
|
+
const secondHalfResolved = await this.resolveRelatedOpenPrUrlsByBisectingFailedBatches(references.slice(splitPoint));
|
|
1742
|
+
const merged = new Map(firstHalfResolved);
|
|
1743
|
+
for (const [issueUrl, prUrls] of secondHalfResolved) {
|
|
1744
|
+
merged.set(issueUrl, prUrls);
|
|
1745
|
+
}
|
|
1746
|
+
return merged;
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1717
1749
|
this.fetchRelatedOpenPrUrlsInOneQuery = async (references) => {
|
|
1718
1750
|
const aliasOf = (index) => `issue${index}`;
|
|
1719
1751
|
const variableDeclarations = references
|
|
@@ -2099,7 +2131,12 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
2099
2131
|
if (issueEventListingScan.listingOutcome === 'listedEveryEvent') {
|
|
2100
2132
|
return issueEventListingScan.latestReopenedEventAt;
|
|
2101
2133
|
}
|
|
2102
|
-
|
|
2134
|
+
const latestReopenedTimelineItemListing = await this.fetchLatestReopenedTimelineItemListing(issue);
|
|
2135
|
+
if (latestReopenedTimelineItemListing.listingOutcome ===
|
|
2136
|
+
'listedEveryReopenedTimelineItem') {
|
|
2137
|
+
return latestReopenedTimelineItemListing.latestReopenedTimelineItemCreatedAt;
|
|
2138
|
+
}
|
|
2139
|
+
return this.scanRepositoryIssueEventFeedForLatestReopenedEventAt(issue, latestReopenedTimelineItemListing.lastListedReopenedTimelineItemCreatedAt);
|
|
2103
2140
|
};
|
|
2104
2141
|
this.scanIssueEventListingForLatestReopenedEventAt = async (issue) => {
|
|
2105
2142
|
const { owner, repo, issueNumber } = this.parseIssueUrl(issue.url);
|
|
@@ -2146,13 +2183,14 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
2146
2183
|
}
|
|
2147
2184
|
return { listingOutcome: 'listedEveryEvent', latestReopenedEventAt };
|
|
2148
2185
|
};
|
|
2149
|
-
this.
|
|
2186
|
+
this.fetchLatestReopenedTimelineItemListing = async (issue) => {
|
|
2150
2187
|
const { owner, repo, issueNumber } = this.parseIssueUrl(issue.url);
|
|
2151
2188
|
const query = `
|
|
2152
2189
|
query IssueLatestReopenedTimelineItem($owner: String!, $repo: String!, $issueNumber: Int!) {
|
|
2153
2190
|
repository(owner: $owner, name: $repo) {
|
|
2154
2191
|
issue(number: $issueNumber) {
|
|
2155
2192
|
timelineItems(last: 1, itemTypes: [REOPENED_EVENT]) {
|
|
2193
|
+
totalCount
|
|
2156
2194
|
nodes {
|
|
2157
2195
|
... on ReopenedEvent {
|
|
2158
2196
|
createdAt
|
|
@@ -2179,12 +2217,65 @@ class ApiV3CheerioRestIssueRepository extends BaseGitHubRepository_1.BaseGitHubR
|
|
|
2179
2217
|
throw new Error(`GitHub GraphQL API returned errors for the latest reopened timeline item of issue ${issue.url}: ${JSON.stringify(graphqlErrors)}`);
|
|
2180
2218
|
}
|
|
2181
2219
|
if (!isIssueLatestReopenedTimelineItemResponse(responseBody)) {
|
|
2182
|
-
throw new Error(`GitHub GraphQL API returned no timeline items for issue ${issue.url}`);
|
|
2220
|
+
throw new Error(`GitHub GraphQL API returned no reopened timeline items with a totalCount for issue ${issue.url}`);
|
|
2221
|
+
}
|
|
2222
|
+
const { totalCount: reopenedTimelineItemTotalCount, nodes: reopenedTimelineItems, } = responseBody.data.repository.issue.timelineItems;
|
|
2223
|
+
const lastListedReopenedTimelineItemCreatedAt = reopenedTimelineItems.length === 0
|
|
2224
|
+
? null
|
|
2225
|
+
: new Date(reopenedTimelineItems[reopenedTimelineItems.length - 1].createdAt);
|
|
2226
|
+
if (reopenedTimelineItemTotalCount <
|
|
2227
|
+
REOPENED_TIMELINE_ITEM_COUNT_AT_WHICH_GITHUB_STOPS_LISTING_REOPENED_TIMELINE_ITEMS) {
|
|
2228
|
+
return {
|
|
2229
|
+
listingOutcome: 'listedEveryReopenedTimelineItem',
|
|
2230
|
+
latestReopenedTimelineItemCreatedAt: lastListedReopenedTimelineItemCreatedAt,
|
|
2231
|
+
};
|
|
2183
2232
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
return
|
|
2233
|
+
if (lastListedReopenedTimelineItemCreatedAt === null) {
|
|
2234
|
+
throw new Error(`GitHub GraphQL API reported ${reopenedTimelineItemTotalCount} reopened timeline items but listed none for issue ${issue.url}`);
|
|
2235
|
+
}
|
|
2236
|
+
return {
|
|
2237
|
+
listingOutcome: 'stoppedAtGitHubReopenedTimelineItemListingLimit',
|
|
2238
|
+
lastListedReopenedTimelineItemCreatedAt,
|
|
2239
|
+
};
|
|
2240
|
+
};
|
|
2241
|
+
this.scanRepositoryIssueEventFeedForLatestReopenedEventAt = async (issue, lastListedReopenedTimelineItemCreatedAt) => {
|
|
2242
|
+
const { owner, repo, issueNumber } = this.parseIssueUrl(issue.url);
|
|
2243
|
+
const ownerSegment = encodeURIComponent(owner);
|
|
2244
|
+
const repoSegment = encodeURIComponent(repo);
|
|
2245
|
+
let page = 1;
|
|
2246
|
+
let hasNextPage = true;
|
|
2247
|
+
while (hasNextPage) {
|
|
2248
|
+
const repositoryIssueEventFeedUrl = `https://api.github.com/repos/${ownerSegment}/${repoSegment}/issues/events?per_page=${ISSUE_EVENTS_PAGE_SIZE}&page=${page}`;
|
|
2249
|
+
const response = await this.fetchWithRateLimitRetry(() => fetch(repositoryIssueEventFeedUrl, {
|
|
2250
|
+
method: 'GET',
|
|
2251
|
+
headers: {
|
|
2252
|
+
Authorization: `Bearer ${this.ghToken}`,
|
|
2253
|
+
Accept: 'application/vnd.github+json',
|
|
2254
|
+
},
|
|
2255
|
+
}), { method: 'GET', path: (0, githubRestClient_1.sanitizeRestPath)(repositoryIssueEventFeedUrl) });
|
|
2256
|
+
if (!response.ok) {
|
|
2257
|
+
const reason = await this.formatGitHubErrorWithStatus(response);
|
|
2258
|
+
throw new Error(`Failed to fetch page ${page} of the repository issue event feed of ${owner}/${repo} for issue ${issue.url}: ${reason}`);
|
|
2259
|
+
}
|
|
2260
|
+
const body = await response.json();
|
|
2261
|
+
if (!isRepositoryIssueEventFeedResponse(body)) {
|
|
2262
|
+
throw new Error(`Unexpected response shape when fetching page ${page} of the repository issue event feed of ${owner}/${repo} for issue ${issue.url}`);
|
|
2263
|
+
}
|
|
2264
|
+
for (const feedEvent of body) {
|
|
2265
|
+
const feedEventCreatedAt = new Date(feedEvent.created_at);
|
|
2266
|
+
if (feedEventCreatedAt < lastListedReopenedTimelineItemCreatedAt) {
|
|
2267
|
+
return lastListedReopenedTimelineItemCreatedAt;
|
|
2268
|
+
}
|
|
2269
|
+
if (feedEvent.event === 'reopened' &&
|
|
2270
|
+
feedEvent.issue.number === issueNumber) {
|
|
2271
|
+
return feedEventCreatedAt;
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
const linkHeader = response.headers.get('Link') ?? '';
|
|
2275
|
+
hasNextPage = linkHeader.includes('rel="next"');
|
|
2276
|
+
page++;
|
|
2277
|
+
}
|
|
2278
|
+
throw new Error(`The repository issue event feed of ${owner}/${repo} ended before listing a reopened event of issue ${issue.url} or an event earlier than its last listed reopened timeline item created at ${lastListedReopenedTimelineItemCreatedAt.toISOString()}`);
|
|
2188
2279
|
};
|
|
2189
2280
|
this.getPullRequestChangedFilePaths = async (prUrl) => {
|
|
2190
2281
|
const { owner, repo, issueNumber: prNumber } = this.parseIssueUrl(prUrl);
|