paperclip-github-plugin 0.5.1 → 0.5.2
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 +8 -5
- 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 +513 -102
- 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) {
|
|
@@ -4010,8 +4034,13 @@ function normalizeProjectPullRequestClosingIssues(repository, nodes) {
|
|
|
4010
4034
|
function resolveProjectPullRequestReviewable(record) {
|
|
4011
4035
|
return record.githubMergeable === true && record.checksStatus === "passed" && typeof record.copilotUnresolvedReviewThreads === "number" && record.copilotUnresolvedReviewThreads === 0;
|
|
4012
4036
|
}
|
|
4037
|
+
function resolveProjectPullRequestTargetsDefaultBranch(record) {
|
|
4038
|
+
const baseBranch = normalizeOptionalString2(record.baseBranch);
|
|
4039
|
+
const defaultBranchName = normalizeOptionalString2(record.defaultBranchName);
|
|
4040
|
+
return Boolean(baseBranch && defaultBranchName && baseBranch === defaultBranchName);
|
|
4041
|
+
}
|
|
4013
4042
|
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;
|
|
4043
|
+
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
4044
|
}
|
|
4016
4045
|
function resolveProjectPullRequestUpToDateStatus(record) {
|
|
4017
4046
|
const mergeStateStatus = typeof record.mergeStateStatus === "string" ? record.mergeStateStatus : null;
|
|
@@ -4194,12 +4223,12 @@ function classifyGitHubPullRequestCiState(contexts) {
|
|
|
4194
4223
|
return hasPendingContext ? "unfinished" : "green";
|
|
4195
4224
|
}
|
|
4196
4225
|
function resolvePaperclipStatusFromLinkedPullRequests(linkedPullRequests, options) {
|
|
4197
|
-
if (linkedPullRequests.some(
|
|
4226
|
+
if (linkedPullRequests.some(
|
|
4227
|
+
(pullRequest) => pullRequest.hasUnresolvedReviewThreads || pullRequest.ciState === "red" || isGitHubPullRequestActionRequiredForSync(pullRequest)
|
|
4228
|
+
)) {
|
|
4198
4229
|
return options?.preferInProgress ? "in_progress" : "todo";
|
|
4199
4230
|
}
|
|
4200
|
-
if (linkedPullRequests.length > 0 && linkedPullRequests.every(
|
|
4201
|
-
(pullRequest) => pullRequest.ciState === "green" && pullRequest.hasUnresolvedReviewThreads === false
|
|
4202
|
-
)) {
|
|
4231
|
+
if (linkedPullRequests.length > 0 && linkedPullRequests.every((pullRequest) => isGitHubPullRequestReviewReadyForSync(pullRequest))) {
|
|
4203
4232
|
return "in_review";
|
|
4204
4233
|
}
|
|
4205
4234
|
return "in_progress";
|
|
@@ -4445,15 +4474,19 @@ function resolvePaperclipIssueReviewAssignee(syncContext, advancedSettings) {
|
|
|
4445
4474
|
role: nextStage.type === "approval" ? "approver" : "reviewer"
|
|
4446
4475
|
};
|
|
4447
4476
|
}
|
|
4477
|
+
const reviewStageType = nextStage?.type ?? currentStageType;
|
|
4478
|
+
if (!reviewStageType && !syncContext.executionPolicy) {
|
|
4479
|
+
return null;
|
|
4480
|
+
}
|
|
4448
4481
|
const approverOverride = getConfiguredAdvancedAssigneePrincipal(advancedSettings, "approver");
|
|
4449
|
-
if (
|
|
4482
|
+
if (reviewStageType === "approval" && approverOverride) {
|
|
4450
4483
|
return {
|
|
4451
4484
|
principal: approverOverride,
|
|
4452
4485
|
role: "approver"
|
|
4453
4486
|
};
|
|
4454
4487
|
}
|
|
4455
4488
|
const reviewerOverride = getConfiguredAdvancedAssigneePrincipal(advancedSettings, "reviewer");
|
|
4456
|
-
if (reviewerOverride) {
|
|
4489
|
+
if (reviewStageType !== "approval" && reviewerOverride) {
|
|
4457
4490
|
return {
|
|
4458
4491
|
principal: reviewerOverride,
|
|
4459
4492
|
role: "reviewer"
|
|
@@ -4541,6 +4574,9 @@ function buildSyncFallbackExecutionStatePatch(params) {
|
|
|
4541
4574
|
if ((currentStatus === "done" || currentStatus === "cancelled") && nextStatus !== "done" && nextStatus !== "cancelled") {
|
|
4542
4575
|
return previousState ? null : void 0;
|
|
4543
4576
|
}
|
|
4577
|
+
if (nextStatus === "done" || nextStatus === "cancelled") {
|
|
4578
|
+
return previousState ? null : void 0;
|
|
4579
|
+
}
|
|
4544
4580
|
if (nextStatus === "in_review" && syncContext.executionPolicy) {
|
|
4545
4581
|
const nextStageMatch = findPaperclipIssueExecutionStageMatch(syncContext.executionPolicy, previousState);
|
|
4546
4582
|
if (!nextStageMatch) {
|
|
@@ -4599,32 +4635,33 @@ function describeGitHubStatusTransitionReason(params) {
|
|
|
4599
4635
|
}
|
|
4600
4636
|
const linkedPullRequestSubject = snapshot.linkedPullRequests.length === 1 ? "the linked pull request" : "linked pull requests";
|
|
4601
4637
|
const linkedPullRequestVerb = snapshot.linkedPullRequests.length === 1 ? "has" : "have";
|
|
4602
|
-
const
|
|
4603
|
-
|
|
4638
|
+
const blockingConditions = [...new Set(
|
|
4639
|
+
snapshot.linkedPullRequests.flatMap((pullRequest) => listGitHubPullRequestSyncBlockingConditions(pullRequest))
|
|
4640
|
+
)];
|
|
4604
4641
|
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`;
|
|
4642
|
+
const hasUnknownMergeability = snapshot.linkedPullRequests.some(
|
|
4643
|
+
(pullRequest) => pullRequest.mergeStateStatus === "unknown"
|
|
4644
|
+
);
|
|
4645
|
+
if (blockingConditions.length > 0) {
|
|
4646
|
+
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} ${formatPlainTextList(blockingConditions)}`;
|
|
4613
4647
|
}
|
|
4614
4648
|
if (hasUnfinishedCi) {
|
|
4615
4649
|
return `${linkedPullRequestSubject} still ${linkedPullRequestVerb} unfinished CI jobs`;
|
|
4616
4650
|
}
|
|
4651
|
+
if (hasUnknownMergeability) {
|
|
4652
|
+
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} unknown mergeability`;
|
|
4653
|
+
}
|
|
4617
4654
|
return `${linkedPullRequestSubject} ${linkedPullRequestVerb} green CI with all review threads resolved`;
|
|
4618
4655
|
}
|
|
4619
4656
|
function buildStatusTransitionCommentAnnotation(params) {
|
|
4620
4657
|
const { repository, snapshot, previousStatus, nextStatus, reason } = params;
|
|
4658
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(snapshot.linkedPullRequests);
|
|
4621
4659
|
return {
|
|
4622
4660
|
repositoryUrl: repository.url,
|
|
4623
4661
|
githubIssueNumber: snapshot.issueNumber,
|
|
4624
4662
|
githubIssueUrl: `${repository.url}/issues/${snapshot.issueNumber}`,
|
|
4625
|
-
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
4626
|
-
|
|
4627
|
-
),
|
|
4663
|
+
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(linkedPullRequests.map((pullRequest) => pullRequest.number)),
|
|
4664
|
+
linkedPullRequests,
|
|
4628
4665
|
previousStatus,
|
|
4629
4666
|
nextStatus,
|
|
4630
4667
|
reason,
|
|
@@ -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
|
-
|
|
4728
|
-
}
|
|
4762
|
+
const pullRequestRepository = pullRequestOwner && pullRequestRepo ? parseRepositoryReference(`${pullRequestOwner}/${pullRequestRepo}`) : repository;
|
|
4763
|
+
if (!pullRequestRepository) {
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4766
|
+
const pullRequestKey = buildGitHubPullRequestReferenceKey({
|
|
4767
|
+
number: node.number,
|
|
4768
|
+
repositoryUrl: pullRequestRepository.url
|
|
4769
|
+
});
|
|
4770
|
+
if (seenPullRequestKeys.has(pullRequestKey)) {
|
|
4729
4771
|
continue;
|
|
4730
4772
|
}
|
|
4731
|
-
|
|
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 = {
|
|
@@ -5212,11 +5355,86 @@ function getHiddenGitHubImportMarkerPattern() {
|
|
|
5212
5355
|
"i"
|
|
5213
5356
|
);
|
|
5214
5357
|
}
|
|
5358
|
+
function formatPlainTextList(items) {
|
|
5359
|
+
if (items.length === 0) {
|
|
5360
|
+
return "";
|
|
5361
|
+
}
|
|
5362
|
+
if (items.length === 1) {
|
|
5363
|
+
return items[0];
|
|
5364
|
+
}
|
|
5365
|
+
if (items.length === 2) {
|
|
5366
|
+
return `${items[0]} and ${items[1]}`;
|
|
5367
|
+
}
|
|
5368
|
+
return `${items.slice(0, -1).join(", ")}, and ${items.at(-1)}`;
|
|
5369
|
+
}
|
|
5215
5370
|
function normalizeLinkedPullRequestNumbers(values) {
|
|
5216
5371
|
return [...new Set(
|
|
5217
5372
|
values.filter((pullRequestNumber) => Number.isInteger(pullRequestNumber) && pullRequestNumber > 0)
|
|
5218
5373
|
)].sort((left, right) => left - right);
|
|
5219
5374
|
}
|
|
5375
|
+
function buildGitHubPullRequestReferenceKey(pullRequest) {
|
|
5376
|
+
return `${getNormalizedMappingRepositoryUrl({ repositoryUrl: pullRequest.repositoryUrl }).toLowerCase()}#${Math.max(1, Math.floor(pullRequest.number))}`;
|
|
5377
|
+
}
|
|
5378
|
+
function normalizeLinkedPullRequestReferences(values, fallbackRepositoryUrl) {
|
|
5379
|
+
const references = [];
|
|
5380
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
5381
|
+
const normalizedFallbackRepositoryUrl = typeof fallbackRepositoryUrl === "string" && fallbackRepositoryUrl.trim() ? getNormalizedMappingRepositoryUrl({
|
|
5382
|
+
repositoryUrl: fallbackRepositoryUrl
|
|
5383
|
+
}) : void 0;
|
|
5384
|
+
for (const value of values) {
|
|
5385
|
+
const number = typeof value === "number" ? Math.floor(value) : value && typeof value === "object" && typeof value.number === "number" ? Math.floor(value.number) : void 0;
|
|
5386
|
+
const repositoryUrl = value && typeof value === "object" && typeof value.repositoryUrl === "string" && value.repositoryUrl.trim() ? getNormalizedMappingRepositoryUrl({
|
|
5387
|
+
repositoryUrl: value.repositoryUrl
|
|
5388
|
+
}) : normalizedFallbackRepositoryUrl;
|
|
5389
|
+
if (!number || number < 1 || !repositoryUrl) {
|
|
5390
|
+
continue;
|
|
5391
|
+
}
|
|
5392
|
+
const referenceKey = buildGitHubPullRequestReferenceKey({
|
|
5393
|
+
number,
|
|
5394
|
+
repositoryUrl
|
|
5395
|
+
});
|
|
5396
|
+
if (seenKeys.has(referenceKey)) {
|
|
5397
|
+
continue;
|
|
5398
|
+
}
|
|
5399
|
+
seenKeys.add(referenceKey);
|
|
5400
|
+
references.push({
|
|
5401
|
+
number,
|
|
5402
|
+
repositoryUrl
|
|
5403
|
+
});
|
|
5404
|
+
}
|
|
5405
|
+
references.sort((left, right) => {
|
|
5406
|
+
const repositoryUrlComparison = left.repositoryUrl.toLowerCase().localeCompare(right.repositoryUrl.toLowerCase());
|
|
5407
|
+
if (repositoryUrlComparison !== 0) {
|
|
5408
|
+
return repositoryUrlComparison;
|
|
5409
|
+
}
|
|
5410
|
+
return left.number - right.number;
|
|
5411
|
+
});
|
|
5412
|
+
return references;
|
|
5413
|
+
}
|
|
5414
|
+
function formatLinkedPullRequestReferenceLabel(pullRequest, issueRepositoryUrl) {
|
|
5415
|
+
const pullRequestRepository = parseRepositoryReference(pullRequest.repositoryUrl);
|
|
5416
|
+
if (!pullRequestRepository) {
|
|
5417
|
+
return `PR #${pullRequest.number}`;
|
|
5418
|
+
}
|
|
5419
|
+
if (issueRepositoryUrl) {
|
|
5420
|
+
const issueRepository = parseRepositoryReference(issueRepositoryUrl);
|
|
5421
|
+
if (issueRepository && areRepositoriesEqual(issueRepository, pullRequestRepository)) {
|
|
5422
|
+
return `PR #${pullRequest.number}`;
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
return `${formatRepositoryLabel(pullRequestRepository)}#${pullRequest.number}`;
|
|
5426
|
+
}
|
|
5427
|
+
function getCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, repository, pullRequestNumber) {
|
|
5428
|
+
return pullRequestStatusCache.get(
|
|
5429
|
+
buildGitHubPullRequestReferenceKey({
|
|
5430
|
+
number: pullRequestNumber,
|
|
5431
|
+
repositoryUrl: repository.url
|
|
5432
|
+
})
|
|
5433
|
+
);
|
|
5434
|
+
}
|
|
5435
|
+
function setCachedGitHubPullRequestStatusSnapshot(pullRequestStatusCache, snapshot) {
|
|
5436
|
+
pullRequestStatusCache.set(buildGitHubPullRequestReferenceKey(snapshot), snapshot);
|
|
5437
|
+
}
|
|
5220
5438
|
function extractImportedGitHubIssueUrlFromDescription(description) {
|
|
5221
5439
|
if (typeof description !== "string") {
|
|
5222
5440
|
return void 0;
|
|
@@ -5442,6 +5660,14 @@ function normalizeGitHubIssueLinkEntityData(value) {
|
|
|
5442
5660
|
if (!repositoryUrl || githubIssueId === void 0 || githubIssueNumber === void 0 || !githubIssueUrl || !githubIssueState || !syncedAt) {
|
|
5443
5661
|
return null;
|
|
5444
5662
|
}
|
|
5663
|
+
const linkedPullRequestNumbers = normalizeLinkedPullRequestNumbers(
|
|
5664
|
+
Array.isArray(record.linkedPullRequestNumbers) ? record.linkedPullRequestNumbers.filter((entry) => typeof entry === "number") : []
|
|
5665
|
+
);
|
|
5666
|
+
const rawLinkedPullRequests = Array.isArray(record.linkedPullRequests) ? record.linkedPullRequests : [];
|
|
5667
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(
|
|
5668
|
+
rawLinkedPullRequests.length > 0 ? rawLinkedPullRequests : linkedPullRequestNumbers,
|
|
5669
|
+
repositoryUrl
|
|
5670
|
+
);
|
|
5445
5671
|
return {
|
|
5446
5672
|
...typeof record.companyId === "string" && record.companyId.trim() ? { companyId: record.companyId.trim() } : {},
|
|
5447
5673
|
...typeof record.paperclipProjectId === "string" && record.paperclipProjectId.trim() ? { paperclipProjectId: record.paperclipProjectId.trim() } : {},
|
|
@@ -5455,9 +5681,8 @@ function normalizeGitHubIssueLinkEntityData(value) {
|
|
|
5455
5681
|
githubIssueState,
|
|
5456
5682
|
...githubIssueStateReason ? { githubIssueStateReason } : {},
|
|
5457
5683
|
commentsCount,
|
|
5458
|
-
linkedPullRequestNumbers
|
|
5459
|
-
|
|
5460
|
-
),
|
|
5684
|
+
linkedPullRequestNumbers,
|
|
5685
|
+
linkedPullRequests,
|
|
5461
5686
|
labels: normalizeStoredGitHubIssueLabels(record.labels),
|
|
5462
5687
|
syncedAt
|
|
5463
5688
|
};
|
|
@@ -5507,15 +5732,22 @@ function normalizeStoredStatusTransitionCommentAnnotation(value) {
|
|
|
5507
5732
|
if (!repositoryUrl || githubIssueNumber === void 0 || !githubIssueUrl || !previousStatus || !nextStatus || !reason || !createdAt || !paperclipIssueId) {
|
|
5508
5733
|
return null;
|
|
5509
5734
|
}
|
|
5735
|
+
const linkedPullRequestNumbers = normalizeLinkedPullRequestNumbers(
|
|
5736
|
+
Array.isArray(record.linkedPullRequestNumbers) ? record.linkedPullRequestNumbers.filter((entry) => typeof entry === "number") : []
|
|
5737
|
+
);
|
|
5738
|
+
const rawLinkedPullRequests = Array.isArray(record.linkedPullRequests) ? record.linkedPullRequests : [];
|
|
5739
|
+
const linkedPullRequests = normalizeLinkedPullRequestReferences(
|
|
5740
|
+
rawLinkedPullRequests.length > 0 ? rawLinkedPullRequests : linkedPullRequestNumbers,
|
|
5741
|
+
repositoryUrl
|
|
5742
|
+
);
|
|
5510
5743
|
return {
|
|
5511
5744
|
...typeof record.companyId === "string" && record.companyId.trim() ? { companyId: record.companyId.trim() } : {},
|
|
5512
5745
|
paperclipIssueId,
|
|
5513
5746
|
repositoryUrl,
|
|
5514
5747
|
githubIssueNumber,
|
|
5515
5748
|
githubIssueUrl,
|
|
5516
|
-
linkedPullRequestNumbers
|
|
5517
|
-
|
|
5518
|
-
),
|
|
5749
|
+
linkedPullRequestNumbers,
|
|
5750
|
+
linkedPullRequests,
|
|
5519
5751
|
previousStatus,
|
|
5520
5752
|
nextStatus,
|
|
5521
5753
|
reason,
|
|
@@ -5642,9 +5874,10 @@ async function findStoredStatusTransitionCommentAnnotation(ctx, params) {
|
|
|
5642
5874
|
}
|
|
5643
5875
|
return null;
|
|
5644
5876
|
}
|
|
5645
|
-
function buildGitHubIssueLinkRecord(target, issueId, githubIssue,
|
|
5877
|
+
function buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequests) {
|
|
5646
5878
|
const githubIssueUrl = normalizeGitHubIssueHtmlUrl(githubIssue.htmlUrl) ?? githubIssue.htmlUrl;
|
|
5647
5879
|
const repositoryUrl = parseRepositoryReference(target.repositoryUrl)?.url ?? target.repositoryUrl.trim();
|
|
5880
|
+
const normalizedLinkedPullRequests = normalizeLinkedPullRequestReferences(linkedPullRequests, repositoryUrl);
|
|
5648
5881
|
return {
|
|
5649
5882
|
paperclipIssueId: issueId,
|
|
5650
5883
|
title: `GitHub issue #${githubIssue.number}`,
|
|
@@ -5662,14 +5895,17 @@ function buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequ
|
|
|
5662
5895
|
githubIssueState: githubIssue.state,
|
|
5663
5896
|
...githubIssue.stateReason ? { githubIssueStateReason: githubIssue.stateReason } : {},
|
|
5664
5897
|
commentsCount: githubIssue.commentsCount,
|
|
5665
|
-
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
5898
|
+
linkedPullRequestNumbers: normalizeLinkedPullRequestNumbers(
|
|
5899
|
+
normalizedLinkedPullRequests.map((pullRequest) => pullRequest.number)
|
|
5900
|
+
),
|
|
5901
|
+
linkedPullRequests: normalizedLinkedPullRequests,
|
|
5666
5902
|
labels: githubIssue.labels,
|
|
5667
5903
|
syncedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5668
5904
|
}
|
|
5669
5905
|
};
|
|
5670
5906
|
}
|
|
5671
|
-
async function upsertGitHubIssueLinkRecord(ctx, target, issueId, githubIssue,
|
|
5672
|
-
const record = buildGitHubIssueLinkRecord(target, issueId, githubIssue,
|
|
5907
|
+
async function upsertGitHubIssueLinkRecord(ctx, target, issueId, githubIssue, linkedPullRequests) {
|
|
5908
|
+
const record = buildGitHubIssueLinkRecord(target, issueId, githubIssue, linkedPullRequests);
|
|
5673
5909
|
await ctx.entities.upsert({
|
|
5674
5910
|
entityType: ISSUE_LINK_ENTITY_TYPE,
|
|
5675
5911
|
scopeKind: "issue",
|
|
@@ -6580,14 +6816,22 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6580
6816
|
syncContext,
|
|
6581
6817
|
nextStatus,
|
|
6582
6818
|
nextAssignee,
|
|
6819
|
+
clearAssignee,
|
|
6583
6820
|
transitionComment,
|
|
6584
6821
|
transitionCommentAnnotation,
|
|
6585
6822
|
paperclipApiBaseUrl
|
|
6586
6823
|
} = params;
|
|
6587
6824
|
const trimmedTransitionComment = transitionComment.trim();
|
|
6588
6825
|
let issueUpdated = false;
|
|
6826
|
+
const syncExecutionStatePatch = buildSyncFallbackExecutionStatePatch({
|
|
6827
|
+
currentStatus,
|
|
6828
|
+
nextStatus,
|
|
6829
|
+
syncContext,
|
|
6830
|
+
nextAssignee
|
|
6831
|
+
});
|
|
6589
6832
|
const issuePatch = {
|
|
6590
|
-
status: nextStatus
|
|
6833
|
+
status: nextStatus,
|
|
6834
|
+
...syncExecutionStatePatch === null ? { executionState: null } : {}
|
|
6591
6835
|
};
|
|
6592
6836
|
if (nextAssignee) {
|
|
6593
6837
|
if (nextAssignee.kind === "agent") {
|
|
@@ -6597,6 +6841,9 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6597
6841
|
issuePatch.assigneeAgentId = null;
|
|
6598
6842
|
issuePatch.assigneeUserId = nextAssignee.id;
|
|
6599
6843
|
}
|
|
6844
|
+
} else if (clearAssignee) {
|
|
6845
|
+
issuePatch.assigneeAgentId = null;
|
|
6846
|
+
issuePatch.assigneeUserId = null;
|
|
6600
6847
|
}
|
|
6601
6848
|
if (paperclipApiBaseUrl) {
|
|
6602
6849
|
try {
|
|
@@ -6642,16 +6889,10 @@ async function updatePaperclipIssueState(ctx, params) {
|
|
|
6642
6889
|
}
|
|
6643
6890
|
}
|
|
6644
6891
|
if (!issueUpdated) {
|
|
6645
|
-
const fallbackExecutionStatePatch = buildSyncFallbackExecutionStatePatch({
|
|
6646
|
-
currentStatus,
|
|
6647
|
-
nextStatus,
|
|
6648
|
-
syncContext,
|
|
6649
|
-
nextAssignee
|
|
6650
|
-
});
|
|
6651
6892
|
const preserveExistingUserAssigneeWithoutLocalApi = nextAssignee?.kind === "user" && !paperclipApiBaseUrl;
|
|
6652
6893
|
const sdkIssuePatch = {
|
|
6653
6894
|
...issuePatch,
|
|
6654
|
-
...
|
|
6895
|
+
...syncExecutionStatePatch !== void 0 ? { executionState: syncExecutionStatePatch } : {}
|
|
6655
6896
|
};
|
|
6656
6897
|
if (preserveExistingUserAssigneeWithoutLocalApi) {
|
|
6657
6898
|
delete sdkIssuePatch.assigneeAgentId;
|
|
@@ -7034,7 +7275,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7034
7275
|
stateReason: snapshot.stateReason,
|
|
7035
7276
|
commentsCount: snapshot.commentCount
|
|
7036
7277
|
},
|
|
7037
|
-
|
|
7278
|
+
snapshot.linkedPullRequests
|
|
7038
7279
|
);
|
|
7039
7280
|
const previousCommentCount = importedIssue.lastSeenCommentCount;
|
|
7040
7281
|
const hasNewComments = snapshot.commentCount > (previousCommentCount ?? snapshot.commentCount);
|
|
@@ -7073,12 +7314,30 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7073
7314
|
syncContext: paperclipIssueSyncContext,
|
|
7074
7315
|
advancedSettings
|
|
7075
7316
|
});
|
|
7317
|
+
const shouldClearTransitionAssignee = nextStatus === "in_review" && nextTransitionAssignee === null && paperclipIssueSyncContext.assignee !== null;
|
|
7076
7318
|
const nextAssigneeChanged = nextTransitionAssignee ? !doesPaperclipIssueAssigneeMatch(paperclipIssueSyncContext.assignee, nextTransitionAssignee.principal) : false;
|
|
7077
7319
|
const shouldWakeImportedAssignee = wasImportedThisRun && paperclipIssue.status === nextStatus && nextStatus === "todo" && paperclipIssueSyncContext.assignee?.kind === "agent";
|
|
7078
7320
|
const shouldWakeTransitionAssignee = paperclipIssue.status !== nextStatus && nextTransitionAssignee?.principal.kind === "agent" && isActionablePaperclipIssueStatus(nextStatus) && (nextAssigneeChanged || paperclipIssue.status !== nextStatus);
|
|
7079
7321
|
importedIssue.githubIssueNumber = githubIssue.number;
|
|
7080
7322
|
importedIssue.lastSeenCommentCount = snapshot.commentCount;
|
|
7081
7323
|
if (paperclipIssue.status === nextStatus) {
|
|
7324
|
+
if (shouldClearTransitionAssignee) {
|
|
7325
|
+
updateSyncFailureContext(syncFailureContext, {
|
|
7326
|
+
phase: "updating_paperclip_status",
|
|
7327
|
+
repositoryUrl: repository.url,
|
|
7328
|
+
githubIssueNumber: githubIssue.number
|
|
7329
|
+
});
|
|
7330
|
+
await updatePaperclipIssueState(ctx, {
|
|
7331
|
+
companyId: mapping.companyId,
|
|
7332
|
+
issueId: importedIssue.paperclipIssueId,
|
|
7333
|
+
currentStatus: paperclipIssue.status,
|
|
7334
|
+
syncContext: paperclipIssueSyncContext,
|
|
7335
|
+
nextStatus,
|
|
7336
|
+
clearAssignee: true,
|
|
7337
|
+
transitionComment: "",
|
|
7338
|
+
paperclipApiBaseUrl
|
|
7339
|
+
});
|
|
7340
|
+
}
|
|
7082
7341
|
if (shouldWakeImportedAssignee) {
|
|
7083
7342
|
queuedIssueWakeups.push({
|
|
7084
7343
|
assigneeAgentId: paperclipIssueSyncContext.assignee?.kind === "agent" ? paperclipIssueSyncContext.assignee.id : null,
|
|
@@ -7110,6 +7369,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
7110
7369
|
syncContext: paperclipIssueSyncContext,
|
|
7111
7370
|
nextStatus,
|
|
7112
7371
|
...nextTransitionAssignee ? { nextAssignee: nextTransitionAssignee.principal } : {},
|
|
7372
|
+
...shouldClearTransitionAssignee ? { clearAssignee: true } : {},
|
|
7113
7373
|
transitionComment: transitionComment.body,
|
|
7114
7374
|
transitionCommentAnnotation: transitionComment.annotation,
|
|
7115
7375
|
paperclipApiBaseUrl
|
|
@@ -7672,23 +7932,73 @@ async function resolveGitHubPullRequestToolTarget(ctx, runCtx, input) {
|
|
|
7672
7932
|
if (!link) {
|
|
7673
7933
|
throw new Error("This Paperclip issue is not linked to GitHub yet.");
|
|
7674
7934
|
}
|
|
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
7935
|
const explicitPullRequestNumber = normalizeToolPositiveInteger(input.pullRequestNumber);
|
|
7936
|
+
const linkedPullRequests = link.linkedPullRequests.length > 0 ? link.linkedPullRequests : normalizeLinkedPullRequestReferences(link.linkedPullRequestNumbers, link.repositoryUrl);
|
|
7681
7937
|
if (explicitPullRequestNumber !== void 0) {
|
|
7938
|
+
const explicitRepository = normalizeOptionalToolString(input.repository);
|
|
7939
|
+
const matchingLinkedPullRequests = linkedPullRequests.filter(
|
|
7940
|
+
(pullRequest) => pullRequest.number === explicitPullRequestNumber
|
|
7941
|
+
);
|
|
7942
|
+
if (explicitRepository) {
|
|
7943
|
+
const requestedRepository = requireRepositoryReference(explicitRepository);
|
|
7944
|
+
if (matchingLinkedPullRequests.length > 0) {
|
|
7945
|
+
const matchingLinkedPullRequest = matchingLinkedPullRequests.find(
|
|
7946
|
+
(pullRequest) => areRepositoriesEqual(requestedRepository, requireRepositoryReference(pullRequest.repositoryUrl))
|
|
7947
|
+
);
|
|
7948
|
+
if (!matchingLinkedPullRequest) {
|
|
7949
|
+
const linkedIssueRepository = requireRepositoryReference(link.repositoryUrl);
|
|
7950
|
+
const allMatchingPullRequestsUseIssueRepository = matchingLinkedPullRequests.every(
|
|
7951
|
+
(pullRequest) => areRepositoriesEqual(linkedIssueRepository, requireRepositoryReference(pullRequest.repositoryUrl))
|
|
7952
|
+
);
|
|
7953
|
+
throw new Error(
|
|
7954
|
+
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."
|
|
7955
|
+
);
|
|
7956
|
+
}
|
|
7957
|
+
return {
|
|
7958
|
+
repository: requestedRepository,
|
|
7959
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
7960
|
+
paperclipIssueId
|
|
7961
|
+
};
|
|
7962
|
+
}
|
|
7963
|
+
const repository2 = assertExplicitRepositoryMatchesLinkedRepository(
|
|
7964
|
+
input.repository,
|
|
7965
|
+
link.repositoryUrl,
|
|
7966
|
+
"repository must match the GitHub repository linked to the provided Paperclip issue."
|
|
7967
|
+
);
|
|
7968
|
+
return {
|
|
7969
|
+
repository: repository2,
|
|
7970
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
7971
|
+
paperclipIssueId
|
|
7972
|
+
};
|
|
7973
|
+
}
|
|
7974
|
+
if (matchingLinkedPullRequests.length === 1) {
|
|
7975
|
+
return {
|
|
7976
|
+
repository: requireRepositoryReference(matchingLinkedPullRequests[0].repositoryUrl),
|
|
7977
|
+
pullRequestNumber: explicitPullRequestNumber,
|
|
7978
|
+
paperclipIssueId
|
|
7979
|
+
};
|
|
7980
|
+
}
|
|
7981
|
+
if (matchingLinkedPullRequests.length > 1) {
|
|
7982
|
+
throw new Error("repository is required because the linked Paperclip issue has matching pull request numbers in multiple repositories.");
|
|
7983
|
+
}
|
|
7682
7984
|
return {
|
|
7683
|
-
repository:
|
|
7985
|
+
repository: requireRepositoryReference(link.repositoryUrl),
|
|
7684
7986
|
pullRequestNumber: explicitPullRequestNumber,
|
|
7685
7987
|
paperclipIssueId
|
|
7686
7988
|
};
|
|
7687
7989
|
}
|
|
7688
|
-
if (
|
|
7990
|
+
if (linkedPullRequests.length === 1) {
|
|
7991
|
+
const inferredPullRequest = linkedPullRequests[0];
|
|
7992
|
+
const explicitRepository = normalizeOptionalToolString(input.repository);
|
|
7993
|
+
if (explicitRepository) {
|
|
7994
|
+
const requestedRepository = requireRepositoryReference(explicitRepository);
|
|
7995
|
+
if (!areRepositoriesEqual(requestedRepository, requireRepositoryReference(inferredPullRequest.repositoryUrl))) {
|
|
7996
|
+
throw new Error("repository must match the GitHub repository for the selected linked pull request.");
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7689
7999
|
return {
|
|
7690
|
-
repository:
|
|
7691
|
-
pullRequestNumber:
|
|
8000
|
+
repository: requireRepositoryReference(inferredPullRequest.repositoryUrl),
|
|
8001
|
+
pullRequestNumber: inferredPullRequest.number,
|
|
7692
8002
|
paperclipIssueId
|
|
7693
8003
|
};
|
|
7694
8004
|
}
|
|
@@ -8437,7 +8747,7 @@ function getProjectPullRequestStatus(state) {
|
|
|
8437
8747
|
return "open";
|
|
8438
8748
|
}
|
|
8439
8749
|
}
|
|
8440
|
-
async function buildProjectPullRequestSummaryRecord(octokit, repository, node, issueLookup, pullRequestStatusCache) {
|
|
8750
|
+
async function buildProjectPullRequestSummaryRecord(octokit, repository, node, issueLookup, pullRequestStatusCache, defaultBranchName) {
|
|
8441
8751
|
if (!node || typeof node.number !== "number" || !node.url || !node.title?.trim()) {
|
|
8442
8752
|
return null;
|
|
8443
8753
|
}
|
|
@@ -8446,6 +8756,8 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8446
8756
|
const inlineCiState = tryBuildGitHubPullRequestCiStateFromBatchNode({
|
|
8447
8757
|
statusCheckRollup: node.statusCheckRollup
|
|
8448
8758
|
});
|
|
8759
|
+
const inlineMergeability = normalizeGitHubPullRequestMergeability(node.mergeable);
|
|
8760
|
+
const inlineMergeStateStatus = normalizeGitHubPullRequestMergeStateStatus(node.mergeStateStatus);
|
|
8449
8761
|
const [reviewThreadSummary, reviewSummary, statusSnapshot, behindBy] = await Promise.all([
|
|
8450
8762
|
getOrLoadCachedGitHubPullRequestReviewThreadSummary(
|
|
8451
8763
|
octokit,
|
|
@@ -8461,7 +8773,9 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8461
8773
|
),
|
|
8462
8774
|
getGitHubPullRequestStatusSnapshot(octokit, repository, node.number, pullRequestStatusCache, {
|
|
8463
8775
|
reviewThreadSummary: inlineReviewThreadSummary,
|
|
8464
|
-
ciState: inlineCiState
|
|
8776
|
+
ciState: inlineCiState,
|
|
8777
|
+
mergeability: inlineMergeability,
|
|
8778
|
+
mergeStateStatus: inlineMergeStateStatus
|
|
8465
8779
|
}),
|
|
8466
8780
|
getGitHubPullRequestBehindCount(octokit, repository, {
|
|
8467
8781
|
baseBranch: node.baseRefName,
|
|
@@ -8486,8 +8800,11 @@ async function buildProjectPullRequestSummaryRecord(octokit, repository, node, i
|
|
|
8486
8800
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
8487
8801
|
checksStatus,
|
|
8488
8802
|
reviewApprovals: reviewSummary.approvals,
|
|
8803
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
8489
8804
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
8490
|
-
githubMergeable
|
|
8805
|
+
githubMergeable,
|
|
8806
|
+
baseBranch: node.baseRefName,
|
|
8807
|
+
defaultBranchName
|
|
8491
8808
|
});
|
|
8492
8809
|
const upToDateStatus = resolveProjectPullRequestUpToDateStatus({
|
|
8493
8810
|
mergeStateStatus: node.mergeStateStatus,
|
|
@@ -8562,7 +8879,8 @@ async function listProjectPullRequestSummaryRecords(ctx, octokit, scope, options
|
|
|
8562
8879
|
scope.repository,
|
|
8563
8880
|
node,
|
|
8564
8881
|
issueLookup,
|
|
8565
|
-
pullRequestStatusCache
|
|
8882
|
+
pullRequestStatusCache,
|
|
8883
|
+
defaultBranchName
|
|
8566
8884
|
)
|
|
8567
8885
|
);
|
|
8568
8886
|
pullRequests.push(...pageRecords.filter((record) => Boolean(record)));
|
|
@@ -8581,7 +8899,7 @@ async function listProjectPullRequestSummaryRecords(ctx, octokit, scope, options
|
|
|
8581
8899
|
...nextCursor ? { nextCursor } : {}
|
|
8582
8900
|
};
|
|
8583
8901
|
}
|
|
8584
|
-
async function buildProjectPullRequestMetricCounts(octokit, repository, node, pullRequestStatusCache) {
|
|
8902
|
+
async function buildProjectPullRequestMetricCounts(octokit, repository, node, pullRequestStatusCache, defaultBranchName) {
|
|
8585
8903
|
if (!node || typeof node.number !== "number") {
|
|
8586
8904
|
return {
|
|
8587
8905
|
pullRequestNumber: null,
|
|
@@ -8595,6 +8913,8 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8595
8913
|
const inlineCiState = tryBuildGitHubPullRequestCiStateFromBatchNode({
|
|
8596
8914
|
statusCheckRollup: node.statusCheckRollup
|
|
8597
8915
|
});
|
|
8916
|
+
const inlineMergeability = normalizeGitHubPullRequestMergeability(node.mergeable);
|
|
8917
|
+
const inlineMergeStateStatus = normalizeGitHubPullRequestMergeStateStatus(node.mergeStateStatus);
|
|
8598
8918
|
const [reviewThreadSummary, reviewSummary, statusSnapshot] = await Promise.all([
|
|
8599
8919
|
getOrLoadCachedGitHubPullRequestReviewThreadSummary(
|
|
8600
8920
|
octokit,
|
|
@@ -8610,7 +8930,9 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8610
8930
|
),
|
|
8611
8931
|
getGitHubPullRequestStatusSnapshot(octokit, repository, node.number, pullRequestStatusCache, {
|
|
8612
8932
|
reviewThreadSummary: inlineReviewThreadSummary,
|
|
8613
|
-
ciState: inlineCiState
|
|
8933
|
+
ciState: inlineCiState,
|
|
8934
|
+
mergeability: inlineMergeability,
|
|
8935
|
+
mergeStateStatus: inlineMergeStateStatus
|
|
8614
8936
|
})
|
|
8615
8937
|
]);
|
|
8616
8938
|
const checksStatus = statusSnapshot.ciState === "green" ? "passed" : statusSnapshot.ciState === "red" ? "failed" : "pending";
|
|
@@ -8623,8 +8945,11 @@ async function buildProjectPullRequestMetricCounts(octokit, repository, node, pu
|
|
|
8623
8945
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
8624
8946
|
checksStatus,
|
|
8625
8947
|
reviewApprovals: reviewSummary.approvals,
|
|
8948
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
8626
8949
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
8627
|
-
githubMergeable
|
|
8950
|
+
githubMergeable,
|
|
8951
|
+
baseBranch: node.baseRefName,
|
|
8952
|
+
defaultBranchName
|
|
8628
8953
|
});
|
|
8629
8954
|
return {
|
|
8630
8955
|
pullRequestNumber: Math.floor(node.number),
|
|
@@ -8674,7 +8999,13 @@ async function listProjectPullRequestMetrics(octokit, scope) {
|
|
|
8674
8999
|
const pageMetrics = await mapWithConcurrency(
|
|
8675
9000
|
pageNodes,
|
|
8676
9001
|
PROJECT_PULL_REQUEST_SUMMARY_CONCURRENCY,
|
|
8677
|
-
async (node) => buildProjectPullRequestMetricCounts(
|
|
9002
|
+
async (node) => buildProjectPullRequestMetricCounts(
|
|
9003
|
+
octokit,
|
|
9004
|
+
scope.repository,
|
|
9005
|
+
node,
|
|
9006
|
+
pullRequestStatusCache,
|
|
9007
|
+
defaultBranchName
|
|
9008
|
+
)
|
|
8678
9009
|
);
|
|
8679
9010
|
for (const pageMetric of pageMetrics) {
|
|
8680
9011
|
mergeablePullRequests += pageMetric.mergeablePullRequests;
|
|
@@ -9410,6 +9741,20 @@ function getPullRequestApiState(value) {
|
|
|
9410
9741
|
}
|
|
9411
9742
|
return value.state === "closed" ? "closed" : "open";
|
|
9412
9743
|
}
|
|
9744
|
+
async function getGitHubRepositoryDefaultBranchName(octokit, repository) {
|
|
9745
|
+
try {
|
|
9746
|
+
const response = await octokit.rest.repos.get({
|
|
9747
|
+
owner: repository.owner,
|
|
9748
|
+
repo: repository.repo,
|
|
9749
|
+
headers: {
|
|
9750
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
9751
|
+
}
|
|
9752
|
+
});
|
|
9753
|
+
return normalizeOptionalString2(response.data.default_branch);
|
|
9754
|
+
} catch {
|
|
9755
|
+
return void 0;
|
|
9756
|
+
}
|
|
9757
|
+
}
|
|
9413
9758
|
async function buildProjectPullRequestDetailData(ctx, input) {
|
|
9414
9759
|
const pullRequestNumber = normalizeToolPositiveInteger(input.pullRequestNumber);
|
|
9415
9760
|
if (!pullRequestNumber) {
|
|
@@ -9425,6 +9770,15 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9425
9770
|
activeProjectPullRequestSummaryRecordCache,
|
|
9426
9771
|
buildProjectPullRequestSummaryRecordCacheKey(scope, pullRequestNumber)
|
|
9427
9772
|
);
|
|
9773
|
+
const cachedSummary = getFreshCacheValue(
|
|
9774
|
+
activeProjectPullRequestSummaryCache,
|
|
9775
|
+
buildProjectPullRequestSummaryCacheKey(scope)
|
|
9776
|
+
);
|
|
9777
|
+
const cachedMetrics = getFreshCacheValue(
|
|
9778
|
+
activeProjectPullRequestMetricsCache,
|
|
9779
|
+
buildProjectPullRequestMetricsCacheKey(scope)
|
|
9780
|
+
);
|
|
9781
|
+
const cachedDefaultBranchName = normalizeOptionalString2(cachedSummary?.defaultBranchName) ?? normalizeOptionalString2(cachedMetrics?.defaultBranchName);
|
|
9428
9782
|
const cachedLinkedIssue = cachedSummaryRecord ? getLinkedPaperclipIssueFromProjectPullRequestRecord(cachedSummaryRecord) : void 0;
|
|
9429
9783
|
const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
|
|
9430
9784
|
const response = await octokit.rest.pulls.get({
|
|
@@ -9443,7 +9797,8 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9443
9797
|
reviewThreadSummary: reviewThreadSummary2
|
|
9444
9798
|
})
|
|
9445
9799
|
);
|
|
9446
|
-
const
|
|
9800
|
+
const defaultBranchNamePromise = cachedDefaultBranchName ? Promise.resolve(cachedDefaultBranchName) : getGitHubRepositoryDefaultBranchName(octokit, scope.repository);
|
|
9801
|
+
const [reviewSummary, reviewThreadSummary, comments, linkedIssue, statusSnapshot, defaultBranchName] = await Promise.all([
|
|
9447
9802
|
reviewSummaryPromise,
|
|
9448
9803
|
reviewThreadSummaryPromise,
|
|
9449
9804
|
listAllGitHubIssueComments(octokit, scope.repository, pullRequestNumber),
|
|
@@ -9455,7 +9810,8 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9455
9810
|
issueLookup
|
|
9456
9811
|
);
|
|
9457
9812
|
})(),
|
|
9458
|
-
statusSnapshotPromise
|
|
9813
|
+
statusSnapshotPromise,
|
|
9814
|
+
defaultBranchNamePromise
|
|
9459
9815
|
]);
|
|
9460
9816
|
const author = buildProjectPullRequestPerson({
|
|
9461
9817
|
login: pullRequest.user?.login,
|
|
@@ -9499,8 +9855,11 @@ async function buildProjectPullRequestDetailData(ctx, input) {
|
|
|
9499
9855
|
const mergeable = resolveProjectPullRequestMergeable({
|
|
9500
9856
|
checksStatus,
|
|
9501
9857
|
reviewApprovals: reviewSummary.approvals,
|
|
9858
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
9502
9859
|
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
9503
|
-
githubMergeable
|
|
9860
|
+
githubMergeable,
|
|
9861
|
+
baseBranch: pullRequest.base.ref,
|
|
9862
|
+
defaultBranchName
|
|
9504
9863
|
});
|
|
9505
9864
|
return setCacheValue(
|
|
9506
9865
|
activeProjectPullRequestDetailCache,
|
|
@@ -9695,6 +10054,49 @@ async function mergeProjectPullRequest(ctx, input) {
|
|
|
9695
10054
|
}
|
|
9696
10055
|
const scope = await requireProjectPullRequestScope(ctx, input);
|
|
9697
10056
|
const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
|
|
10057
|
+
const pullRequestResponse = await octokit.rest.pulls.get({
|
|
10058
|
+
owner: scope.repository.owner,
|
|
10059
|
+
repo: scope.repository.repo,
|
|
10060
|
+
pull_number: pullRequestNumber,
|
|
10061
|
+
headers: {
|
|
10062
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
10063
|
+
}
|
|
10064
|
+
});
|
|
10065
|
+
const pullRequest = pullRequestResponse.data;
|
|
10066
|
+
const reviewSummaryPromise = getOrLoadCachedGitHubPullRequestReviewSummary(octokit, scope.repository, pullRequestNumber);
|
|
10067
|
+
const reviewThreadSummaryPromise = getOrLoadCachedGitHubPullRequestReviewThreadSummary(octokit, scope.repository, pullRequestNumber);
|
|
10068
|
+
const statusSnapshotPromise = reviewThreadSummaryPromise.then(
|
|
10069
|
+
(reviewThreadSummary2) => getGitHubPullRequestStatusSnapshot(octokit, scope.repository, pullRequestNumber, /* @__PURE__ */ new Map(), {
|
|
10070
|
+
reviewThreadSummary: reviewThreadSummary2
|
|
10071
|
+
})
|
|
10072
|
+
);
|
|
10073
|
+
const defaultBranchNamePromise = getGitHubRepositoryDefaultBranchName(octokit, scope.repository);
|
|
10074
|
+
const [reviewSummary, reviewThreadSummary, statusSnapshot, defaultBranchName] = await Promise.all([
|
|
10075
|
+
reviewSummaryPromise,
|
|
10076
|
+
reviewThreadSummaryPromise,
|
|
10077
|
+
statusSnapshotPromise,
|
|
10078
|
+
defaultBranchNamePromise
|
|
10079
|
+
]);
|
|
10080
|
+
if (!defaultBranchName) {
|
|
10081
|
+
throw new Error(
|
|
10082
|
+
"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."
|
|
10083
|
+
);
|
|
10084
|
+
}
|
|
10085
|
+
const checksStatus = statusSnapshot.ciState === "green" ? "passed" : statusSnapshot.ciState === "red" ? "failed" : "pending";
|
|
10086
|
+
const mergeable = resolveProjectPullRequestMergeable({
|
|
10087
|
+
checksStatus,
|
|
10088
|
+
reviewApprovals: reviewSummary.approvals,
|
|
10089
|
+
reviewChangesRequested: reviewSummary.changesRequested,
|
|
10090
|
+
unresolvedReviewThreads: reviewThreadSummary.unresolvedReviewThreads,
|
|
10091
|
+
githubMergeable: pullRequest.mergeable === true,
|
|
10092
|
+
baseBranch: pullRequest.base.ref,
|
|
10093
|
+
defaultBranchName
|
|
10094
|
+
});
|
|
10095
|
+
if (!mergeable) {
|
|
10096
|
+
throw new Error(
|
|
10097
|
+
"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."
|
|
10098
|
+
);
|
|
10099
|
+
}
|
|
9698
10100
|
const response = await octokit.rest.pulls.merge({
|
|
9699
10101
|
owner: scope.repository.owner,
|
|
9700
10102
|
repo: scope.repository.repo,
|
|
@@ -10472,20 +10874,28 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
10472
10874
|
for (const [issueNumber, linkedPullRequests] of warmedLinkedPullRequests.entries()) {
|
|
10473
10875
|
linkedPullRequestsByIssueNumber.set(issueNumber, linkedPullRequests);
|
|
10474
10876
|
}
|
|
10475
|
-
const
|
|
10877
|
+
const openLinkedPullRequestNumbersByRepository = /* @__PURE__ */ new Map();
|
|
10476
10878
|
for (const linkedPullRequests of warmedLinkedPullRequests.values()) {
|
|
10477
10879
|
for (const pullRequest of linkedPullRequests) {
|
|
10478
10880
|
if (pullRequest.state === "OPEN") {
|
|
10479
|
-
|
|
10881
|
+
const pullRequestRepository = requireRepositoryReference(pullRequest.repositoryUrl);
|
|
10882
|
+
const entry = openLinkedPullRequestNumbersByRepository.get(pullRequestRepository.url) ?? {
|
|
10883
|
+
repository: pullRequestRepository,
|
|
10884
|
+
numbers: /* @__PURE__ */ new Set()
|
|
10885
|
+
};
|
|
10886
|
+
entry.numbers.add(pullRequest.number);
|
|
10887
|
+
openLinkedPullRequestNumbersByRepository.set(pullRequestRepository.url, entry);
|
|
10480
10888
|
}
|
|
10481
10889
|
}
|
|
10482
10890
|
}
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10891
|
+
for (const entry of openLinkedPullRequestNumbersByRepository.values()) {
|
|
10892
|
+
await warmGitHubPullRequestStatusCache(
|
|
10893
|
+
octokit,
|
|
10894
|
+
entry.repository,
|
|
10895
|
+
entry.numbers,
|
|
10896
|
+
pullRequestStatusCache
|
|
10897
|
+
);
|
|
10898
|
+
}
|
|
10489
10899
|
await throwIfSyncCancelled();
|
|
10490
10900
|
} catch (error) {
|
|
10491
10901
|
if (error instanceof SyncCancellationError || isGitHubRateLimitError(error)) {
|
|
@@ -11274,6 +11684,7 @@ function registerGitHubAgentTools(ctx) {
|
|
|
11274
11684
|
].filter((warning) => warning !== null);
|
|
11275
11685
|
const snapshot = snapshotResult.status === "fulfilled" ? snapshotResult.value : {
|
|
11276
11686
|
number: target.pullRequestNumber,
|
|
11687
|
+
repositoryUrl: target.repository.url,
|
|
11277
11688
|
hasUnresolvedReviewThreads: false,
|
|
11278
11689
|
ciState: "unfinished"
|
|
11279
11690
|
};
|