paperclip-github-plugin 0.5.1 → 0.5.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.
- package/README.md +9 -6
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +47 -12
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +747 -130
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -728,6 +728,17 @@ var PENDING_STATUS_CONTEXT_STATES = /* @__PURE__ */ new Set(["EXPECTED", "PENDIN
|
|
|
728
728
|
var GITHUB_REPOSITORY_MAINTAINER_WARMUP_CONCURRENCY = 4;
|
|
729
729
|
var GITHUB_REPOSITORY_MAINTAINER_ROLE_NAMES = /* @__PURE__ */ new Set(["admin", "maintain"]);
|
|
730
730
|
var GITHUB_REPOSITORY_TRUSTED_AUTHOR_ASSOCIATIONS = /* @__PURE__ */ new Set(["collaborator", "member", "owner"]);
|
|
731
|
+
var ACTION_REQUIRED_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES = /* @__PURE__ */ new Set([
|
|
732
|
+
"behind",
|
|
733
|
+
"blocked",
|
|
734
|
+
"dirty",
|
|
735
|
+
"draft",
|
|
736
|
+
"unstable"
|
|
737
|
+
]);
|
|
738
|
+
var REVIEW_READY_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES = /* @__PURE__ */ new Set([
|
|
739
|
+
"clean",
|
|
740
|
+
"has_hooks"
|
|
741
|
+
]);
|
|
731
742
|
var GITHUB_ISSUE_STATUS_SNAPSHOT_QUERY = `
|
|
732
743
|
query GitHubIssueStatusSnapshot($owner: String!, $repo: String!, $issueNumber: Int!, $after: String) {
|
|
733
744
|
repository(owner: $owner, name: $repo) {
|
|
@@ -762,6 +773,8 @@ var GITHUB_PULL_REQUEST_CI_CONTEXTS_QUERY = `
|
|
|
762
773
|
query GitHubPullRequestCiContexts($owner: String!, $repo: String!, $pullRequestNumber: Int!, $after: String) {
|
|
763
774
|
repository(owner: $owner, name: $repo) {
|
|
764
775
|
pullRequest(number: $pullRequestNumber) {
|
|
776
|
+
mergeable
|
|
777
|
+
mergeStateStatus
|
|
765
778
|
statusCheckRollup {
|
|
766
779
|
contexts(first: 100, after: $after) {
|
|
767
780
|
pageInfo {
|
|
@@ -825,6 +838,8 @@ var GITHUB_REPOSITORY_OPEN_PULL_REQUEST_STATUSES_QUERY = `
|
|
|
825
838
|
}
|
|
826
839
|
nodes {
|
|
827
840
|
number
|
|
841
|
+
mergeable
|
|
842
|
+
mergeStateStatus
|
|
828
843
|
reviewThreads(first: 100) {
|
|
829
844
|
pageInfo {
|
|
830
845
|
hasNextPage
|
|
@@ -950,6 +965,8 @@ var GITHUB_PROJECT_PULL_REQUEST_SUMMARY_FIELDS = `${GITHUB_PROJECT_PULL_REQUEST_
|
|
|
950
965
|
var GITHUB_PROJECT_PULL_REQUEST_METRICS_FIELDS = `
|
|
951
966
|
number
|
|
952
967
|
mergeable
|
|
968
|
+
mergeStateStatus
|
|
969
|
+
baseRefName
|
|
953
970
|
reviews(first: 100) {
|
|
954
971
|
pageInfo {
|
|
955
972
|
hasNextPage
|
|
@@ -2219,6 +2236,7 @@ async function resolvePaperclipIssueGitHubLink(ctx, issueId, companyId, options
|
|
|
2219
2236
|
githubIssueNumber: entityMatch.data.githubIssueNumber,
|
|
2220
2237
|
githubIssueUrl: entityMatch.data.githubIssueUrl,
|
|
2221
2238
|
linkedPullRequestNumbers: entityMatch.data.linkedPullRequestNumbers,
|
|
2239
|
+
linkedPullRequests: entityMatch.data.linkedPullRequests,
|
|
2222
2240
|
entityRecord: entityMatch
|
|
2223
2241
|
};
|
|
2224
2242
|
}
|
|
@@ -2240,7 +2258,8 @@ async function resolvePaperclipIssueGitHubLink(ctx, issueId, companyId, options
|
|
|
2240
2258
|
githubIssueId: registryMatch.githubIssueId,
|
|
2241
2259
|
githubIssueNumber: registryMatch.githubIssueNumber,
|
|
2242
2260
|
githubIssueUrl: githubIssueUrl2,
|
|
2243
|
-
linkedPullRequestNumbers: []
|
|
2261
|
+
linkedPullRequestNumbers: [],
|
|
2262
|
+
linkedPullRequests: []
|
|
2244
2263
|
};
|
|
2245
2264
|
return await hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLink2) ?? fallbackLink2;
|
|
2246
2265
|
}
|
|
@@ -2258,7 +2277,8 @@ async function resolvePaperclipIssueGitHubLink(ctx, issueId, companyId, options
|
|
|
2258
2277
|
repositoryUrl: githubIssueReference.repositoryUrl,
|
|
2259
2278
|
githubIssueNumber: githubIssueReference.issueNumber,
|
|
2260
2279
|
githubIssueUrl: githubIssueReference.issueUrl,
|
|
2261
|
-
linkedPullRequestNumbers: []
|
|
2280
|
+
linkedPullRequestNumbers: [],
|
|
2281
|
+
linkedPullRequests: []
|
|
2262
2282
|
};
|
|
2263
2283
|
return await hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLink) ?? fallbackLink;
|
|
2264
2284
|
}
|
|
@@ -2293,7 +2313,7 @@ async function hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLi
|
|
|
2293
2313
|
},
|
|
2294
2314
|
issueId,
|
|
2295
2315
|
githubIssue,
|
|
2296
|
-
|
|
2316
|
+
linkedPullRequests
|
|
2297
2317
|
);
|
|
2298
2318
|
await upsertGitHubIssueLinkRecord(
|
|
2299
2319
|
ctx,
|
|
@@ -2304,7 +2324,7 @@ async function hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLi
|
|
|
2304
2324
|
},
|
|
2305
2325
|
issueId,
|
|
2306
2326
|
githubIssue,
|
|
2307
|
-
|
|
2327
|
+
linkedPullRequests
|
|
2308
2328
|
);
|
|
2309
2329
|
return {
|
|
2310
2330
|
source: "entity",
|
|
@@ -2315,6 +2335,7 @@ async function hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLi
|
|
|
2315
2335
|
githubIssueNumber: githubIssue.number,
|
|
2316
2336
|
githubIssueUrl: normalizeGitHubIssueHtmlUrl(githubIssue.htmlUrl) ?? githubIssue.htmlUrl,
|
|
2317
2337
|
linkedPullRequestNumbers,
|
|
2338
|
+
linkedPullRequests: normalizeLinkedPullRequestReferences(linkedPullRequests, fallbackLink.repositoryUrl),
|
|
2318
2339
|
entityRecord
|
|
2319
2340
|
};
|
|
2320
2341
|
} catch (error) {
|
|
@@ -2418,11 +2439,12 @@ function buildCommentAnnotationLinksFromStoredData(annotation) {
|
|
|
2418
2439
|
href: annotation.githubIssueUrl
|
|
2419
2440
|
}
|
|
2420
2441
|
];
|
|
2421
|
-
|
|
2442
|
+
const linkedPullRequests = annotation.linkedPullRequests.length > 0 ? annotation.linkedPullRequests : normalizeLinkedPullRequestReferences(annotation.linkedPullRequestNumbers, annotation.repositoryUrl);
|
|
2443
|
+
for (const pullRequest of linkedPullRequests) {
|
|
2422
2444
|
links.push({
|
|
2423
2445
|
type: "pull_request",
|
|
2424
|
-
label:
|
|
2425
|
-
href: `${
|
|
2446
|
+
label: formatLinkedPullRequestReferenceLabel(pullRequest, annotation.repositoryUrl),
|
|
2447
|
+
href: `${pullRequest.repositoryUrl}/pull/${pullRequest.number}`
|
|
2426
2448
|
});
|
|
2427
2449
|
}
|
|
2428
2450
|
return links;
|
|
@@ -2540,6 +2562,7 @@ async function buildIssueGitHubDetails(ctx, input) {
|
|
|
2540
2562
|
githubIssueStateReason: entityMatch.data.githubIssueStateReason,
|
|
2541
2563
|
commentsCount: entityMatch.data.commentsCount,
|
|
2542
2564
|
linkedPullRequestNumbers: entityMatch.data.linkedPullRequestNumbers,
|
|
2565
|
+
linkedPullRequests: entityMatch.data.linkedPullRequests,
|
|
2543
2566
|
labels: entityMatch.data.labels,
|
|
2544
2567
|
syncedAt: entityMatch.data.syncedAt
|
|
2545
2568
|
};
|
|
@@ -2550,7 +2573,8 @@ async function buildIssueGitHubDetails(ctx, input) {
|
|
|
2550
2573
|
githubIssueNumber: link.githubIssueNumber,
|
|
2551
2574
|
githubIssueUrl: link.githubIssueUrl,
|
|
2552
2575
|
repositoryUrl: link.repositoryUrl,
|
|
2553
|
-
linkedPullRequestNumbers: link.linkedPullRequestNumbers
|
|
2576
|
+
linkedPullRequestNumbers: link.linkedPullRequestNumbers,
|
|
2577
|
+
linkedPullRequests: link.linkedPullRequests
|
|
2554
2578
|
};
|
|
2555
2579
|
}
|
|
2556
2580
|
async function resolveIssueByIdentifier(ctx, input) {
|
|
@@ -3698,6 +3722,9 @@ function normalizeImportRegistry(value) {
|
|
|
3698
3722
|
const paperclipProjectId = typeof record.paperclipProjectId === "string" && record.paperclipProjectId.trim() ? record.paperclipProjectId.trim() : void 0;
|
|
3699
3723
|
const companyId = typeof record.companyId === "string" && record.companyId.trim() ? record.companyId.trim() : void 0;
|
|
3700
3724
|
const lastSeenCommentCount = typeof record.lastSeenCommentCount === "number" && record.lastSeenCommentCount >= 0 ? Math.floor(record.lastSeenCommentCount) : void 0;
|
|
3725
|
+
const linkedPullRequestCommentCounts = normalizeGitHubPullRequestCommentCountRecords(
|
|
3726
|
+
record.linkedPullRequestCommentCounts
|
|
3727
|
+
);
|
|
3701
3728
|
if (!mappingId || Number.isNaN(githubIssueId) || !paperclipIssueId || !importedAt) {
|
|
3702
3729
|
return null;
|
|
3703
3730
|
}
|
|
@@ -3710,7 +3737,8 @@ function normalizeImportRegistry(value) {
|
|
|
3710
3737
|
...repositoryUrl ? { repositoryUrl } : {},
|
|
3711
3738
|
...paperclipProjectId ? { paperclipProjectId } : {},
|
|
3712
3739
|
...companyId ? { companyId } : {},
|
|
3713
|
-
...lastSeenCommentCount !== void 0 ? { lastSeenCommentCount } : {}
|
|
3740
|
+
...lastSeenCommentCount !== void 0 ? { lastSeenCommentCount } : {},
|
|
3741
|
+
...linkedPullRequestCommentCounts.length > 0 ? { linkedPullRequestCommentCounts } : {}
|
|
3714
3742
|
};
|
|
3715
3743
|
}).filter((entry) => entry !== null);
|
|
3716
3744
|
}
|
|
@@ -3756,6 +3784,7 @@ function buildImportedIssueRecord(mapping, issue, paperclipIssueId, importedAt)
|
|
|
3756
3784
|
paperclipIssueId,
|
|
3757
3785
|
importedAt,
|
|
3758
3786
|
lastSeenCommentCount: issue.commentsCount,
|
|
3787
|
+
linkedPullRequestCommentCounts: [],
|
|
3759
3788
|
repositoryUrl: getNormalizedMappingRepositoryUrl(mapping),
|
|
3760
3789
|
paperclipProjectId: mapping.paperclipProjectId,
|
|
3761
3790
|
companyId: mapping.companyId
|
|
@@ -4010,8 +4039,13 @@ function normalizeProjectPullRequestClosingIssues(repository, nodes) {
|
|
|
4010
4039
|
function resolveProjectPullRequestReviewable(record) {
|
|
4011
4040
|
return record.githubMergeable === true && record.checksStatus === "passed" && typeof record.copilotUnresolvedReviewThreads === "number" && record.copilotUnresolvedReviewThreads === 0;
|
|
4012
4041
|
}
|
|
4042
|
+
function resolveProjectPullRequestTargetsDefaultBranch(record) {
|
|
4043
|
+
const baseBranch = normalizeOptionalString2(record.baseBranch);
|
|
4044
|
+
const defaultBranchName = normalizeOptionalString2(record.defaultBranchName);
|
|
4045
|
+
return Boolean(baseBranch && defaultBranchName && baseBranch === defaultBranchName);
|
|
4046
|
+
}
|
|
4013
4047
|
function resolveProjectPullRequestMergeable(record) {
|
|
4014
|
-
return record.githubMergeable === true && record.checksStatus === "passed" && typeof record.reviewApprovals === "number" && record.reviewApprovals > 0 && typeof record.unresolvedReviewThreads === "number" && record.unresolvedReviewThreads === 0;
|
|
4048
|
+
return record.githubMergeable === true && record.checksStatus === "passed" && typeof record.reviewApprovals === "number" && record.reviewApprovals > 0 && typeof record.reviewChangesRequested === "number" && record.reviewChangesRequested === 0 && typeof record.unresolvedReviewThreads === "number" && record.unresolvedReviewThreads === 0 && resolveProjectPullRequestTargetsDefaultBranch(record);
|
|
4015
4049
|
}
|
|
4016
4050
|
function resolveProjectPullRequestUpToDateStatus(record) {
|
|
4017
4051
|
const mergeStateStatus = typeof record.mergeStateStatus === "string" ? record.mergeStateStatus : null;
|
|
@@ -4194,12 +4228,12 @@ function classifyGitHubPullRequestCiState(contexts) {
|
|
|
4194
4228
|
return hasPendingContext ? "unfinished" : "green";
|
|
4195
4229
|
}
|
|
4196
4230
|
function resolvePaperclipStatusFromLinkedPullRequests(linkedPullRequests, options) {
|
|
4197
|
-
if (linkedPullRequests.some(
|
|
4231
|
+
if (linkedPullRequests.some(
|
|
4232
|
+
(pullRequest) => pullRequest.hasUnresolvedReviewThreads || pullRequest.ciState === "red" || isGitHubPullRequestActionRequiredForSync(pullRequest)
|
|
4233
|
+
)) {
|
|
4198
4234
|
return options?.preferInProgress ? "in_progress" : "todo";
|
|
4199
4235
|
}
|
|
4200
|
-
if (linkedPullRequests.length > 0 && linkedPullRequests.every(
|
|
4201
|
-
(pullRequest) => pullRequest.ciState === "green" && pullRequest.hasUnresolvedReviewThreads === false
|
|
4202
|
-
)) {
|
|
4236
|
+
if (linkedPullRequests.length > 0 && linkedPullRequests.every((pullRequest) => isGitHubPullRequestReviewReadyForSync(pullRequest))) {
|
|
4203
4237
|
return "in_review";
|
|
4204
4238
|
}
|
|
4205
4239
|
return "in_progress";
|
|
@@ -4445,15 +4479,19 @@ function resolvePaperclipIssueReviewAssignee(syncContext, advancedSettings) {
|
|
|
4445
4479
|
role: nextStage.type === "approval" ? "approver" : "reviewer"
|
|
4446
4480
|
};
|
|
4447
4481
|
}
|
|
4482
|
+
const reviewStageType = nextStage?.type ?? currentStageType;
|
|
4483
|
+
if (!reviewStageType && !syncContext.executionPolicy) {
|
|
4484
|
+
return null;
|
|
4485
|
+
}
|
|
4448
4486
|
const approverOverride = getConfiguredAdvancedAssigneePrincipal(advancedSettings, "approver");
|
|
4449
|
-
if (
|
|
4487
|
+
if (reviewStageType === "approval" && approverOverride) {
|
|
4450
4488
|
return {
|
|
4451
4489
|
principal: approverOverride,
|
|
4452
4490
|
role: "approver"
|
|
4453
4491
|
};
|
|
4454
4492
|
}
|
|
4455
4493
|
const reviewerOverride = getConfiguredAdvancedAssigneePrincipal(advancedSettings, "reviewer");
|
|
4456
|
-
if (reviewerOverride) {
|
|
4494
|
+
if (reviewStageType !== "approval" && reviewerOverride) {
|
|
4457
4495
|
return {
|
|
4458
4496
|
principal: reviewerOverride,
|
|
4459
4497
|
role: "reviewer"
|
|
@@ -4541,6 +4579,9 @@ function buildSyncFallbackExecutionStatePatch(params) {
|
|
|
4541
4579
|
if ((currentStatus === "done" || currentStatus === "cancelled") && nextStatus !== "done" && nextStatus !== "cancelled") {
|
|
4542
4580
|
return previousState ? null : void 0;
|
|
4543
4581
|
}
|
|
4582
|
+
if (nextStatus === "done" || nextStatus === "cancelled") {
|
|
4583
|
+
return previousState ? null : void 0;
|
|
4584
|
+
}
|
|
4544
4585
|
if (nextStatus === "in_review" && syncContext.executionPolicy) {
|
|
4545
4586
|
const nextStageMatch = findPaperclipIssueExecutionStageMatch(syncContext.executionPolicy, previousState);
|
|
4546
4587
|
if (!nextStageMatch) {
|
|
@@ -4576,7 +4617,7 @@ function buildSyncFallbackExecutionStatePatch(params) {
|
|
|
4576
4617
|
return void 0;
|
|
4577
4618
|
}
|
|
4578
4619
|
function describeGitHubStatusTransitionReason(params) {
|
|
4579
|
-
const { snapshot,
|
|
4620
|
+
const { snapshot, hasTrustedNewComment, maintainerAuthoredImportedIssue } = params;
|
|
4580
4621
|
if (snapshot.state === "closed") {
|
|
4581
4622
|
switch (snapshot.stateReason) {
|
|
4582
4623
|
case "duplicate":
|
|
@@ -4587,8 +4628,7 @@ function describeGitHubStatusTransitionReason(params) {
|
|
|
4587
4628
|
return "the GitHub issue was closed as completed work";
|
|
4588
4629
|
}
|
|
4589
4630
|
}
|
|
4590
|
-
|
|
4591
|
-
if (snapshot.commentCount > baselineCommentCount && hasTrustedNewComment) {
|
|
4631
|
+
if (hasTrustedNewComment) {
|
|
4592
4632
|
return "a new GitHub comment from the issue author or a repository maintainer was added";
|
|
4593
4633
|
}
|
|
4594
4634
|
if (snapshot.linkedPullRequests.length === 0) {
|
|
@@ -4599,32 +4639,33 @@ function describeGitHubStatusTransitionReason(params) {
|
|
|
4599
4639
|
}
|
|
4600
4640
|
const linkedPullRequestSubject = snapshot.linkedPullRequests.length === 1 ? "the linked pull request" : "linked pull requests";
|
|
4601
4641
|
const linkedPullRequestVerb = snapshot.linkedPullRequests.length === 1 ? "has" : "have";
|
|
4602
|
-
const
|
|
4603
|
-
|
|
4642
|
+
const blockingConditions = [...new Set(
|
|
4643
|
+
snapshot.linkedPullRequests.flatMap((pullRequest) => listGitHubPullRequestSyncBlockingConditions(pullRequest))
|
|
4644
|
+
)];
|
|
4604
4645
|
const hasUnfinishedCi = snapshot.linkedPullRequests.some((pullRequest) => pullRequest.ciState === "unfinished");
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
if (
|
|
4609
|
-
return `${linkedPullRequestSubject} ${linkedPullRequestVerb}
|
|
4610
|
-
}
|
|
4611
|
-
if (hasUnresolvedReviewThreads) {
|
|
4612
|
-
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} unresolved review threads`;
|
|
4646
|
+
const hasUnknownMergeability = snapshot.linkedPullRequests.some(
|
|
4647
|
+
(pullRequest) => pullRequest.mergeStateStatus === "unknown"
|
|
4648
|
+
);
|
|
4649
|
+
if (blockingConditions.length > 0) {
|
|
4650
|
+
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} ${formatPlainTextList(blockingConditions)}`;
|
|
4613
4651
|
}
|
|
4614
4652
|
if (hasUnfinishedCi) {
|
|
4615
4653
|
return `${linkedPullRequestSubject} still ${linkedPullRequestVerb} unfinished CI jobs`;
|
|
4616
4654
|
}
|
|
4655
|
+
if (hasUnknownMergeability) {
|
|
4656
|
+
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} unknown mergeability`;
|
|
4657
|
+
}
|
|
4617
4658
|
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} green CI with all review threads resolved`;
|
|
4618
4659
|
}
|
|
4619
4660
|
function buildStatusTransitionCommentAnnotation(params) {
|
|
4620
4661
|
const { repository, snapshot, previousStatus, nextStatus, reason } = params;
|
|
4662
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(snapshot.linkedPullRequests);
|
|
4621
4663
|
return {
|
|
4622
4664
|
repositoryUrl: repository.url,
|
|
4623
4665
|
githubIssueNumber: snapshot.issueNumber,
|
|
4624
4666
|
githubIssueUrl: `${repository.url}/issues/${snapshot.issueNumber}`,
|
|
4625
|
-
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
4626
|
-
|
|
4627
|
-
),
|
|
4667
|
+
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(linkedPullRequests.map((pullRequest) => pullRequest.number)),
|
|
4668
|
+
linkedPullRequests,
|
|
4628
4669
|
previousStatus,
|
|
4629
4670
|
nextStatus,
|
|
4630
4671
|
reason,
|
|
@@ -4638,13 +4679,11 @@ function buildPaperclipIssueStatusTransitionComment(params) {
|
|
|
4638
4679
|
nextStatus,
|
|
4639
4680
|
repository,
|
|
4640
4681
|
snapshot,
|
|
4641
|
-
previousCommentCount,
|
|
4642
4682
|
hasTrustedNewComment,
|
|
4643
4683
|
maintainerAuthoredImportedIssue
|
|
4644
4684
|
} = params;
|
|
4645
4685
|
const reason = describeGitHubStatusTransitionReason({
|
|
4646
4686
|
snapshot,
|
|
4647
|
-
previousCommentCount,
|
|
4648
4687
|
hasTrustedNewComment,
|
|
4649
4688
|
maintainerAuthoredImportedIssue
|
|
4650
4689
|
});
|
|
@@ -4663,7 +4702,6 @@ function resolvePaperclipIssueStatus(params) {
|
|
|
4663
4702
|
const {
|
|
4664
4703
|
currentStatus,
|
|
4665
4704
|
snapshot,
|
|
4666
|
-
previousCommentCount,
|
|
4667
4705
|
hasTrustedNewComment,
|
|
4668
4706
|
wasImportedThisRun,
|
|
4669
4707
|
defaultImportedStatus,
|
|
@@ -4676,8 +4714,7 @@ function resolvePaperclipIssueStatus(params) {
|
|
|
4676
4714
|
if (currentStatus === "backlog" && !wasImportedThisRun) {
|
|
4677
4715
|
return "backlog";
|
|
4678
4716
|
}
|
|
4679
|
-
|
|
4680
|
-
if (snapshot.commentCount > baselineCommentCount && hasTrustedNewComment) {
|
|
4717
|
+
if (hasTrustedNewComment) {
|
|
4681
4718
|
return hasExecutorHandoffTarget ? "in_progress" : "todo";
|
|
4682
4719
|
}
|
|
4683
4720
|
if (snapshot.linkedPullRequests.length > 0) {
|
|
@@ -4695,7 +4732,7 @@ function resolvePaperclipIssueStatus(params) {
|
|
|
4695
4732
|
}
|
|
4696
4733
|
async function listLinkedPullRequestsForIssue(octokit, repository, issueNumber) {
|
|
4697
4734
|
const linkedPullRequests = [];
|
|
4698
|
-
const
|
|
4735
|
+
const seenPullRequestKeys = /* @__PURE__ */ new Set();
|
|
4699
4736
|
let after;
|
|
4700
4737
|
do {
|
|
4701
4738
|
const response = await octokit.graphql(GITHUB_ISSUE_STATUS_SNAPSHOT_QUERY, {
|
|
@@ -4707,31 +4744,37 @@ async function listLinkedPullRequestsForIssue(octokit, repository, issueNumber)
|
|
|
4707
4744
|
const nextLinkedPullRequests = collectGitHubLinkedPullRequests(
|
|
4708
4745
|
response.repository?.issue?.closedByPullRequestsReferences?.nodes ?? [],
|
|
4709
4746
|
repository,
|
|
4710
|
-
|
|
4747
|
+
seenPullRequestKeys
|
|
4711
4748
|
);
|
|
4712
4749
|
linkedPullRequests.push(...nextLinkedPullRequests);
|
|
4713
4750
|
after = getPageCursor(response.repository?.issue?.closedByPullRequestsReferences?.pageInfo);
|
|
4714
4751
|
} while (after);
|
|
4715
4752
|
return linkedPullRequests;
|
|
4716
4753
|
}
|
|
4717
|
-
function collectGitHubLinkedPullRequests(nodes, repository,
|
|
4754
|
+
function collectGitHubLinkedPullRequests(nodes, repository, seenPullRequestKeys = /* @__PURE__ */ new Set()) {
|
|
4718
4755
|
const linkedPullRequests = [];
|
|
4719
4756
|
for (const node of nodes) {
|
|
4720
|
-
if (!node || typeof node.number !== "number" || !node.state
|
|
4757
|
+
if (!node || typeof node.number !== "number" || !node.state) {
|
|
4721
4758
|
continue;
|
|
4722
4759
|
}
|
|
4723
4760
|
const pullRequestOwner = node.repository?.owner?.login?.trim();
|
|
4724
4761
|
const pullRequestRepo = node.repository?.name?.trim();
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
repo: pullRequestRepo
|
|
4728
|
-
})) {
|
|
4762
|
+
const pullRequestRepository = pullRequestOwner && pullRequestRepo ? parseRepositoryReference(`${pullRequestOwner}/${pullRequestRepo}`) : repository;
|
|
4763
|
+
if (!pullRequestRepository) {
|
|
4729
4764
|
continue;
|
|
4730
4765
|
}
|
|
4731
|
-
|
|
4766
|
+
const pullRequestKey = buildGitHubPullRequestReferenceKey({
|
|
4767
|
+
number: node.number,
|
|
4768
|
+
repositoryUrl: pullRequestRepository.url
|
|
4769
|
+
});
|
|
4770
|
+
if (seenPullRequestKeys.has(pullRequestKey)) {
|
|
4771
|
+
continue;
|
|
4772
|
+
}
|
|
4773
|
+
seenPullRequestKeys.add(pullRequestKey);
|
|
4732
4774
|
linkedPullRequests.push({
|
|
4733
4775
|
number: node.number,
|
|
4734
|
-
state: node.state
|
|
4776
|
+
state: node.state,
|
|
4777
|
+
repositoryUrl: pullRequestRepository.url
|
|
4735
4778
|
});
|
|
4736
4779
|
}
|
|
4737
4780
|
return linkedPullRequests;
|
|
@@ -4789,7 +4832,75 @@ function extractGitHubCiContextRecords(nodes) {
|
|
|
4789
4832
|
}
|
|
4790
4833
|
return contexts;
|
|
4791
4834
|
}
|
|
4792
|
-
function
|
|
4835
|
+
function normalizeGitHubPullRequestMergeability(value) {
|
|
4836
|
+
if (value === "MERGEABLE") {
|
|
4837
|
+
return "mergeable";
|
|
4838
|
+
}
|
|
4839
|
+
if (value === "CONFLICTING") {
|
|
4840
|
+
return "conflicting";
|
|
4841
|
+
}
|
|
4842
|
+
return "unknown";
|
|
4843
|
+
}
|
|
4844
|
+
function normalizeGitHubPullRequestMergeStateStatus(value) {
|
|
4845
|
+
switch (typeof value === "string" ? value.trim().toLowerCase() : "") {
|
|
4846
|
+
case "behind":
|
|
4847
|
+
return "behind";
|
|
4848
|
+
case "blocked":
|
|
4849
|
+
return "blocked";
|
|
4850
|
+
case "clean":
|
|
4851
|
+
return "clean";
|
|
4852
|
+
case "dirty":
|
|
4853
|
+
return "dirty";
|
|
4854
|
+
case "draft":
|
|
4855
|
+
return "draft";
|
|
4856
|
+
case "has_hooks":
|
|
4857
|
+
return "has_hooks";
|
|
4858
|
+
case "unstable":
|
|
4859
|
+
return "unstable";
|
|
4860
|
+
default:
|
|
4861
|
+
return "unknown";
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4864
|
+
function isGitHubPullRequestActionRequiredForSync(pullRequest) {
|
|
4865
|
+
return pullRequest.mergeability === "conflicting" || ACTION_REQUIRED_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES.has(pullRequest.mergeStateStatus);
|
|
4866
|
+
}
|
|
4867
|
+
function isGitHubPullRequestReviewReadyForSync(pullRequest) {
|
|
4868
|
+
if (pullRequest.ciState !== "green" || pullRequest.hasUnresolvedReviewThreads) {
|
|
4869
|
+
return false;
|
|
4870
|
+
}
|
|
4871
|
+
return REVIEW_READY_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES.has(pullRequest.mergeStateStatus);
|
|
4872
|
+
}
|
|
4873
|
+
function listGitHubPullRequestSyncBlockingConditions(pullRequest) {
|
|
4874
|
+
const conditions = [];
|
|
4875
|
+
if (pullRequest.ciState === "red") {
|
|
4876
|
+
conditions.push("failing CI");
|
|
4877
|
+
}
|
|
4878
|
+
if (pullRequest.mergeability === "conflicting" || pullRequest.mergeStateStatus === "dirty") {
|
|
4879
|
+
conditions.push("merge conflicts");
|
|
4880
|
+
} else {
|
|
4881
|
+
switch (pullRequest.mergeStateStatus) {
|
|
4882
|
+
case "behind":
|
|
4883
|
+
conditions.push("out-of-date branch state");
|
|
4884
|
+
break;
|
|
4885
|
+
case "blocked":
|
|
4886
|
+
conditions.push("blocked merge requirements");
|
|
4887
|
+
break;
|
|
4888
|
+
case "draft":
|
|
4889
|
+
conditions.push("draft status");
|
|
4890
|
+
break;
|
|
4891
|
+
case "unstable":
|
|
4892
|
+
conditions.push("unstable merge requirements");
|
|
4893
|
+
break;
|
|
4894
|
+
default:
|
|
4895
|
+
break;
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
if (pullRequest.hasUnresolvedReviewThreads) {
|
|
4899
|
+
conditions.push("unresolved review threads");
|
|
4900
|
+
}
|
|
4901
|
+
return conditions;
|
|
4902
|
+
}
|
|
4903
|
+
function tryBuildGitHubPullRequestStatusSnapshotFromBatchNode(node, repository) {
|
|
4793
4904
|
if (typeof node.number !== "number") {
|
|
4794
4905
|
return null;
|
|
4795
4906
|
}
|
|
@@ -4800,8 +4911,11 @@ function tryBuildGitHubPullRequestStatusSnapshotFromBatchNode(node) {
|
|
|
4800
4911
|
}
|
|
4801
4912
|
return {
|
|
4802
4913
|
number: node.number,
|
|
4914
|
+
repositoryUrl: repository.url,
|
|
4803
4915
|
hasUnresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads > 0,
|
|
4804
|
-
ciState
|
|
4916
|
+
ciState,
|
|
4917
|
+
mergeability: normalizeGitHubPullRequestMergeability(node.mergeable),
|
|
4918
|
+
mergeStateStatus: normalizeGitHubPullRequestMergeStateStatus(node.mergeStateStatus)
|
|
4805
4919
|
};
|
|
4806
4920
|
}
|
|
4807
4921
|
function tryBuildGitHubPullRequestCiStateFromBatchNode(node) {
|
|
@@ -4816,7 +4930,9 @@ async function warmGitHubPullRequestStatusCache(octokit, repository, targetPullR
|
|
|
4816
4930
|
return;
|
|
4817
4931
|
}
|
|
4818
4932
|
const remainingNumbers = new Set(
|
|
4819
|
-
[...targetPullRequestNumbers].filter(
|
|
4933
|
+
[...targetPullRequestNumbers].filter(
|
|
4934
|
+
(pullRequestNumber) => !getCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, repository, pullRequestNumber)
|
|
4935
|
+
)
|
|
4820
4936
|
);
|
|
4821
4937
|
if (remainingNumbers.size === 0) {
|
|
4822
4938
|
return;
|
|
@@ -4837,9 +4953,9 @@ async function warmGitHubPullRequestStatusCache(octokit, repository, targetPullR
|
|
|
4837
4953
|
continue;
|
|
4838
4954
|
}
|
|
4839
4955
|
remainingNumbers.delete(node.number);
|
|
4840
|
-
const snapshot = tryBuildGitHubPullRequestStatusSnapshotFromBatchNode(node);
|
|
4956
|
+
const snapshot = tryBuildGitHubPullRequestStatusSnapshotFromBatchNode(node, repository);
|
|
4841
4957
|
if (snapshot) {
|
|
4842
|
-
pullRequestStatusCache
|
|
4958
|
+
setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot);
|
|
4843
4959
|
cacheGitHubPullRequestStatusSnapshot(repository, snapshot);
|
|
4844
4960
|
}
|
|
4845
4961
|
}
|
|
@@ -4850,7 +4966,12 @@ async function warmGitHubPullRequestStatusCache(octokit, repository, targetPullR
|
|
|
4850
4966
|
} while (after);
|
|
4851
4967
|
}
|
|
4852
4968
|
async function getGitHubPullRequestCiState(octokit, repository, pullRequestNumber) {
|
|
4969
|
+
return (await getGitHubPullRequestCiSnapshot(octokit, repository, pullRequestNumber)).ciState;
|
|
4970
|
+
}
|
|
4971
|
+
async function getGitHubPullRequestCiSnapshot(octokit, repository, pullRequestNumber) {
|
|
4853
4972
|
const contexts = [];
|
|
4973
|
+
let mergeability = "unknown";
|
|
4974
|
+
let mergeStateStatus = "unknown";
|
|
4854
4975
|
let after;
|
|
4855
4976
|
do {
|
|
4856
4977
|
const response = await octokit.graphql(GITHUB_PULL_REQUEST_CI_CONTEXTS_QUERY, {
|
|
@@ -4859,6 +4980,8 @@ async function getGitHubPullRequestCiState(octokit, repository, pullRequestNumbe
|
|
|
4859
4980
|
pullRequestNumber,
|
|
4860
4981
|
after
|
|
4861
4982
|
});
|
|
4983
|
+
mergeability = normalizeGitHubPullRequestMergeability(response.repository?.pullRequest?.mergeable);
|
|
4984
|
+
mergeStateStatus = normalizeGitHubPullRequestMergeStateStatus(response.repository?.pullRequest?.mergeStateStatus);
|
|
4862
4985
|
const connection = response.repository?.pullRequest?.statusCheckRollup?.contexts;
|
|
4863
4986
|
const nodes = connection?.nodes ?? [];
|
|
4864
4987
|
for (const node of nodes) {
|
|
@@ -4882,49 +5005,63 @@ async function getGitHubPullRequestCiState(octokit, repository, pullRequestNumbe
|
|
|
4882
5005
|
}
|
|
4883
5006
|
after = getPageCursor(connection?.pageInfo);
|
|
4884
5007
|
} while (after);
|
|
4885
|
-
return
|
|
5008
|
+
return {
|
|
5009
|
+
ciState: classifyGitHubPullRequestCiState(contexts),
|
|
5010
|
+
mergeability,
|
|
5011
|
+
mergeStateStatus
|
|
5012
|
+
};
|
|
4886
5013
|
}
|
|
4887
5014
|
async function getGitHubPullRequestStatusSnapshot(octokit, repository, pullRequestNumber, pullRequestStatusCache, options) {
|
|
4888
|
-
const cached = pullRequestStatusCache
|
|
5015
|
+
const cached = getCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, repository, pullRequestNumber);
|
|
4889
5016
|
if (cached) {
|
|
4890
5017
|
return cached;
|
|
4891
5018
|
}
|
|
4892
5019
|
const cacheKey = buildRepositoryPullRequestRecordCacheKey(repository, pullRequestNumber, "status");
|
|
4893
5020
|
const cachedSnapshot = getFreshCacheValue(activeGitHubPullRequestStatusSnapshotCache, cacheKey);
|
|
4894
5021
|
if (cachedSnapshot) {
|
|
4895
|
-
pullRequestStatusCache
|
|
5022
|
+
setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, cachedSnapshot);
|
|
4896
5023
|
return cachedSnapshot;
|
|
4897
5024
|
}
|
|
4898
|
-
if (options?.reviewThreadSummary && options.ciState) {
|
|
5025
|
+
if (options?.reviewThreadSummary && options.ciState && options.mergeability !== void 0 && options.mergeStateStatus !== void 0) {
|
|
4899
5026
|
const snapshot = cacheGitHubPullRequestStatusSnapshot(repository, {
|
|
4900
5027
|
number: pullRequestNumber,
|
|
5028
|
+
repositoryUrl: repository.url,
|
|
4901
5029
|
hasUnresolvedReviewThreads: options.reviewThreadSummary.unresolvedReviewThreads > 0,
|
|
4902
|
-
ciState: options.ciState
|
|
5030
|
+
ciState: options.ciState,
|
|
5031
|
+
mergeability: options.mergeability,
|
|
5032
|
+
mergeStateStatus: options.mergeStateStatus
|
|
4903
5033
|
});
|
|
4904
|
-
pullRequestStatusCache
|
|
5034
|
+
setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot);
|
|
4905
5035
|
return snapshot;
|
|
4906
5036
|
}
|
|
4907
5037
|
const inFlightSnapshot = activeGitHubPullRequestStatusSnapshotPromiseCache.get(cacheKey);
|
|
4908
5038
|
if (inFlightSnapshot) {
|
|
4909
5039
|
const snapshot = await inFlightSnapshot;
|
|
4910
|
-
pullRequestStatusCache
|
|
5040
|
+
setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot);
|
|
4911
5041
|
return snapshot;
|
|
4912
5042
|
}
|
|
4913
5043
|
const loadSnapshotPromise = (async () => {
|
|
4914
|
-
const [reviewThreadSummary,
|
|
5044
|
+
const [reviewThreadSummary, ciSnapshot] = await Promise.all([
|
|
4915
5045
|
options?.reviewThreadSummary ?? getOrLoadCachedGitHubPullRequestReviewThreadSummary(octokit, repository, pullRequestNumber),
|
|
4916
|
-
options?.ciState
|
|
5046
|
+
options?.ciState && options.mergeability !== void 0 && options.mergeStateStatus !== void 0 ? {
|
|
5047
|
+
ciState: options.ciState,
|
|
5048
|
+
mergeability: options.mergeability,
|
|
5049
|
+
mergeStateStatus: options.mergeStateStatus
|
|
5050
|
+
} : getGitHubPullRequestCiSnapshot(octokit, repository, pullRequestNumber)
|
|
4917
5051
|
]);
|
|
4918
5052
|
return cacheGitHubPullRequestStatusSnapshot(repository, {
|
|
4919
5053
|
number: pullRequestNumber,
|
|
5054
|
+
repositoryUrl: repository.url,
|
|
4920
5055
|
hasUnresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads > 0,
|
|
4921
|
-
ciState
|
|
5056
|
+
ciState: ciSnapshot.ciState,
|
|
5057
|
+
mergeability: ciSnapshot.mergeability,
|
|
5058
|
+
mergeStateStatus: ciSnapshot.mergeStateStatus
|
|
4922
5059
|
});
|
|
4923
5060
|
})();
|
|
4924
5061
|
activeGitHubPullRequestStatusSnapshotPromiseCache.set(cacheKey, loadSnapshotPromise);
|
|
4925
5062
|
try {
|
|
4926
5063
|
const snapshot = await loadSnapshotPromise;
|
|
4927
|
-
pullRequestStatusCache
|
|
5064
|
+
setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot);
|
|
4928
5065
|
return snapshot;
|
|
4929
5066
|
} finally {
|
|
4930
5067
|
if (activeGitHubPullRequestStatusSnapshotPromiseCache.get(cacheKey) === loadSnapshotPromise) {
|
|
@@ -4957,8 +5094,14 @@ async function getGitHubIssueStatusSnapshot(octokit, repository, issueNumber, gi
|
|
|
4957
5094
|
if (pullRequest.state !== "OPEN") {
|
|
4958
5095
|
continue;
|
|
4959
5096
|
}
|
|
5097
|
+
const linkedPullRequestRepository = requireRepositoryReference(pullRequest.repositoryUrl);
|
|
4960
5098
|
linkedPullRequestSnapshots.push(
|
|
4961
|
-
await getGitHubPullRequestStatusSnapshot(
|
|
5099
|
+
await getGitHubPullRequestStatusSnapshot(
|
|
5100
|
+
octokit,
|
|
5101
|
+
linkedPullRequestRepository,
|
|
5102
|
+
pullRequest.number,
|
|
5103
|
+
pullRequestStatusCache
|
|
5104
|
+
)
|
|
4962
5105
|
);
|
|
4963
5106
|
}
|
|
4964
5107
|
const snapshot = {
|
|
@@ -5071,25 +5214,58 @@ async function listNewGitHubIssueCommentsSinceCount(octokit, repository, issueNu
|
|
|
5071
5214
|
}
|
|
5072
5215
|
return comments;
|
|
5073
5216
|
}
|
|
5074
|
-
async function
|
|
5075
|
-
const normalizedPreviousCommentCount =
|
|
5076
|
-
const normalizedCurrentCommentCount = Math.max(0, Math.floor(
|
|
5217
|
+
async function listNewGitHubPullRequestReviewCommentsSinceCount(octokit, repository, pullRequestNumber, previousCommentCount, currentCommentCount) {
|
|
5218
|
+
const normalizedPreviousCommentCount = Math.max(0, Math.floor(previousCommentCount));
|
|
5219
|
+
const normalizedCurrentCommentCount = Math.max(0, Math.floor(currentCommentCount));
|
|
5077
5220
|
if (normalizedCurrentCommentCount <= normalizedPreviousCommentCount) {
|
|
5078
|
-
return
|
|
5221
|
+
return [];
|
|
5079
5222
|
}
|
|
5080
|
-
const
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5223
|
+
const newCommentCount = normalizedCurrentCommentCount - normalizedPreviousCommentCount;
|
|
5224
|
+
const comments = [];
|
|
5225
|
+
const perPage = 100;
|
|
5226
|
+
let page = Math.floor(normalizedPreviousCommentCount / perPage) + 1;
|
|
5227
|
+
let remainingOffset = normalizedPreviousCommentCount % perPage;
|
|
5228
|
+
while (comments.length < newCommentCount) {
|
|
5229
|
+
const response = await octokit.rest.pulls.listReviewComments({
|
|
5230
|
+
owner: repository.owner,
|
|
5231
|
+
repo: repository.repo,
|
|
5232
|
+
pull_number: pullRequestNumber,
|
|
5233
|
+
page,
|
|
5234
|
+
per_page: perPage,
|
|
5235
|
+
headers: {
|
|
5236
|
+
accept: "application/vnd.github+json",
|
|
5237
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
5238
|
+
}
|
|
5239
|
+
});
|
|
5240
|
+
if (response.data.length === 0) {
|
|
5241
|
+
break;
|
|
5242
|
+
}
|
|
5243
|
+
for (const comment of response.data.slice(remainingOffset)) {
|
|
5244
|
+
comments.push({
|
|
5245
|
+
id: comment.id,
|
|
5246
|
+
body: typeof comment.body === "string" ? stripNullBytes(comment.body) : "",
|
|
5247
|
+
url: comment.html_url ?? void 0,
|
|
5248
|
+
authorLogin: normalizeGitHubUserLogin(comment.user?.login),
|
|
5249
|
+
...normalizeGitHubLowercaseString(comment.author_association) ? { authorAssociation: normalizeGitHubLowercaseString(comment.author_association) } : {},
|
|
5250
|
+
createdAt: comment.created_at ?? void 0,
|
|
5251
|
+
updatedAt: comment.updated_at ?? void 0
|
|
5252
|
+
});
|
|
5253
|
+
if (comments.length >= newCommentCount) {
|
|
5254
|
+
break;
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
if (response.data.length < perPage) {
|
|
5258
|
+
break;
|
|
5259
|
+
}
|
|
5260
|
+
page += 1;
|
|
5261
|
+
remainingOffset = 0;
|
|
5089
5262
|
}
|
|
5090
|
-
|
|
5263
|
+
return comments;
|
|
5264
|
+
}
|
|
5265
|
+
async function hasTrustedGitHubCommentRecords(params) {
|
|
5266
|
+
const originalPosterLogin = normalizeGitHubUserLogin(params.originalPosterLogin);
|
|
5091
5267
|
const unseenAuthors = /* @__PURE__ */ new Set();
|
|
5092
|
-
for (const comment of
|
|
5268
|
+
for (const comment of params.comments) {
|
|
5093
5269
|
const authorLogin = normalizeGitHubUserLogin(comment.authorLogin);
|
|
5094
5270
|
if (!authorLogin) {
|
|
5095
5271
|
continue;
|
|
@@ -5123,6 +5299,122 @@ async function hasTrustedNewGitHubIssueComment(params) {
|
|
|
5123
5299
|
}
|
|
5124
5300
|
return false;
|
|
5125
5301
|
}
|
|
5302
|
+
async function hasTrustedNewGitHubIssueComment(params) {
|
|
5303
|
+
const normalizedPreviousCommentCount = typeof params.previousCommentCount === "number" && params.previousCommentCount >= 0 ? Math.floor(params.previousCommentCount) : params.currentCommentCount;
|
|
5304
|
+
const normalizedCurrentCommentCount = Math.max(0, Math.floor(params.currentCommentCount));
|
|
5305
|
+
if (normalizedCurrentCommentCount <= normalizedPreviousCommentCount) {
|
|
5306
|
+
return false;
|
|
5307
|
+
}
|
|
5308
|
+
const newComments = await listNewGitHubIssueCommentsSinceCount(
|
|
5309
|
+
params.octokit,
|
|
5310
|
+
params.repository,
|
|
5311
|
+
params.githubIssue.number,
|
|
5312
|
+
normalizedPreviousCommentCount,
|
|
5313
|
+
normalizedCurrentCommentCount
|
|
5314
|
+
);
|
|
5315
|
+
if (newComments.length === 0) {
|
|
5316
|
+
return false;
|
|
5317
|
+
}
|
|
5318
|
+
return hasTrustedGitHubCommentRecords({
|
|
5319
|
+
octokit: params.octokit,
|
|
5320
|
+
repository: params.repository,
|
|
5321
|
+
comments: newComments,
|
|
5322
|
+
originalPosterLogin: params.githubIssue.authorLogin,
|
|
5323
|
+
maintainerCache: params.maintainerCache
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
5326
|
+
async function getGitHubPullRequestCommentCountRecord(octokit, repository, pullRequestNumber, cache) {
|
|
5327
|
+
const pullRequestReference = {
|
|
5328
|
+
number: pullRequestNumber,
|
|
5329
|
+
repositoryUrl: repository.url
|
|
5330
|
+
};
|
|
5331
|
+
const cacheKey = buildGitHubPullRequestReferenceKey(pullRequestReference);
|
|
5332
|
+
const cachedRecord = cache.get(cacheKey);
|
|
5333
|
+
if (cachedRecord) {
|
|
5334
|
+
return cachedRecord;
|
|
5335
|
+
}
|
|
5336
|
+
const response = await octokit.rest.pulls.get({
|
|
5337
|
+
owner: repository.owner,
|
|
5338
|
+
repo: repository.repo,
|
|
5339
|
+
pull_number: pullRequestNumber,
|
|
5340
|
+
headers: {
|
|
5341
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
5342
|
+
}
|
|
5343
|
+
});
|
|
5344
|
+
const record = {
|
|
5345
|
+
...pullRequestReference,
|
|
5346
|
+
topLevelCommentCount: typeof response.data.comments === "number" && response.data.comments >= 0 ? Math.floor(response.data.comments) : 0,
|
|
5347
|
+
reviewCommentCount: typeof response.data.review_comments === "number" && response.data.review_comments >= 0 ? Math.floor(response.data.review_comments) : 0
|
|
5348
|
+
};
|
|
5349
|
+
cache.set(cacheKey, record);
|
|
5350
|
+
return record;
|
|
5351
|
+
}
|
|
5352
|
+
async function listGitHubPullRequestCommentCountRecords(octokit, linkedPullRequests, cache) {
|
|
5353
|
+
const commentCounts = [];
|
|
5354
|
+
for (const pullRequest of linkedPullRequests) {
|
|
5355
|
+
commentCounts.push(
|
|
5356
|
+
await getGitHubPullRequestCommentCountRecord(
|
|
5357
|
+
octokit,
|
|
5358
|
+
requireRepositoryReference(pullRequest.repositoryUrl),
|
|
5359
|
+
pullRequest.number,
|
|
5360
|
+
cache
|
|
5361
|
+
)
|
|
5362
|
+
);
|
|
5363
|
+
}
|
|
5364
|
+
return normalizeGitHubPullRequestCommentCountRecords(commentCounts);
|
|
5365
|
+
}
|
|
5366
|
+
async function hasTrustedNewLinkedPullRequestComments(params) {
|
|
5367
|
+
if ((params.currentCommentCounts?.length ?? 0) === 0 || (params.previousCommentCounts?.length ?? 0) === 0) {
|
|
5368
|
+
return false;
|
|
5369
|
+
}
|
|
5370
|
+
const previousCommentCountsByKey = new Map(
|
|
5371
|
+
(params.previousCommentCounts ?? []).map((record) => [buildGitHubPullRequestReferenceKey(record), record])
|
|
5372
|
+
);
|
|
5373
|
+
for (const currentCommentCount of params.currentCommentCounts) {
|
|
5374
|
+
const previousCommentCount = previousCommentCountsByKey.get(buildGitHubPullRequestReferenceKey(currentCommentCount));
|
|
5375
|
+
if (!previousCommentCount) {
|
|
5376
|
+
continue;
|
|
5377
|
+
}
|
|
5378
|
+
const pullRequestRepository = requireRepositoryReference(currentCommentCount.repositoryUrl);
|
|
5379
|
+
if (currentCommentCount.topLevelCommentCount > previousCommentCount.topLevelCommentCount) {
|
|
5380
|
+
const newTopLevelComments = await listNewGitHubIssueCommentsSinceCount(
|
|
5381
|
+
params.octokit,
|
|
5382
|
+
pullRequestRepository,
|
|
5383
|
+
currentCommentCount.number,
|
|
5384
|
+
previousCommentCount.topLevelCommentCount,
|
|
5385
|
+
currentCommentCount.topLevelCommentCount
|
|
5386
|
+
);
|
|
5387
|
+
if (await hasTrustedGitHubCommentRecords({
|
|
5388
|
+
octokit: params.octokit,
|
|
5389
|
+
repository: pullRequestRepository,
|
|
5390
|
+
comments: newTopLevelComments,
|
|
5391
|
+
originalPosterLogin: params.githubIssue.authorLogin,
|
|
5392
|
+
maintainerCache: params.maintainerCache
|
|
5393
|
+
})) {
|
|
5394
|
+
return true;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
if (currentCommentCount.reviewCommentCount > previousCommentCount.reviewCommentCount) {
|
|
5398
|
+
const newReviewComments = await listNewGitHubPullRequestReviewCommentsSinceCount(
|
|
5399
|
+
params.octokit,
|
|
5400
|
+
pullRequestRepository,
|
|
5401
|
+
currentCommentCount.number,
|
|
5402
|
+
previousCommentCount.reviewCommentCount,
|
|
5403
|
+
currentCommentCount.reviewCommentCount
|
|
5404
|
+
);
|
|
5405
|
+
if (await hasTrustedGitHubCommentRecords({
|
|
5406
|
+
octokit: params.octokit,
|
|
5407
|
+
repository: pullRequestRepository,
|
|
5408
|
+
comments: newReviewComments,
|
|
5409
|
+
originalPosterLogin: params.githubIssue.authorLogin,
|
|
5410
|
+
maintainerCache: params.maintainerCache
|
|
5411
|
+
})) {
|
|
5412
|
+
return true;
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
}
|
|
5416
|
+
return false;
|
|
5417
|
+
}
|
|
5126
5418
|
async function isMaintainerAuthoredGitHubIssue(params) {
|
|
5127
5419
|
const authorLogin = normalizeGitHubUserLogin(params.githubIssue.authorLogin);
|
|
5128
5420
|
if (!authorLogin) {
|
|
@@ -5212,11 +5504,121 @@ function getHiddenGitHubImportMarkerPattern() {
|
|
|
5212
5504
|
"i"
|
|
5213
5505
|
);
|
|
5214
5506
|
}
|
|
5507
|
+
function formatPlainTextList(items) {
|
|
5508
|
+
if (items.length === 0) {
|
|
5509
|
+
return "";
|
|
5510
|
+
}
|
|
5511
|
+
if (items.length === 1) {
|
|
5512
|
+
return items[0];
|
|
5513
|
+
}
|
|
5514
|
+
if (items.length === 2) {
|
|
5515
|
+
return `${items[0]} and ${items[1]}`;
|
|
5516
|
+
}
|
|
5517
|
+
return `${items.slice(0, -1).join(", ")}, and ${items.at(-1)}`;
|
|
5518
|
+
}
|
|
5215
5519
|
function normalizeLinkedPullRequestNumbers(values) {
|
|
5216
5520
|
return [...new Set(
|
|
5217
5521
|
values.filter((pullRequestNumber) => Number.isInteger(pullRequestNumber) && pullRequestNumber > 0)
|
|
5218
5522
|
)].sort((left, right) => left - right);
|
|
5219
5523
|
}
|
|
5524
|
+
function buildGitHubPullRequestReferenceKey(pullRequest) {
|
|
5525
|
+
return `${getNormalizedMappingRepositoryUrl({ repositoryUrl: pullRequest.repositoryUrl }).toLowerCase()}#${Math.max(1, Math.floor(pullRequest.number))}`;
|
|
5526
|
+
}
|
|
5527
|
+
function normalizeGitHubPullRequestCommentCountRecords(value) {
|
|
5528
|
+
if (!Array.isArray(value)) {
|
|
5529
|
+
return [];
|
|
5530
|
+
}
|
|
5531
|
+
const recordsByKey = /* @__PURE__ */ new Map();
|
|
5532
|
+
for (const entry of value) {
|
|
5533
|
+
if (!entry || typeof entry !== "object") {
|
|
5534
|
+
continue;
|
|
5535
|
+
}
|
|
5536
|
+
const record = entry;
|
|
5537
|
+
const pullRequestNumber = typeof record.number === "number" && Number.isInteger(record.number) && record.number > 0 ? Math.floor(record.number) : void 0;
|
|
5538
|
+
const repositoryUrl = typeof record.repositoryUrl === "string" && record.repositoryUrl.trim() ? getNormalizedMappingRepositoryUrl({
|
|
5539
|
+
repositoryUrl: record.repositoryUrl
|
|
5540
|
+
}) : void 0;
|
|
5541
|
+
const topLevelCommentCount = typeof record.topLevelCommentCount === "number" && record.topLevelCommentCount >= 0 ? Math.floor(record.topLevelCommentCount) : void 0;
|
|
5542
|
+
const reviewCommentCount = typeof record.reviewCommentCount === "number" && record.reviewCommentCount >= 0 ? Math.floor(record.reviewCommentCount) : void 0;
|
|
5543
|
+
if (pullRequestNumber === void 0 || !repositoryUrl || topLevelCommentCount === void 0 || reviewCommentCount === void 0) {
|
|
5544
|
+
continue;
|
|
5545
|
+
}
|
|
5546
|
+
const normalizedRecord = {
|
|
5547
|
+
number: pullRequestNumber,
|
|
5548
|
+
repositoryUrl,
|
|
5549
|
+
topLevelCommentCount,
|
|
5550
|
+
reviewCommentCount
|
|
5551
|
+
};
|
|
5552
|
+
recordsByKey.set(buildGitHubPullRequestReferenceKey(normalizedRecord), normalizedRecord);
|
|
5553
|
+
}
|
|
5554
|
+
return [...recordsByKey.values()].sort((left, right) => {
|
|
5555
|
+
const repositoryComparison = left.repositoryUrl.toLowerCase().localeCompare(right.repositoryUrl.toLowerCase());
|
|
5556
|
+
if (repositoryComparison !== 0) {
|
|
5557
|
+
return repositoryComparison;
|
|
5558
|
+
}
|
|
5559
|
+
return left.number - right.number;
|
|
5560
|
+
});
|
|
5561
|
+
}
|
|
5562
|
+
function normalizeLinkedPullRequestReferences(values, fallbackRepositoryUrl) {
|
|
5563
|
+
const references = [];
|
|
5564
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
5565
|
+
const normalizedFallbackRepositoryUrl = typeof fallbackRepositoryUrl === "string" && fallbackRepositoryUrl.trim() ? getNormalizedMappingRepositoryUrl({
|
|
5566
|
+
repositoryUrl: fallbackRepositoryUrl
|
|
5567
|
+
}) : void 0;
|
|
5568
|
+
for (const value of values) {
|
|
5569
|
+
const number = typeof value === "number" ? Math.floor(value) : value && typeof value === "object" && typeof value.number === "number" ? Math.floor(value.number) : void 0;
|
|
5570
|
+
const repositoryUrl = value && typeof value === "object" && typeof value.repositoryUrl === "string" && value.repositoryUrl.trim() ? getNormalizedMappingRepositoryUrl({
|
|
5571
|
+
repositoryUrl: value.repositoryUrl
|
|
5572
|
+
}) : normalizedFallbackRepositoryUrl;
|
|
5573
|
+
if (!number || number < 1 || !repositoryUrl) {
|
|
5574
|
+
continue;
|
|
5575
|
+
}
|
|
5576
|
+
const referenceKey = buildGitHubPullRequestReferenceKey({
|
|
5577
|
+
number,
|
|
5578
|
+
repositoryUrl
|
|
5579
|
+
});
|
|
5580
|
+
if (seenKeys.has(referenceKey)) {
|
|
5581
|
+
continue;
|
|
5582
|
+
}
|
|
5583
|
+
seenKeys.add(referenceKey);
|
|
5584
|
+
references.push({
|
|
5585
|
+
number,
|
|
5586
|
+
repositoryUrl
|
|
5587
|
+
});
|
|
5588
|
+
}
|
|
5589
|
+
references.sort((left, right) => {
|
|
5590
|
+
const repositoryUrlComparison = left.repositoryUrl.toLowerCase().localeCompare(right.repositoryUrl.toLowerCase());
|
|
5591
|
+
if (repositoryUrlComparison !== 0) {
|
|
5592
|
+
return repositoryUrlComparison;
|
|
5593
|
+
}
|
|
5594
|
+
return left.number - right.number;
|
|
5595
|
+
});
|
|
5596
|
+
return references;
|
|
5597
|
+
}
|
|
5598
|
+
function formatLinkedPullRequestReferenceLabel(pullRequest, issueRepositoryUrl) {
|
|
5599
|
+
const pullRequestRepository = parseRepositoryReference(pullRequest.repositoryUrl);
|
|
5600
|
+
if (!pullRequestRepository) {
|
|
5601
|
+
return `PR #${pullRequest.number}`;
|
|
5602
|
+
}
|
|
5603
|
+
if (issueRepositoryUrl) {
|
|
5604
|
+
const issueRepository = parseRepositoryReference(issueRepositoryUrl);
|
|
5605
|
+
if (issueRepository && areRepositoriesEqual(issueRepository, pullRequestRepository)) {
|
|
5606
|
+
return `PR #${pullRequest.number}`;
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
return `${formatRepositoryLabel(pullRequestRepository)}#${pullRequest.number}`;
|
|
5610
|
+
}
|
|
5611
|
+
function getCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, repository, pullRequestNumber) {
|
|
5612
|
+
return pullRequestStatusCache.get(
|
|
5613
|
+
buildGitHubPullRequestReferenceKey({
|
|
5614
|
+
number: pullRequestNumber,
|
|
5615
|
+
repositoryUrl: repository.url
|
|
5616
|
+
})
|
|
5617
|
+
);
|
|
5618
|
+
}
|
|
5619
|
+
function setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot) {
|
|
5620
|
+
pullRequestStatusCache.set(buildGitHubPullRequestReferenceKey(snapshot), snapshot);
|
|
5621
|
+
}
|
|
5220
5622
|
function extractImportedGitHubIssueUrlFromDescription(description) {
|
|
5221
5623
|
if (typeof description !== "string") {
|
|
5222
5624
|
return void 0;
|
|
@@ -5442,6 +5844,14 @@ function normalizeGitHubIssueLinkEntityData(value) {
|
|
|
5442
5844
|
if (!repositoryUrl || githubIssueId === void 0 || githubIssueNumber === void 0 || !githubIssueUrl || !githubIssueState || !syncedAt) {
|
|
5443
5845
|
return null;
|
|
5444
5846
|
}
|
|
5847
|
+
const linkedPullRequestNumbers = normalizeLinkedPullRequestNumbers(
|
|
5848
|
+
Array.isArray(record.linkedPullRequestNumbers) ? record.linkedPullRequestNumbers.filter((entry) => typeof entry === "number") : []
|
|
5849
|
+
);
|
|
5850
|
+
const rawLinkedPullRequests = Array.isArray(record.linkedPullRequests) ? record.linkedPullRequests : [];
|
|
5851
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(
|
|
5852
|
+
rawLinkedPullRequests.length > 0 ? rawLinkedPullRequests : linkedPullRequestNumbers,
|
|
5853
|
+
repositoryUrl
|
|
5854
|
+
);
|
|
5445
5855
|
return {
|
|
5446
5856
|
...typeof record.companyId === "string" && record.companyId.trim() ? { companyId: record.companyId.trim() } : {},
|
|
5447
5857
|
...typeof record.paperclipProjectId === "string" && record.paperclipProjectId.trim() ? { paperclipProjectId: record.paperclipProjectId.trim() } : {},
|
|
@@ -5455,9 +5865,8 @@ function normalizeGitHubIssueLinkEntityData(value) {
|
|
|
5455
5865
|
githubIssueState,
|
|
5456
5866
|
...githubIssueStateReason ? { githubIssueStateReason } : {},
|
|
5457
5867
|
commentsCount,
|
|
5458
|
-
linkedPullRequestNumbers
|
|
5459
|
-
|
|
5460
|
-
),
|
|
5868
|
+
linkedPullRequestNumbers,
|
|
5869
|
+
linkedPullRequests,
|
|
5461
5870
|
labels: normalizeStoredGitHubIssueLabels(record.labels),
|
|
5462
5871
|
syncedAt
|
|
5463
5872
|
};
|
|
@@ -5507,15 +5916,22 @@ function normalizeStoredStatusTransitionCommentAnnotation(value) {
|
|
|
5507
5916
|
if (!repositoryUrl || githubIssueNumber === void 0 || !githubIssueUrl || !previousStatus || !nextStatus || !reason || !createdAt || !paperclipIssueId) {
|
|
5508
5917
|
return null;
|
|
5509
5918
|
}
|
|
5919
|
+
const linkedPullRequestNumbers = normalizeLinkedPullRequestNumbers(
|
|
5920
|
+
Array.isArray(record.linkedPullRequestNumbers) ? record.linkedPullRequestNumbers.filter((entry) => typeof entry === "number") : []
|
|
5921
|
+
);
|
|
5922
|
+
const rawLinkedPullRequests = Array.isArray(record.linkedPullRequests) ? record.linkedPullRequests : [];
|
|
5923
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(
|
|
5924
|
+
rawLinkedPullRequests.length > 0 ? rawLinkedPullRequests : linkedPullRequestNumbers,
|
|
5925
|
+
repositoryUrl
|
|
5926
|
+
);
|
|
5510
5927
|
return {
|
|
5511
5928
|
...typeof record.companyId === "string" && record.companyId.trim() ? { companyId: record.companyId.trim() } : {},
|
|
5512
5929
|
paperclipIssueId,
|
|
5513
5930
|
repositoryUrl,
|
|
5514
5931
|
githubIssueNumber,
|
|
5515
5932
|
githubIssueUrl,
|
|
5516
|
-
linkedPullRequestNumbers
|
|
5517
|
-
|
|
5518
|
-
),
|
|
5933
|
+
linkedPullRequestNumbers,
|
|
5934
|
+
linkedPullRequests,
|
|
5519
5935
|
previousStatus,
|
|
5520
5936
|
nextStatus,
|
|
5521
5937
|
reason,
|
|
@@ -5642,9 +6058,10 @@ async function findStoredStatusTransitionCommentAnnotation(ctx, params) {
|
|
|
5642
6058
|
}
|
|
5643
6059
|
return null;
|
|
5644
6060
|
}
|
|
5645
|
-
function buildGitHubIssueLinkRecord(target, issueId, githubIssue,
|
|
6061
|
+
function buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequests) {
|
|
5646
6062
|
const githubIssueUrl = normalizeGitHubIssueHtmlUrl(githubIssue.htmlUrl) ?? githubIssue.htmlUrl;
|
|
5647
6063
|
const repositoryUrl = parseRepositoryReference(target.repositoryUrl)?.url ?? target.repositoryUrl.trim();
|
|
6064
|
+
const normalizedLinkedPullRequests = normalizeLinkedPullRequestReferences(linkedPullRequests, repositoryUrl);
|
|
5648
6065
|
return {
|
|
5649
6066
|
paperclipIssueId: issueId,
|
|
5650
6067
|
title: `GitHub issue #${githubIssue.number}`,
|
|
@@ -5662,14 +6079,17 @@ function buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequ
|
|
|
5662
6079
|
githubIssueState: githubIssue.state,
|
|
5663
6080
|
...githubIssue.stateReason ? { githubIssueStateReason: githubIssue.stateReason } : {},
|
|
5664
6081
|
commentsCount: githubIssue.commentsCount,
|
|
5665
|
-
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
6082
|
+
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
6083
|
+
normalizedLinkedPullRequests.map((pullRequest) => pullRequest.number)
|
|
6084
|
+
),
|
|
6085
|
+
linkedPullRequests: normalizedLinkedPullRequests,
|
|
5666
6086
|
labels: githubIssue.labels,
|
|
5667
6087
|
syncedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5668
6088
|
}
|
|
5669
6089
|
};
|
|
5670
6090
|
}
|
|
5671
|
-
async function upsertGitHubIssueLinkRecord(ctx, target, issueId, githubIssue,
|
|
5672
|
-
const record = buildGitHubIssueLinkRecord(target, issueId, githubIssue,
|
|
6091
|
+
async function upsertGitHubIssueLinkRecord(ctx, target, issueId, githubIssue, linkedPullRequests) {
|
|
6092
|
+
const record = buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequests);
|
|
5673
6093
|
await ctx.entities.upsert({
|
|
5674
6094
|
entityType: ISSUE_LINK_ENTITY_TYPE,
|
|
5675
6095
|
scopeKind: "issue",
|
|
@@ -6580,14 +7000,22 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6580
7000
|
syncContext,
|
|
6581
7001
|
nextStatus,
|
|
6582
7002
|
nextAssignee,
|
|
7003
|
+
clearAssignee,
|
|
6583
7004
|
transitionComment,
|
|
6584
7005
|
transitionCommentAnnotation,
|
|
6585
7006
|
paperclipApiBaseUrl
|
|
6586
7007
|
} = params;
|
|
6587
7008
|
const trimmedTransitionComment = transitionComment.trim();
|
|
6588
7009
|
let issueUpdated = false;
|
|
7010
|
+
const syncExecutionStatePatch = buildSyncFallbackExecutionStatePatch({
|
|
7011
|
+
currentStatus,
|
|
7012
|
+
nextStatus,
|
|
7013
|
+
syncContext,
|
|
7014
|
+
nextAssignee
|
|
7015
|
+
});
|
|
6589
7016
|
const issuePatch = {
|
|
6590
|
-
status: nextStatus
|
|
7017
|
+
status: nextStatus,
|
|
7018
|
+
...syncExecutionStatePatch === null ? { executionState: null } : {}
|
|
6591
7019
|
};
|
|
6592
7020
|
if (nextAssignee) {
|
|
6593
7021
|
if (nextAssignee.kind === "agent") {
|
|
@@ -6597,6 +7025,9 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6597
7025
|
issuePatch.assigneeAgentId = null;
|
|
6598
7026
|
issuePatch.assigneeUserId = nextAssignee.id;
|
|
6599
7027
|
}
|
|
7028
|
+
} else if (clearAssignee) {
|
|
7029
|
+
issuePatch.assigneeAgentId = null;
|
|
7030
|
+
issuePatch.assigneeUserId = null;
|
|
6600
7031
|
}
|
|
6601
7032
|
if (paperclipApiBaseUrl) {
|
|
6602
7033
|
try {
|
|
@@ -6642,16 +7073,10 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6642
7073
|
}
|
|
6643
7074
|
}
|
|
6644
7075
|
if (!issueUpdated) {
|
|
6645
|
-
const fallbackExecutionStatePatch = buildSyncFallbackExecutionStatePatch({
|
|
6646
|
-
currentStatus,
|
|
6647
|
-
nextStatus,
|
|
6648
|
-
syncContext,
|
|
6649
|
-
nextAssignee
|
|
6650
|
-
});
|
|
6651
7076
|
const preserveExistingUserAssigneeWithoutLocalApi = nextAssignee?.kind === "user" && !paperclipApiBaseUrl;
|
|
6652
7077
|
const sdkIssuePatch = {
|
|
6653
7078
|
...issuePatch,
|
|
6654
|
-
...
|
|
7079
|
+
...syncExecutionStatePatch !== void 0 ? { executionState: syncExecutionStatePatch } : {}
|
|
6655
7080
|
};
|
|
6656
7081
|
if (preserveExistingUserAssigneeWithoutLocalApi) {
|
|
6657
7082
|
delete sdkIssuePatch.assigneeAgentId;
|
|
@@ -6931,6 +7356,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
6931
7356
|
let completedIssueCount = 0;
|
|
6932
7357
|
const totalIssueCount = importedIssues.length;
|
|
6933
7358
|
const queuedIssueWakeups = [];
|
|
7359
|
+
const pullRequestCommentCountCache = /* @__PURE__ */ new Map();
|
|
6934
7360
|
for (const importedIssue of importedIssues) {
|
|
6935
7361
|
if (assertNotCancelled) {
|
|
6936
7362
|
await assertNotCancelled();
|
|
@@ -7034,11 +7460,11 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7034
7460
|
stateReason: snapshot.stateReason,
|
|
7035
7461
|
commentsCount: snapshot.commentCount
|
|
7036
7462
|
},
|
|
7037
|
-
|
|
7463
|
+
snapshot.linkedPullRequests
|
|
7038
7464
|
);
|
|
7039
7465
|
const previousCommentCount = importedIssue.lastSeenCommentCount;
|
|
7040
|
-
const
|
|
7041
|
-
const
|
|
7466
|
+
const hasNewIssueComments = snapshot.commentCount > (previousCommentCount ?? snapshot.commentCount);
|
|
7467
|
+
const hasTrustedNewIssueComment = paperclipIssue.status === "backlog" || !hasNewIssueComments ? false : await hasTrustedNewGitHubIssueComment({
|
|
7042
7468
|
octokit,
|
|
7043
7469
|
repository,
|
|
7044
7470
|
githubIssue,
|
|
@@ -7046,6 +7472,28 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7046
7472
|
currentCommentCount: snapshot.commentCount,
|
|
7047
7473
|
maintainerCache: repositoryMaintainerCache
|
|
7048
7474
|
});
|
|
7475
|
+
let currentLinkedPullRequestCommentCounts = snapshot.linkedPullRequests.length === 0 ? [] : importedIssue.linkedPullRequestCommentCounts ?? [];
|
|
7476
|
+
if (snapshot.linkedPullRequests.length > 0) {
|
|
7477
|
+
try {
|
|
7478
|
+
currentLinkedPullRequestCommentCounts = await listGitHubPullRequestCommentCountRecords(
|
|
7479
|
+
octokit,
|
|
7480
|
+
snapshot.linkedPullRequests,
|
|
7481
|
+
pullRequestCommentCountCache
|
|
7482
|
+
);
|
|
7483
|
+
} catch (error) {
|
|
7484
|
+
if (isGitHubRateLimitError(error)) {
|
|
7485
|
+
throw error;
|
|
7486
|
+
}
|
|
7487
|
+
}
|
|
7488
|
+
}
|
|
7489
|
+
const hasTrustedNewLinkedPullRequestComment = paperclipIssue.status === "backlog" || currentLinkedPullRequestCommentCounts.length === 0 ? false : await hasTrustedNewLinkedPullRequestComments({
|
|
7490
|
+
octokit,
|
|
7491
|
+
githubIssue,
|
|
7492
|
+
previousCommentCounts: importedIssue.linkedPullRequestCommentCounts,
|
|
7493
|
+
currentCommentCounts: currentLinkedPullRequestCommentCounts,
|
|
7494
|
+
maintainerCache: repositoryMaintainerCache
|
|
7495
|
+
});
|
|
7496
|
+
const hasTrustedNewComment = hasTrustedNewIssueComment || hasTrustedNewLinkedPullRequestComment;
|
|
7049
7497
|
const wasImportedThisRun = createdIssueIds.has(importedIssue.githubIssueId);
|
|
7050
7498
|
const maintainerAuthoredImportedIssue = wasImportedThisRun && advancedSettings.defaultStatus !== "todo" && snapshot.state === "open" && snapshot.linkedPullRequests.length === 0 ? await isMaintainerAuthoredGitHubIssue({
|
|
7051
7499
|
octokit,
|
|
@@ -7061,7 +7509,6 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7061
7509
|
const nextStatus = resolvePaperclipIssueStatus({
|
|
7062
7510
|
currentStatus: paperclipIssue.status,
|
|
7063
7511
|
snapshot,
|
|
7064
|
-
previousCommentCount,
|
|
7065
7512
|
hasTrustedNewComment,
|
|
7066
7513
|
wasImportedThisRun,
|
|
7067
7514
|
defaultImportedStatus: advancedSettings.defaultStatus,
|
|
@@ -7073,12 +7520,31 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7073
7520
|
syncContext: paperclipIssueSyncContext,
|
|
7074
7521
|
advancedSettings
|
|
7075
7522
|
});
|
|
7523
|
+
const shouldClearTransitionAssignee = nextStatus === "in_review" && nextTransitionAssignee === null && paperclipIssueSyncContext.assignee !== null;
|
|
7076
7524
|
const nextAssigneeChanged = nextTransitionAssignee ? !doesPaperclipIssueAssigneeMatch(paperclipIssueSyncContext.assignee, nextTransitionAssignee.principal) : false;
|
|
7077
7525
|
const shouldWakeImportedAssignee = wasImportedThisRun && paperclipIssue.status === nextStatus && nextStatus === "todo" && paperclipIssueSyncContext.assignee?.kind === "agent";
|
|
7078
7526
|
const shouldWakeTransitionAssignee = paperclipIssue.status !== nextStatus && nextTransitionAssignee?.principal.kind === "agent" && isActionablePaperclipIssueStatus(nextStatus) && (nextAssigneeChanged || paperclipIssue.status !== nextStatus);
|
|
7079
7527
|
importedIssue.githubIssueNumber = githubIssue.number;
|
|
7080
7528
|
importedIssue.lastSeenCommentCount = snapshot.commentCount;
|
|
7529
|
+
importedIssue.linkedPullRequestCommentCounts = currentLinkedPullRequestCommentCounts;
|
|
7081
7530
|
if (paperclipIssue.status === nextStatus) {
|
|
7531
|
+
if (shouldClearTransitionAssignee) {
|
|
7532
|
+
updateSyncFailureContext(syncFailureContext, {
|
|
7533
|
+
phase: "updating_paperclip_status",
|
|
7534
|
+
repositoryUrl: repository.url,
|
|
7535
|
+
githubIssueNumber: githubIssue.number
|
|
7536
|
+
});
|
|
7537
|
+
await updatePaperclipIssueState(ctx, {
|
|
7538
|
+
companyId: mapping.companyId,
|
|
7539
|
+
issueId: importedIssue.paperclipIssueId,
|
|
7540
|
+
currentStatus: paperclipIssue.status,
|
|
7541
|
+
syncContext: paperclipIssueSyncContext,
|
|
7542
|
+
nextStatus,
|
|
7543
|
+
clearAssignee: true,
|
|
7544
|
+
transitionComment: "",
|
|
7545
|
+
paperclipApiBaseUrl
|
|
7546
|
+
});
|
|
7547
|
+
}
|
|
7082
7548
|
if (shouldWakeImportedAssignee) {
|
|
7083
7549
|
queuedIssueWakeups.push({
|
|
7084
7550
|
assigneeAgentId: paperclipIssueSyncContext.assignee?.kind === "agent" ? paperclipIssueSyncContext.assignee.id : null,
|
|
@@ -7094,7 +7560,6 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7094
7560
|
nextStatus,
|
|
7095
7561
|
repository,
|
|
7096
7562
|
snapshot,
|
|
7097
|
-
previousCommentCount,
|
|
7098
7563
|
hasTrustedNewComment,
|
|
7099
7564
|
maintainerAuthoredImportedIssue
|
|
7100
7565
|
});
|
|
@@ -7110,6 +7575,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7110
7575
|
syncContext: paperclipIssueSyncContext,
|
|
7111
7576
|
nextStatus,
|
|
7112
7577
|
...nextTransitionAssignee ? { nextAssignee: nextTransitionAssignee.principal } : {},
|
|
7578
|
+
...shouldClearTransitionAssignee ? { clearAssignee: true } : {},
|
|
7113
7579
|
transitionComment: transitionComment.body,
|
|
7114
7580
|
transitionCommentAnnotation: transitionComment.annotation,
|
|
7115
7581
|
paperclipApiBaseUrl
|
|
@@ -7672,23 +8138,73 @@ async function resolveGitHubPullRequestToolTarget(ctx, runCtx, input) {
|
|
|
7672
8138
|
if (!link) {
|
|
7673
8139
|
throw new Error("This Paperclip issue is not linked to GitHub yet.");
|
|
7674
8140
|
}
|
|
7675
|
-
const repository2 = assertExplicitRepositoryMatchesLinkedRepository(
|
|
7676
|
-
input.repository,
|
|
7677
|
-
link.repositoryUrl,
|
|
7678
|
-
"repository must match the GitHub repository linked to the provided Paperclip issue."
|
|
7679
|
-
);
|
|
7680
8141
|
const explicitPullRequestNumber = normalizeToolPositiveInteger(input.pullRequestNumber);
|
|
8142
|
+
const linkedPullRequests = link.linkedPullRequests.length > 0 ? link.linkedPullRequests : normalizeLinkedPullRequestReferences(link.linkedPullRequestNumbers, link.repositoryUrl);
|
|
7681
8143
|
if (explicitPullRequestNumber !== void 0) {
|
|
8144
|
+
const explicitRepository = normalizeOptionalToolString(input.repository);
|
|
8145
|
+
const matchingLinkedPullRequests = linkedPullRequests.filter(
|
|
8146
|
+
(pullRequest) => pullRequest.number === explicitPullRequestNumber
|
|
8147
|
+
);
|
|
8148
|
+
if (explicitRepository) {
|
|
8149
|
+
const requestedRepository = requireRepositoryReference(explicitRepository);
|
|
8150
|
+
if (matchingLinkedPullRequests.length > 0) {
|
|
8151
|
+
const matchingLinkedPullRequest = matchingLinkedPullRequests.find(
|
|
8152
|
+
(pullRequest) => areRepositoriesEqual(requestedRepository, requireRepositoryReference(pullRequest.repositoryUrl))
|
|
8153
|
+
);
|
|
8154
|
+
if (!matchingLinkedPullRequest) {
|
|
8155
|
+
const linkedIssueRepository = requireRepositoryReference(link.repositoryUrl);
|
|
8156
|
+
const allMatchingPullRequestsUseIssueRepository = matchingLinkedPullRequests.every(
|
|
8157
|
+
(pullRequest) => areRepositoriesEqual(linkedIssueRepository, requireRepositoryReference(pullRequest.repositoryUrl))
|
|
8158
|
+
);
|
|
8159
|
+
throw new Error(
|
|
8160
|
+
allMatchingPullRequestsUseIssueRepository ? "repository must match the GitHub repository linked to the provided Paperclip issue." : "repository must match the GitHub repository for the selected linked pull request."
|
|
8161
|
+
);
|
|
8162
|
+
}
|
|
8163
|
+
return {
|
|
8164
|
+
repository: requestedRepository,
|
|
8165
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
8166
|
+
paperclipIssueId
|
|
8167
|
+
};
|
|
8168
|
+
}
|
|
8169
|
+
const repository2 = assertExplicitRepositoryMatchesLinkedRepository(
|
|
8170
|
+
input.repository,
|
|
8171
|
+
link.repositoryUrl,
|
|
8172
|
+
"repository must match the GitHub repository linked to the provided Paperclip issue."
|
|
8173
|
+
);
|
|
8174
|
+
return {
|
|
8175
|
+
repository: repository2,
|
|
8176
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
8177
|
+
paperclipIssueId
|
|
8178
|
+
};
|
|
8179
|
+
}
|
|
8180
|
+
if (matchingLinkedPullRequests.length === 1) {
|
|
8181
|
+
return {
|
|
8182
|
+
repository: requireRepositoryReference(matchingLinkedPullRequests[0].repositoryUrl),
|
|
8183
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
8184
|
+
paperclipIssueId
|
|
8185
|
+
};
|
|
8186
|
+
}
|
|
8187
|
+
if (matchingLinkedPullRequests.length > 1) {
|
|
8188
|
+
throw new Error("repository is required because the linked Paperclip issue has matching pull request numbers in multiple repositories.");
|
|
8189
|
+
}
|
|
7682
8190
|
return {
|
|
7683
|
-
repository:
|
|
8191
|
+
repository: requireRepositoryReference(link.repositoryUrl),
|
|
7684
8192
|
pullRequestNumber: explicitPullRequestNumber,
|
|
7685
8193
|
paperclipIssueId
|
|
7686
8194
|
};
|
|
7687
8195
|
}
|
|
7688
|
-
if (
|
|
8196
|
+
if (linkedPullRequests.length === 1) {
|
|
8197
|
+
const inferredPullRequest = linkedPullRequests[0];
|
|
8198
|
+
const explicitRepository = normalizeOptionalToolString(input.repository);
|
|
8199
|
+
if (explicitRepository) {
|
|
8200
|
+
const requestedRepository = requireRepositoryReference(explicitRepository);
|
|
8201
|
+
if (!areRepositoriesEqual(requestedRepository, requireRepositoryReference(inferredPullRequest.repositoryUrl))) {
|
|
8202
|
+
throw new Error("repository must match the GitHub repository for the selected linked pull request.");
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
7689
8205
|
return {
|
|
7690
|
-
repository:
|
|
7691
|
-
pullRequestNumber:
|
|
8206
|
+
repository: requireRepositoryReference(inferredPullRequest.repositoryUrl),
|
|
8207
|
+
pullRequestNumber: inferredPullRequest.number,
|
|
7692
8208
|
paperclipIssueId
|
|
7693
8209
|
};
|
|
7694
8210
|
}
|
|
@@ -8437,7 +8953,7 @@ function getProjectPullRequestStatus(state) {
|
|
|
8437
8953
|
return "open";
|
|
8438
8954
|
}
|
|
8439
8955
|
}
|
|
8440
|
-
async function buildProjectPullRequestSummaryRecord(octokit, repository, node, issueLookup, pullRequestStatusCache) {
|
|
8956
|
+
async function buildProjectPullRequestSummaryRecord(octokit, repository, node, issueLookup, pullRequestStatusCache, defaultBranchName) {
|
|
8441
8957
|
if (!node || typeof node.number !== "number" || !node.url || !node.title?.trim()) {
|
|
8442
8958
|
return null;
|
|
8443
8959
|
}
|
|
@@ -8446,6 +8962,8 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8446
8962
|
const inlineCiState = tryBuildGitHubPullRequestCiStateFromBatchNode({
|
|
8447
8963
|
statusCheckRollup: node.statusCheckRollup
|
|
8448
8964
|
});
|
|
8965
|
+
const inlineMergeability = normalizeGitHubPullRequestMergeability(node.mergeable);
|
|
8966
|
+
const inlineMergeStateStatus = normalizeGitHubPullRequestMergeStateStatus(node.mergeStateStatus);
|
|
8449
8967
|
const [reviewThreadSummary, reviewSummary, statusSnapshot, behindBy] = await Promise.all([
|
|
8450
8968
|
getOrLoadCachedGitHubPullRequestReviewThreadSummary(
|
|
8451
8969
|
octokit,
|
|
@@ -8461,7 +8979,9 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8461
8979
|
),
|
|
8462
8980
|
getGitHubPullRequestStatusSnapshot(octokit, repository, node.number, pullRequestStatusCache, {
|
|
8463
8981
|
reviewThreadSummary: inlineReviewThreadSummary,
|
|
8464
|
-
ciState: inlineCiState
|
|
8982
|
+
ciState: inlineCiState,
|
|
8983
|
+
mergeability: inlineMergeability,
|
|
8984
|
+
mergeStateStatus: inlineMergeStateStatus
|
|
8465
8985
|
}),
|
|
8466
8986
|
getGitHubPullRequestBehindCount(octokit, repository, {
|
|
8467
8987
|
baseBranch: node.baseRefName,
|
|
@@ -8486,8 +9006,11 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8486
9006
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
8487
9007
|
checksStatus,
|
|
8488
9008
|
reviewApprovals: reviewSummary.approvals,
|
|
9009
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
8489
9010
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
8490
|
-
githubMergeable
|
|
9011
|
+
githubMergeable,
|
|
9012
|
+
baseBranch: node.baseRefName,
|
|
9013
|
+
defaultBranchName
|
|
8491
9014
|
});
|
|
8492
9015
|
const upToDateStatus = resolveProjectPullRequestUpToDateStatus({
|
|
8493
9016
|
mergeStateStatus: node.mergeStateStatus,
|
|
@@ -8562,7 +9085,8 @@ async function listProjectPullRequestSummaryRecords(ctx, octokit, scope, options
|
|
|
8562
9085
|
scope.repository,
|
|
8563
9086
|
node,
|
|
8564
9087
|
issueLookup,
|
|
8565
|
-
pullRequestStatusCache
|
|
9088
|
+
pullRequestStatusCache,
|
|
9089
|
+
defaultBranchName
|
|
8566
9090
|
)
|
|
8567
9091
|
);
|
|
8568
9092
|
pullRequests.push(...pageRecords.filter((record) => Boolean(record)));
|
|
@@ -8581,7 +9105,7 @@ async function listProjectPullRequestSummaryRecords(ctx, octokit, scope, options
|
|
|
8581
9105
|
...nextCursor ? { nextCursor } : {}
|
|
8582
9106
|
};
|
|
8583
9107
|
}
|
|
8584
|
-
async function buildProjectPullRequestMetricCounts(octokit, repository, node, pullRequestStatusCache) {
|
|
9108
|
+
async function buildProjectPullRequestMetricCounts(octokit, repository, node, pullRequestStatusCache, defaultBranchName) {
|
|
8585
9109
|
if (!node || typeof node.number !== "number") {
|
|
8586
9110
|
return {
|
|
8587
9111
|
pullRequestNumber: null,
|
|
@@ -8595,6 +9119,8 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8595
9119
|
const inlineCiState = tryBuildGitHubPullRequestCiStateFromBatchNode({
|
|
8596
9120
|
statusCheckRollup: node.statusCheckRollup
|
|
8597
9121
|
});
|
|
9122
|
+
const inlineMergeability = normalizeGitHubPullRequestMergeability(node.mergeable);
|
|
9123
|
+
const inlineMergeStateStatus = normalizeGitHubPullRequestMergeStateStatus(node.mergeStateStatus);
|
|
8598
9124
|
const [reviewThreadSummary, reviewSummary, statusSnapshot] = await Promise.all([
|
|
8599
9125
|
getOrLoadCachedGitHubPullRequestReviewThreadSummary(
|
|
8600
9126
|
octokit,
|
|
@@ -8610,7 +9136,9 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8610
9136
|
),
|
|
8611
9137
|
getGitHubPullRequestStatusSnapshot(octokit, repository, node.number, pullRequestStatusCache, {
|
|
8612
9138
|
reviewThreadSummary: inlineReviewThreadSummary,
|
|
8613
|
-
ciState: inlineCiState
|
|
9139
|
+
ciState: inlineCiState,
|
|
9140
|
+
mergeability: inlineMergeability,
|
|
9141
|
+
mergeStateStatus: inlineMergeStateStatus
|
|
8614
9142
|
})
|
|
8615
9143
|
]);
|
|
8616
9144
|
const checksStatus = statusSnapshot.ciState === "green" ? "passed" : statusSnapshot.ciState === "red" ? "failed" : "pending";
|
|
@@ -8623,8 +9151,11 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8623
9151
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
8624
9152
|
checksStatus,
|
|
8625
9153
|
reviewApprovals: reviewSummary.approvals,
|
|
9154
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
8626
9155
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
8627
|
-
githubMergeable
|
|
9156
|
+
githubMergeable,
|
|
9157
|
+
baseBranch: node.baseRefName,
|
|
9158
|
+
defaultBranchName
|
|
8628
9159
|
});
|
|
8629
9160
|
return {
|
|
8630
9161
|
pullRequestNumber: Math.floor(node.number),
|
|
@@ -8674,7 +9205,13 @@ async function listProjectPullRequestMetrics(octokit, scope) {
|
|
|
8674
9205
|
const pageMetrics = await mapWithConcurrency(
|
|
8675
9206
|
pageNodes,
|
|
8676
9207
|
PROJECT_PULL_REQUEST_SUMMARY_CONCURRENCY,
|
|
8677
|
-
async (node) => buildProjectPullRequestMetricCounts(
|
|
9208
|
+
async (node) => buildProjectPullRequestMetricCounts(
|
|
9209
|
+
octokit,
|
|
9210
|
+
scope.repository,
|
|
9211
|
+
node,
|
|
9212
|
+
pullRequestStatusCache,
|
|
9213
|
+
defaultBranchName
|
|
9214
|
+
)
|
|
8678
9215
|
);
|
|
8679
9216
|
for (const pageMetric of pageMetrics) {
|
|
8680
9217
|
mergeablePullRequests += pageMetric.mergeablePullRequests;
|
|
@@ -9410,6 +9947,20 @@ function getPullRequestApiState(value) {
|
|
|
9410
9947
|
}
|
|
9411
9948
|
return value.state === "closed" ? "closed" : "open";
|
|
9412
9949
|
}
|
|
9950
|
+
async function getGitHubRepositoryDefaultBranchName(octokit, repository) {
|
|
9951
|
+
try {
|
|
9952
|
+
const response = await octokit.rest.repos.get({
|
|
9953
|
+
owner: repository.owner,
|
|
9954
|
+
repo: repository.repo,
|
|
9955
|
+
headers: {
|
|
9956
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
9957
|
+
}
|
|
9958
|
+
});
|
|
9959
|
+
return normalizeOptionalString2(response.data.default_branch);
|
|
9960
|
+
} catch {
|
|
9961
|
+
return void 0;
|
|
9962
|
+
}
|
|
9963
|
+
}
|
|
9413
9964
|
async function buildProjectPullRequestDetailData(ctx, input) {
|
|
9414
9965
|
const pullRequestNumber = normalizeToolPositiveInteger(input.pullRequestNumber);
|
|
9415
9966
|
if (!pullRequestNumber) {
|
|
@@ -9425,6 +9976,15 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9425
9976
|
activeProjectPullRequestSummaryRecordCache,
|
|
9426
9977
|
buildProjectPullRequestSummaryRecordCacheKey(scope, pullRequestNumber)
|
|
9427
9978
|
);
|
|
9979
|
+
const cachedSummary = getFreshCacheValue(
|
|
9980
|
+
activeProjectPullRequestSummaryCache,
|
|
9981
|
+
buildProjectPullRequestSummaryCacheKey(scope)
|
|
9982
|
+
);
|
|
9983
|
+
const cachedMetrics = getFreshCacheValue(
|
|
9984
|
+
activeProjectPullRequestMetricsCache,
|
|
9985
|
+
buildProjectPullRequestMetricsCacheKey(scope)
|
|
9986
|
+
);
|
|
9987
|
+
const cachedDefaultBranchName = normalizeOptionalString2(cachedSummary?.defaultBranchName) ?? normalizeOptionalString2(cachedMetrics?.defaultBranchName);
|
|
9428
9988
|
const cachedLinkedIssue = cachedSummaryRecord ? getLinkedPaperclipIssueFromProjectPullRequestRecord(cachedSummaryRecord) : void 0;
|
|
9429
9989
|
const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
|
|
9430
9990
|
const response = await octokit.rest.pulls.get({
|
|
@@ -9443,7 +10003,8 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9443
10003
|
reviewThreadSummary: reviewThreadSummary2
|
|
9444
10004
|
})
|
|
9445
10005
|
);
|
|
9446
|
-
const
|
|
10006
|
+
const defaultBranchNamePromise = cachedDefaultBranchName ? Promise.resolve(cachedDefaultBranchName) : getGitHubRepositoryDefaultBranchName(octokit, scope.repository);
|
|
10007
|
+
const [reviewSummary, reviewThreadSummary, comments, linkedIssue, statusSnapshot, defaultBranchName] = await Promise.all([
|
|
9447
10008
|
reviewSummaryPromise,
|
|
9448
10009
|
reviewThreadSummaryPromise,
|
|
9449
10010
|
listAllGitHubIssueComments(octokit, scope.repository, pullRequestNumber),
|
|
@@ -9455,7 +10016,8 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9455
10016
|
issueLookup
|
|
9456
10017
|
);
|
|
9457
10018
|
})(),
|
|
9458
|
-
statusSnapshotPromise
|
|
10019
|
+
statusSnapshotPromise,
|
|
10020
|
+
defaultBranchNamePromise
|
|
9459
10021
|
]);
|
|
9460
10022
|
const author = buildProjectPullRequestPerson({
|
|
9461
10023
|
login: pullRequest.user?.login,
|
|
@@ -9499,8 +10061,11 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9499
10061
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
9500
10062
|
checksStatus,
|
|
9501
10063
|
reviewApprovals: reviewSummary.approvals,
|
|
10064
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
9502
10065
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
9503
|
-
githubMergeable
|
|
10066
|
+
githubMergeable,
|
|
10067
|
+
baseBranch: pullRequest.base.ref,
|
|
10068
|
+
defaultBranchName
|
|
9504
10069
|
});
|
|
9505
10070
|
return setCacheValue(
|
|
9506
10071
|
activeProjectPullRequestDetailCache,
|
|
@@ -9695,6 +10260,49 @@ async function mergeProjectPullRequest(ctx, input) {
|
|
|
9695
10260
|
}
|
|
9696
10261
|
const scope = await requireProjectPullRequestScope(ctx, input);
|
|
9697
10262
|
const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
|
|
10263
|
+
const pullRequestResponse = await octokit.rest.pulls.get({
|
|
10264
|
+
owner: scope.repository.owner,
|
|
10265
|
+
repo: scope.repository.repo,
|
|
10266
|
+
pull_number: pullRequestNumber,
|
|
10267
|
+
headers: {
|
|
10268
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
10269
|
+
}
|
|
10270
|
+
});
|
|
10271
|
+
const pullRequest = pullRequestResponse.data;
|
|
10272
|
+
const reviewSummaryPromise = getOrLoadCachedGitHubPullRequestReviewSummary(octokit, scope.repository, pullRequestNumber);
|
|
10273
|
+
const reviewThreadSummaryPromise = getOrLoadCachedGitHubPullRequestReviewThreadSummary(octokit, scope.repository, pullRequestNumber);
|
|
10274
|
+
const statusSnapshotPromise = reviewThreadSummaryPromise.then(
|
|
10275
|
+
(reviewThreadSummary2) => getGitHubPullRequestStatusSnapshot(octokit, scope.repository, pullRequestNumber, /* @__PURE__ */ new Map(), {
|
|
10276
|
+
reviewThreadSummary: reviewThreadSummary2
|
|
10277
|
+
})
|
|
10278
|
+
);
|
|
10279
|
+
const defaultBranchNamePromise = getGitHubRepositoryDefaultBranchName(octokit, scope.repository);
|
|
10280
|
+
const [reviewSummary, reviewThreadSummary, statusSnapshot, defaultBranchName] = await Promise.all([
|
|
10281
|
+
reviewSummaryPromise,
|
|
10282
|
+
reviewThreadSummaryPromise,
|
|
10283
|
+
statusSnapshotPromise,
|
|
10284
|
+
defaultBranchNamePromise
|
|
10285
|
+
]);
|
|
10286
|
+
if (!defaultBranchName) {
|
|
10287
|
+
throw new Error(
|
|
10288
|
+
"Could not determine the repository default branch before merging this pull request. Retry the merge, and if it keeps failing check GitHub token permissions and connectivity."
|
|
10289
|
+
);
|
|
10290
|
+
}
|
|
10291
|
+
const checksStatus = statusSnapshot.ciState === "green" ? "passed" : statusSnapshot.ciState === "red" ? "failed" : "pending";
|
|
10292
|
+
const mergeable = resolveProjectPullRequestMergeable({
|
|
10293
|
+
checksStatus,
|
|
10294
|
+
reviewApprovals: reviewSummary.approvals,
|
|
10295
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
10296
|
+
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
10297
|
+
githubMergeable: pullRequest.mergeable === true,
|
|
10298
|
+
baseBranch: pullRequest.base.ref,
|
|
10299
|
+
defaultBranchName
|
|
10300
|
+
});
|
|
10301
|
+
if (!mergeable) {
|
|
10302
|
+
throw new Error(
|
|
10303
|
+
"This pull request is not mergeable yet. It must target the current default branch, have passing checks, at least one approval, no outstanding changes requests, and no unresolved review threads."
|
|
10304
|
+
);
|
|
10305
|
+
}
|
|
9698
10306
|
const response = await octokit.rest.pulls.merge({
|
|
9699
10307
|
owner: scope.repository.owner,
|
|
9700
10308
|
repo: scope.repository.repo,
|
|
@@ -10472,20 +11080,28 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
10472
11080
|
for (const [issueNumber, linkedPullRequests] of warmedLinkedPullRequests.entries()) {
|
|
10473
11081
|
linkedPullRequestsByIssueNumber.set(issueNumber, linkedPullRequests);
|
|
10474
11082
|
}
|
|
10475
|
-
const
|
|
11083
|
+
const openLinkedPullRequestNumbersByRepository = /* @__PURE__ */ new Map();
|
|
10476
11084
|
for (const linkedPullRequests of warmedLinkedPullRequests.values()) {
|
|
10477
11085
|
for (const pullRequest of linkedPullRequests) {
|
|
10478
11086
|
if (pullRequest.state === "OPEN") {
|
|
10479
|
-
|
|
11087
|
+
const pullRequestRepository = requireRepositoryReference(pullRequest.repositoryUrl);
|
|
11088
|
+
const entry = openLinkedPullRequestNumbersByRepository.get(pullRequestRepository.url) ?? {
|
|
11089
|
+
repository: pullRequestRepository,
|
|
11090
|
+
numbers: /* @__PURE__ */ new Set()
|
|
11091
|
+
};
|
|
11092
|
+
entry.numbers.add(pullRequest.number);
|
|
11093
|
+
openLinkedPullRequestNumbersByRepository.set(pullRequestRepository.url, entry);
|
|
10480
11094
|
}
|
|
10481
11095
|
}
|
|
10482
11096
|
}
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
11097
|
+
for (const entry of openLinkedPullRequestNumbersByRepository.values()) {
|
|
11098
|
+
await warmGitHubPullRequestStatusCache(
|
|
11099
|
+
octokit,
|
|
11100
|
+
entry.repository,
|
|
11101
|
+
entry.numbers,
|
|
11102
|
+
pullRequestStatusCache
|
|
11103
|
+
);
|
|
11104
|
+
}
|
|
10489
11105
|
await throwIfSyncCancelled();
|
|
10490
11106
|
} catch (error) {
|
|
10491
11107
|
if (error instanceof SyncCancellationError || isGitHubRateLimitError(error)) {
|
|
@@ -11274,6 +11890,7 @@ function registerGitHubAgentTools(ctx) {
|
|
|
11274
11890
|
].filter((warning) => warning !== null);
|
|
11275
11891
|
const snapshot = snapshotResult.status === "fulfilled" ? snapshotResult.value : {
|
|
11276
11892
|
number: target.pullRequestNumber,
|
|
11893
|
+
repositoryUrl: target.repository.url,
|
|
11277
11894
|
hasUnresolvedReviewThreads: false,
|
|
11278
11895
|
ciState: "unfinished"
|
|
11279
11896
|
};
|