@gitkraken/core-gitlens 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/dist/git/models/issue.d.ts +25 -2
  3. package/dist/git/models/issue.js +3 -1
  4. package/dist/git/models/issue.js.map +1 -1
  5. package/dist/git/models/pullRequest.d.ts +62 -7
  6. package/dist/git/models/pullRequest.js +5 -1
  7. package/dist/git/models/pullRequest.js.map +1 -1
  8. package/dist/git/utils/issue.utils.d.ts +4 -0
  9. package/dist/git/utils/issue.utils.js +4 -0
  10. package/dist/git/utils/issue.utils.js.map +1 -1
  11. package/dist/git/utils/pullRequest.utils.d.ts +4 -0
  12. package/dist/git/utils/pullRequest.utils.js +8 -0
  13. package/dist/git/utils/pullRequest.utils.js.map +1 -1
  14. package/dist/plus/git-github/api/github.d.ts +64 -4
  15. package/dist/plus/git-github/api/github.js +232 -15
  16. package/dist/plus/git-github/api/github.js.map +1 -1
  17. package/dist/plus/git-github/models.d.ts +48 -6
  18. package/dist/plus/git-github/models.js +11 -10
  19. package/dist/plus/git-github/models.js.map +1 -1
  20. package/dist/plus/integrations/fieldPresence.d.ts +75 -0
  21. package/dist/plus/integrations/fieldPresence.js +381 -0
  22. package/dist/plus/integrations/fieldPresence.js.map +1 -0
  23. package/dist/plus/integrations/index.d.ts +6 -4
  24. package/dist/plus/integrations/index.js +2 -1
  25. package/dist/plus/integrations/index.js.map +1 -1
  26. package/dist/plus/integrations/integrationService.d.ts +7 -3
  27. package/dist/plus/integrations/integrationService.js.map +1 -1
  28. package/dist/plus/integrations/manager.d.ts +56 -6
  29. package/dist/plus/integrations/models/gitHostIntegration.d.ts +103 -9
  30. package/dist/plus/integrations/models/gitHostIntegration.js +116 -5
  31. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  32. package/dist/plus/integrations/models/integration.d.ts +91 -4
  33. package/dist/plus/integrations/models/integration.js +56 -7
  34. package/dist/plus/integrations/models/integration.js.map +1 -1
  35. package/dist/plus/integrations/models/issuesIntegration.d.ts +44 -3
  36. package/dist/plus/integrations/models/issuesIntegration.js +51 -1
  37. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  38. package/dist/plus/integrations/providers/azure/azure.js +3 -3
  39. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  40. package/dist/plus/integrations/providers/azure/models.d.ts +36 -4
  41. package/dist/plus/integrations/providers/azure/models.js +118 -8
  42. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  43. package/dist/plus/integrations/providers/azureDevOps.d.ts +102 -5
  44. package/dist/plus/integrations/providers/azureDevOps.js +264 -45
  45. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  46. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +30 -6
  47. package/dist/plus/integrations/providers/azureDevOpsServer.js +82 -21
  48. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  49. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +21 -1
  50. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +74 -10
  51. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  52. package/dist/plus/integrations/providers/bitbucket/models.d.ts +40 -3
  53. package/dist/plus/integrations/providers/bitbucket/models.js +30 -7
  54. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  55. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +2 -6
  56. package/dist/plus/integrations/providers/bitbucket-server/models.js +1 -3
  57. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
  58. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +3 -1
  59. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +4 -1
  60. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  61. package/dist/plus/integrations/providers/bitbucket-server.d.ts +2 -2
  62. package/dist/plus/integrations/providers/bitbucket-server.js +7 -5
  63. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  64. package/dist/plus/integrations/providers/bitbucket.d.ts +22 -2
  65. package/dist/plus/integrations/providers/bitbucket.js +29 -6
  66. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  67. package/dist/plus/integrations/providers/github.d.ts +40 -3
  68. package/dist/plus/integrations/providers/github.js +133 -11
  69. package/dist/plus/integrations/providers/github.js.map +1 -1
  70. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +34 -1
  71. package/dist/plus/integrations/providers/gitlab/gitlab.js +118 -4
  72. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  73. package/dist/plus/integrations/providers/gitlab/models.d.ts +70 -5
  74. package/dist/plus/integrations/providers/gitlab/models.js +106 -13
  75. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  76. package/dist/plus/integrations/providers/gitlab.d.ts +31 -2
  77. package/dist/plus/integrations/providers/gitlab.js +48 -8
  78. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  79. package/dist/plus/integrations/providers/jira-server.d.ts +1 -0
  80. package/dist/plus/integrations/providers/jira-server.js +9 -6
  81. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  82. package/dist/plus/integrations/providers/jira.d.ts +20 -1
  83. package/dist/plus/integrations/providers/jira.js +101 -6
  84. package/dist/plus/integrations/providers/jira.js.map +1 -1
  85. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +79 -0
  86. package/dist/plus/integrations/providers/jiraIssueByKey.js +58 -7
  87. package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
  88. package/dist/plus/integrations/providers/linear.d.ts +19 -1
  89. package/dist/plus/integrations/providers/linear.js +97 -5
  90. package/dist/plus/integrations/providers/linear.js.map +1 -1
  91. package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +42 -0
  92. package/dist/plus/integrations/providers/linearIssuesEtag.js +94 -0
  93. package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -0
  94. package/dist/plus/integrations/providers/models.d.ts +51 -7
  95. package/dist/plus/integrations/providers/models.js +46 -17
  96. package/dist/plus/integrations/providers/models.js.map +1 -1
  97. package/dist/plus/integrations/providers/providerErrors.js +8 -1
  98. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  99. package/dist/plus/integrations/providers/providersApi.d.ts +62 -3
  100. package/dist/plus/integrations/providers/providersApi.js +145 -4
  101. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  102. package/dist/plus/integrations/providers/pullRequestReviews.d.ts +13 -0
  103. package/dist/plus/integrations/providers/pullRequestReviews.js +30 -6
  104. package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -1
  105. package/dist/plus/integrations/providers/trello.js +10 -7
  106. package/dist/plus/integrations/providers/trello.js.map +1 -1
  107. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +11 -0
  108. package/dist/plus/integrations/providers/utils/providerPaging.js +47 -1
  109. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  110. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  111. package/dist/plus/integrations/reads/batchEtags.d.ts +69 -0
  112. package/dist/plus/integrations/reads/batchEtags.js +114 -0
  113. package/dist/plus/integrations/reads/batchEtags.js.map +1 -0
  114. package/dist/plus/integrations/reads/counts.js +2 -2
  115. package/dist/plus/integrations/reads/counts.js.map +1 -1
  116. package/dist/plus/integrations/reads/currentAccount.js +2 -2
  117. package/dist/plus/integrations/reads/currentAccount.js.map +1 -1
  118. package/dist/plus/integrations/reads/drains.d.ts +12 -3
  119. package/dist/plus/integrations/reads/drains.js +29 -5
  120. package/dist/plus/integrations/reads/drains.js.map +1 -1
  121. package/dist/plus/integrations/reads/etag.d.ts +26 -0
  122. package/dist/plus/integrations/reads/etag.js +108 -0
  123. package/dist/plus/integrations/reads/etag.js.map +1 -0
  124. package/dist/plus/integrations/reads/hierarchy.js +3 -3
  125. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  126. package/dist/plus/integrations/reads/issueBatch.d.ts +47 -16
  127. package/dist/plus/integrations/reads/issueBatch.js +55 -87
  128. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  129. package/dist/plus/integrations/reads/issueTracker.d.ts +1 -1
  130. package/dist/plus/integrations/reads/issueTracker.js +4 -4
  131. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  132. package/dist/plus/integrations/reads/issues.d.ts +1 -1
  133. package/dist/plus/integrations/reads/issues.js +4 -4
  134. package/dist/plus/integrations/reads/issues.js.map +1 -1
  135. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +44 -6
  136. package/dist/plus/integrations/reads/pullRequestBatch.js +31 -34
  137. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -1
  138. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +5 -2
  139. package/dist/plus/integrations/reads/pullRequestBranches.js +4 -3
  140. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
  141. package/dist/plus/integrations/reads/pullRequests.js +8 -4
  142. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  143. package/dist/plus/integrations/reads/sweeps.js +8 -4
  144. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  145. package/dist/plus/integrations/reads/warnings.d.ts +23 -8
  146. package/dist/plus/integrations/reads/warnings.js +43 -19
  147. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  148. package/dist/plus/integrations/results.d.ts +12 -4
  149. package/dist/plus/integrations/results.js +2 -0
  150. package/dist/plus/integrations/results.js.map +1 -1
  151. package/docs/integrations.md +385 -23
  152. package/docs/kepler-read-api-parity.md +16 -2
  153. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pullRequest.utils.js","names":[],"sources":["../../../../git/src/utils/pullRequest.utils.ts"],"sourcesContent":["import type {\n\tPullRequest,\n\tPullRequestComparisonRefs,\n\tPullRequestRefs,\n\tPullRequestRepositoryIdentityDescriptor,\n\tPullRequestShape,\n\tPullRequestSortField,\n\tPullRequestSorting,\n\tPullRequestStackInfo,\n} from '../models/pullRequest.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/** How many pull requests a merge action affects — unstacked is always 1; a stacked merge lands either\n * just this layer and everything below it (`position`), or the whole stack (`wholeStack`). The one\n * source every merge-confirmation and merge-action label counts from, so they can't drift apart.\n * Takes only the two fields it needs (not the full {@link PullRequestStackInfo}) since callers on the\n * webview side carry narrower serialized stack shapes. */\nexport function getStackedMergeCount(\n\tstack: Pick<PullRequestStackInfo, 'position' | 'size'> | undefined,\n\toptions?: { wholeStack?: boolean },\n): number {\n\tif (stack == null) return 1;\n\treturn options?.wholeStack ? stack.size : stack.position;\n}\n\n/**\n * How each sort field is read off a {@link PullRequestShape}, for the filtered PR search, which MERGES its\n * relationship × state facets in the facade and so has to order the union itself instead of trusting the\n * per-facet server order. Only the fields the shape carries appear — the same rule as `getIssueComparator`, and\n * the reason {@link PullRequestSortField} is just these two.\n */\nconst pullRequestSortValues: Partial<\n\tRecord<PullRequestSortField, (pr: PullRequestShape) => number | Date | string | undefined>\n> = {\n\tcreated: pr => pr.createdDate,\n\tupdated: pr => pr.updatedDate,\n};\n\n/**\n * A comparator for one sort key over normalized pull requests, or `undefined` when the field isn't derivable\n * from a {@link PullRequestShape} — the signal that the key is only honorable on a SINGLE-origin read where the\n * provider already ordered the page. Missing values sort LAST in both directions (partitioned before any\n * arithmetic so two missing values compare equal, exactly as `getIssueComparator` does).\n *\n * Note it orders whatever it is handed. Sorting a page already capped at the result ceiling does not make it the\n * top N.\n */\nexport function getPullRequestComparator(\n\tsort: PullRequestSorting,\n): ((a: PullRequestShape, b: PullRequestShape) => number) | undefined {\n\tconst [field, direction] = sort.split(':') as [PullRequestSortField, 'asc' | 'desc'];\n\tconst getValue = pullRequestSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport interface PullRequestUrlIdentity<TProvider extends string = string> {\n\tprovider?: TProvider;\n\n\townerAndRepo?: string;\n\tprNumber: string;\n}\n\nexport function getComparisonRefsForPullRequest(repoPath: string, prRefs: PullRequestRefs): PullRequestComparisonRefs {\n\tconst refs: PullRequestComparisonRefs = {\n\t\trepoPath: repoPath,\n\t\tbase: { ref: prRefs.base.sha, label: `${prRefs.base.branch} (${shortenRevision(prRefs.base.sha)})` },\n\t\thead: { ref: prRefs.head.sha, label: prRefs.head.branch },\n\t};\n\treturn refs;\n}\n\nexport function getPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\tlet prNumber: string | undefined = undefined;\n\n\tlet match = search.match(/(?:\\/)(\\d+)/); // any number starting with \"/\"\n\tif (match != null) {\n\t\tprNumber = match[1];\n\t}\n\n\tif (prNumber == null) {\n\t\tmatch = search.match(/^#?(\\d+)$/); // just a number or with a leading \"#\"\n\t\tif (match != null) {\n\t\t\tprNumber = match[1];\n\t\t}\n\t}\n\n\treturn prNumber == null ? undefined : { ownerAndRepo: undefined, prNumber: prNumber, provider: undefined };\n}\n\n/** A pull request's display number from its url, or `undefined` for a url naming no pull request. Anchors\n * on the provider's pull request path segment (GitHub `pull`, Bitbucket `pull-requests`, GitLab\n * `merge_requests`, Azure `pullrequest`) so a digit-leading owner (`github.com/1Password/x/pull/123`)\n * can't win. */\nexport function getPullRequestNumberFromUrl(url: string): string | undefined {\n\t// No loose fallback: `getPullRequestIdentityFromMaybeUrl` scans for any `/<digits>`, which reads a bare\n\t// repository url like `github.com/1Password/sdk` as pull request #1. Callers that hold a real pull\n\t// request fall back to its id instead, and the one that asks whether a pasted url names a pull request\n\t// needs \"no\" for an answer.\n\treturn url.match(/(?:pull|pull-requests|merge_requests|pullrequest)\\/(\\d+)(?:\\b|\\/|$)/)?.[1];\n}\n\nexport function getRepositoryIdentityForPullRequest(\n\tpr: PullRequest,\n\theadRepo: boolean = true,\n): PullRequestRepositoryIdentityDescriptor {\n\tif (headRepo) {\n\t\treturn {\n\t\t\tremote: {\n\t\t\t\turl: pr.refs?.head?.url,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t},\n\t\t\tname: `${pr.refs?.head?.owner ?? pr.repository.owner}/${pr.refs?.head?.repo ?? pr.repository.repo}`,\n\t\t\tprovider: {\n\t\t\t\tid: pr.provider.id,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t\trepoDomain: pr.refs?.head?.owner ?? pr.repository.owner,\n\t\t\t\trepoName: pr.refs?.head?.repo ?? pr.repository.repo,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tremote: {\n\t\t\turl: pr.refs?.base?.url ?? pr.url,\n\t\t\tdomain: pr.provider.domain,\n\t\t},\n\t\tname: `${pr.refs?.base?.owner ?? pr.repository.owner}/${pr.refs?.base?.repo ?? pr.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: pr.provider.id,\n\t\t\tdomain: pr.provider.domain,\n\t\t\trepoDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t\trepoName: pr.refs?.base?.repo ?? pr.repository.repo,\n\t\t\trepoOwnerDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t},\n\t};\n}\n\nexport function isMaybeNonSpecificPullRequestSearchUrl(search: string): boolean {\n\treturn getPullRequestIdentityFromMaybeUrl(search) != null;\n}\n\nexport function serializePullRequest(value: PullRequest): PullRequestShape {\n\tconst serialized: PullRequestShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tnumber: value.number,\n\t\ttitle: value.title,\n\t\tbody: value.body,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tauthor: {\n\t\t\tid: value.author.id,\n\t\t\tname: value.author.name,\n\t\t\tusername: value.author.username,\n\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\turl: value.author.url,\n\t\t},\n\t\tstate: value.state,\n\t\tmergedDate: value.mergedDate,\n\t\tmergeableState: value.mergeableState,\n\t\trefs: value.refs\n\t\t\t? {\n\t\t\t\t\thead: {\n\t\t\t\t\t\texists: value.refs.head.exists,\n\t\t\t\t\t\towner: value.refs.head.owner,\n\t\t\t\t\t\trepo: value.refs.head.repo,\n\t\t\t\t\t\tsha: value.refs.head.sha,\n\t\t\t\t\t\tbranch: value.refs.head.branch,\n\t\t\t\t\t\turl: value.refs.head.url,\n\t\t\t\t\t\tcloneHttps: value.refs.head.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.head.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.head.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tbase: {\n\t\t\t\t\t\texists: value.refs.base.exists,\n\t\t\t\t\t\towner: value.refs.base.owner,\n\t\t\t\t\t\trepo: value.refs.base.repo,\n\t\t\t\t\t\tsha: value.refs.base.sha,\n\t\t\t\t\t\tbranch: value.refs.base.branch,\n\t\t\t\t\t\turl: value.refs.base.url,\n\t\t\t\t\t\tcloneHttps: value.refs.base.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.base.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.base.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tisCrossRepository: value.refs.isCrossRepository,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tisDraft: value.isDraft,\n\t\tadditions: value.additions,\n\t\tdeletions: value.deletions,\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\treviewDecision: value.reviewDecision,\n\t\treviewRequests: value.reviewRequests,\n\t\tlatestReviews: value.latestReviews,\n\t\tassignees: value.assignees,\n\t\tauthoredByMe: value.authoredByMe,\n\t\tproject: value.project\n\t\t\t? {\n\t\t\t\t\tid: value.project.id,\n\t\t\t\t\tname: value.project.name,\n\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tstack: value.stack\n\t\t\t? {\n\t\t\t\t\tid: value.stack.id,\n\t\t\t\t\tnumber: value.stack.number,\n\t\t\t\t\tsize: value.stack.size,\n\t\t\t\t\tposition: value.stack.position,\n\t\t\t\t\tbaseRef: value.stack.baseRef,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n\treturn serialized;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pullRequest.utils.js","names":[],"sources":["../../../../git/src/utils/pullRequest.utils.ts"],"sourcesContent":["import type {\n\tPullRequest,\n\tPullRequestComparisonRefs,\n\tPullRequestRefs,\n\tPullRequestRepositoryIdentityDescriptor,\n\tPullRequestShape,\n\tPullRequestSortField,\n\tPullRequestSorting,\n\tPullRequestStackInfo,\n} from '../models/pullRequest.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/** How many pull requests a merge action affects — unstacked is always 1; a stacked merge lands either\n * just this layer and everything below it (`position`), or the whole stack (`wholeStack`). The one\n * source every merge-confirmation and merge-action label counts from, so they can't drift apart.\n * Takes only the two fields it needs (not the full {@link PullRequestStackInfo}) since callers on the\n * webview side carry narrower serialized stack shapes. */\nexport function getStackedMergeCount(\n\tstack: Pick<PullRequestStackInfo, 'position' | 'size'> | undefined,\n\toptions?: { wholeStack?: boolean },\n): number {\n\tif (stack == null) return 1;\n\treturn options?.wholeStack ? stack.size : stack.position;\n}\n\n/**\n * How each sort field is read off a {@link PullRequestShape}, for the filtered PR search, which MERGES its\n * relationship × state facets in the facade and so has to order the union itself instead of trusting the\n * per-facet server order. Only the fields the shape carries appear — the same rule as `getIssueComparator`, and\n * the reason {@link PullRequestSortField} is just these two.\n */\nconst pullRequestSortValues: Partial<\n\tRecord<PullRequestSortField, (pr: PullRequestShape) => number | Date | string | undefined>\n> = {\n\tcreated: pr => pr.createdDate,\n\tupdated: pr => pr.updatedDate,\n};\n\n/**\n * A comparator for one sort key over normalized pull requests, or `undefined` when the field isn't derivable\n * from a {@link PullRequestShape} — the signal that the key is only honorable on a SINGLE-origin read where the\n * provider already ordered the page. Missing values sort LAST in both directions (partitioned before any\n * arithmetic so two missing values compare equal, exactly as `getIssueComparator` does).\n *\n * Note it orders whatever it is handed. Sorting a page already capped at the result ceiling does not make it the\n * top N.\n */\nexport function getPullRequestComparator(\n\tsort: PullRequestSorting,\n): ((a: PullRequestShape, b: PullRequestShape) => number) | undefined {\n\tconst [field, direction] = sort.split(':') as [PullRequestSortField, 'asc' | 'desc'];\n\tconst getValue = pullRequestSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport interface PullRequestUrlIdentity<TProvider extends string = string> {\n\tprovider?: TProvider;\n\n\townerAndRepo?: string;\n\tprNumber: string;\n}\n\nexport function getComparisonRefsForPullRequest(repoPath: string, prRefs: PullRequestRefs): PullRequestComparisonRefs {\n\tconst refs: PullRequestComparisonRefs = {\n\t\trepoPath: repoPath,\n\t\tbase: { ref: prRefs.base.sha, label: `${prRefs.base.branch} (${shortenRevision(prRefs.base.sha)})` },\n\t\thead: { ref: prRefs.head.sha, label: prRefs.head.branch },\n\t};\n\treturn refs;\n}\n\nexport function getPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\tlet prNumber: string | undefined = undefined;\n\n\tlet match = search.match(/(?:\\/)(\\d+)/); // any number starting with \"/\"\n\tif (match != null) {\n\t\tprNumber = match[1];\n\t}\n\n\tif (prNumber == null) {\n\t\tmatch = search.match(/^#?(\\d+)$/); // just a number or with a leading \"#\"\n\t\tif (match != null) {\n\t\t\tprNumber = match[1];\n\t\t}\n\t}\n\n\treturn prNumber == null ? undefined : { ownerAndRepo: undefined, prNumber: prNumber, provider: undefined };\n}\n\n/** A pull request's display number from its url, or `undefined` for a url naming no pull request. Anchors\n * on the provider's pull request path segment (GitHub `pull`, Bitbucket `pull-requests`, GitLab\n * `merge_requests`, Azure `pullrequest`) so a digit-leading owner (`github.com/1Password/x/pull/123`)\n * can't win. */\nexport function getPullRequestNumberFromUrl(url: string): string | undefined {\n\t// No loose fallback: `getPullRequestIdentityFromMaybeUrl` scans for any `/<digits>`, which reads a bare\n\t// repository url like `github.com/1Password/sdk` as pull request #1. Callers that hold a real pull\n\t// request fall back to its id instead, and the one that asks whether a pasted url names a pull request\n\t// needs \"no\" for an answer.\n\treturn url.match(/(?:pull|pull-requests|merge_requests|pullrequest)\\/(\\d+)(?:\\b|\\/|$)/)?.[1];\n}\n\nexport function getRepositoryIdentityForPullRequest(\n\tpr: PullRequest,\n\theadRepo: boolean = true,\n): PullRequestRepositoryIdentityDescriptor {\n\tif (headRepo) {\n\t\treturn {\n\t\t\tremote: {\n\t\t\t\turl: pr.refs?.head?.url,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t},\n\t\t\tname: `${pr.refs?.head?.owner ?? pr.repository.owner}/${pr.refs?.head?.repo ?? pr.repository.repo}`,\n\t\t\tprovider: {\n\t\t\t\tid: pr.provider.id,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t\trepoDomain: pr.refs?.head?.owner ?? pr.repository.owner,\n\t\t\t\trepoName: pr.refs?.head?.repo ?? pr.repository.repo,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tremote: {\n\t\t\turl: pr.refs?.base?.url ?? pr.url,\n\t\t\tdomain: pr.provider.domain,\n\t\t},\n\t\tname: `${pr.refs?.base?.owner ?? pr.repository.owner}/${pr.refs?.base?.repo ?? pr.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: pr.provider.id,\n\t\t\tdomain: pr.provider.domain,\n\t\t\trepoDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t\trepoName: pr.refs?.base?.repo ?? pr.repository.repo,\n\t\t\trepoOwnerDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t},\n\t};\n}\n\nexport function isMaybeNonSpecificPullRequestSearchUrl(search: string): boolean {\n\treturn getPullRequestIdentityFromMaybeUrl(search) != null;\n}\n\n/**\n * Deliberately leaves `projection` out: this copy drops `filesChanged`, `repository` and the class-only check rollup,\n * commit count and `viewerCanUpdate`, so a tag would have field presence report as fetched what the copy no longer has.\n */\nexport function serializePullRequest(value: PullRequest): PullRequestShape {\n\tconst serialized: PullRequestShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tnumber: value.number,\n\t\ttitle: value.title,\n\t\tbody: value.body,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tauthor: {\n\t\t\tid: value.author.id,\n\t\t\tname: value.author.name,\n\t\t\tusername: value.author.username,\n\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\turl: value.author.url,\n\t\t},\n\t\tstate: value.state,\n\t\tmergedDate: value.mergedDate,\n\t\tmergeableState: value.mergeableState,\n\t\trefs: value.refs\n\t\t\t? {\n\t\t\t\t\thead: {\n\t\t\t\t\t\texists: value.refs.head.exists,\n\t\t\t\t\t\towner: value.refs.head.owner,\n\t\t\t\t\t\trepo: value.refs.head.repo,\n\t\t\t\t\t\tsha: value.refs.head.sha,\n\t\t\t\t\t\tbranch: value.refs.head.branch,\n\t\t\t\t\t\turl: value.refs.head.url,\n\t\t\t\t\t\tcloneHttps: value.refs.head.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.head.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.head.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tbase: {\n\t\t\t\t\t\texists: value.refs.base.exists,\n\t\t\t\t\t\towner: value.refs.base.owner,\n\t\t\t\t\t\trepo: value.refs.base.repo,\n\t\t\t\t\t\tsha: value.refs.base.sha,\n\t\t\t\t\t\tbranch: value.refs.base.branch,\n\t\t\t\t\t\turl: value.refs.base.url,\n\t\t\t\t\t\tcloneHttps: value.refs.base.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.base.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.base.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tisCrossRepository: value.refs.isCrossRepository,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tisDraft: value.isDraft,\n\t\tadditions: value.additions,\n\t\tdeletions: value.deletions,\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\treviewDecision: value.reviewDecision,\n\t\treviewRequests: value.reviewRequests,\n\t\tlatestReviews: value.latestReviews,\n\t\tassignees: value.assignees,\n\t\tauthoredByMe: value.authoredByMe,\n\t\tviewer: value.viewer != null ? { id: value.viewer.id, username: value.viewer.username } : undefined,\n\t\tproject: value.project\n\t\t\t? {\n\t\t\t\t\tid: value.project.id,\n\t\t\t\t\tname: value.project.name,\n\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tstack: value.stack\n\t\t\t? {\n\t\t\t\t\tid: value.stack.id,\n\t\t\t\t\tnumber: value.stack.number,\n\t\t\t\t\tsize: value.stack.size,\n\t\t\t\t\tposition: value.stack.position,\n\t\t\t\t\tbaseRef: value.stack.baseRef,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n\treturn serialized;\n}\n"],"mappings":"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"}
@@ -11,7 +11,7 @@ import { Account, UnidentifiedAuthor } from "../../../git/models/author.js";
11
11
  import { DefaultBranch } from "../../../git/models/defaultBranch.js";
12
12
  import { RepositoryMetadata } from "../../../git/models/repositoryMetadata.js";
13
13
  import { GitHubApiConfig } from "./config.js";
14
- import { GitHubBlame, GitHubBranch, GitHubCommit, GitHubCommitRef, GitHubContributor, GitHubPagedResult, GitHubPullRequestState, GitHubSshSigningKey, GitHubTag } from "../models.js";
14
+ import { GitHubBlame, GitHubBranch, GitHubCommit, GitHubCommitRef, GitHubContributor, GitHubIssueEtagInclude, GitHubIssueEtagNode, GitHubPagedResult, GitHubPullRequestEtagInclude, GitHubPullRequestEtagNode, GitHubPullRequestState, GitHubSshSigningKey, GitHubTag } from "../models.js";
15
15
  import { GitHubTokenInfo } from "./token.js";
16
16
  import { Endpoints } from "@octokit/types";
17
17
  //#region ../plus/git-github/src/api/github.d.ts
@@ -270,6 +270,7 @@ export declare class GitHubApi {
270
270
  cursor?: string;
271
271
  hasMore: boolean;
272
272
  truncated: boolean;
273
+ totalCount?: number;
273
274
  }>;
274
275
  /**
275
276
  * The whole list rather than a page: this read has no cursor to hand back (its `IntegrationResult<T[]>` return
@@ -447,6 +448,37 @@ export declare class GitHubApi {
447
448
  baseUrl?: string;
448
449
  avatarSize?: number;
449
450
  }, cancellation?: AbortSignal): Promise<PromiseSettledResult<PullRequest | undefined>[]>;
451
+ /**
452
+ * The cheap check behind the batch reads' etags: {@link getPullRequestsBatch}'s aliased document, slot rules and
453
+ * failure handling, selecting only a pull request's change state ({@link gqlPullRequestEtagFragment}) — plus
454
+ * the selection of each of `etagIncludes` ({@link gqlPullRequestEtagIncludeFragments}). Returns the raw nodes:
455
+ * the caller maps them through the same conversions a full row takes, so both reads' etags agree.
456
+ *
457
+ * Declares no `$avatarSize`: nothing here selects an avatar, and GitHub rejects a document that declares a
458
+ * variable it never uses.
459
+ */
460
+ getPullRequestsEtagFieldsBatch(provider: Provider, token: GitHubTokenInfo, coordinates: readonly {
461
+ owner: string;
462
+ repo: string;
463
+ number: number;
464
+ }[], options?: {
465
+ baseUrl?: string;
466
+ etagIncludes?: readonly GitHubPullRequestEtagInclude[];
467
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<GitHubPullRequestEtagNode | undefined>[]>;
468
+ /**
469
+ * The issue twin of {@link getPullRequestsEtagFieldsBatch}: {@link getIssuesBatch}'s aliased document, slot
470
+ * rules and failure handling, selecting only an issue's change state ({@link gqlIssueEtagFragment}) — plus the
471
+ * selection of each of `etagIncludes` ({@link gqlIssueEtagIncludeFragments}). Returns the raw nodes, and declares
472
+ * no `$avatarSize`, for the same reasons.
473
+ */
474
+ getIssuesEtagFieldsBatch(provider: Provider, token: GitHubTokenInfo, coordinates: readonly {
475
+ owner: string;
476
+ repo: string;
477
+ number: number;
478
+ }[], options?: {
479
+ baseUrl?: string;
480
+ etagIncludes?: readonly GitHubIssueEtagInclude[];
481
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<GitHubIssueEtagNode | undefined>[]>;
450
482
  /**
451
483
  * Finds, for several branches in one request, every pull request whose head is that branch — in any state,
452
484
  * most recently updated first, up to `limit` per branch. Each target names the BASE repository the pull
@@ -460,9 +492,12 @@ export declare class GitHubApi {
460
492
  *
461
493
  * `headRefName` matches every fork's branch of that name too, so rows are kept only when their head
462
494
  * repository is the base repository itself (`headOwner` omitted) or a fork owned by `headOwner` — otherwise
463
- * a `main` in the base repository would claim every fork's `main`. That filter runs after the server's
464
- * `limit`, so `truncated` is set whenever the server matched more rows than it returned, since any of the
465
- * unfetched ones might have passed it.
495
+ * a `main` in the base repository would claim every fork's `main`. The fork is matched by
496
+ * `headRepositoryOwner`, which GitHub keeps after the fork is deleted, so a deleted fork's pull request still
497
+ * matches its old owner. That filter runs after the server's `limit`, so `truncated` is set whenever the server
498
+ * matched more rows than it returned, since any of the unfetched ones might have passed it;
499
+ * {@link getPullRequestNumbersForBranch} settles such a target, though it can't see a deleted fork's pull
500
+ * request, so its caller keeps the rows matched here as well.
466
501
  *
467
502
  * Returns POSITIONALLY, with the same per-alias rules as {@link getPullRequestsBatch}: a missing base
468
503
  * repository (NOT_FOUND on a null repository) is a PROVEN "none" — an empty list — while any other error on
@@ -481,6 +516,31 @@ export declare class GitHubApi {
481
516
  pullRequests: PullRequest[];
482
517
  truncated: boolean;
483
518
  }>[]>;
519
+ /**
520
+ * The numbers of the pull requests into `owner/repo` whose head is `branch` in the repository `headOwner` owns
521
+ * — the base repository's owner when omitted — in any state, most recently updated first, at most `limit`.
522
+ * Only the numbers, so a caller resolves the rows through the same read as its by-number lookups.
523
+ *
524
+ * REST, because its `head` filter matches the head repository's OWNER and the branch on the server, before the
525
+ * page is cut, where GraphQL's `headRefName` matches the name across every fork: this settles a target
526
+ * {@link getPullRequestsForBranches} reported `truncated` only because other forks share its branch name.
527
+ * Keyed on the ref NAME like that read, so a merged pull request whose branch was deleted still matches; one
528
+ * whose fork was deleted has no head repository and matches nothing, so this can't prove such a pull request
529
+ * absent.
530
+ *
531
+ * Strict: an empty list means GitHub answered, and any failure throws, a 404 included — the caller has already
532
+ * read the base repository, so a missing one here proves nothing. A server error or timeout is left to the
533
+ * calling batch to report once (see `reportRequestFailure`), and an authentication failure prompts nothing,
534
+ * since one target's refusal isn't the credential's.
535
+ */
536
+ getPullRequestNumbersForBranch(provider: Provider, token: GitHubTokenInfo, owner: string, repo: string, branch: string, options: {
537
+ baseUrl?: string;
538
+ headOwner?: string;
539
+ limit: number;
540
+ }, cancellation?: AbortSignal): Promise<{
541
+ numbers: number[];
542
+ truncated: boolean;
543
+ }>;
484
544
  /**
485
545
  * The PR twin of {@link countIssues}: counts pull requests for several scopes in ONE request via aliased
486
546
  * `search` fields selecting only `issueCount` with `first: 0`. Same positional/undefined contract as the issue
@@ -303,6 +303,59 @@ repository {
303
303
  }
304
304
  `;
305
305
  /**
306
+ * The change state a pull request's etag reads (see {@link GitHubPullRequestEtagNode}). Every selection is copied
307
+ * from {@link gqlPullRequestFragment} — same arguments, same nesting — so the cheap read sees exactly the values
308
+ * the full read maps; only a requested reviewer drops its avatar and URL, since its nullness is all the etag reads.
309
+ * `merged` is not needed: `state` already reads `MERGED`.
310
+ */
311
+ const gqlPullRequestEtagFragment = `
312
+ id
313
+ number
314
+ state
315
+ isDraft
316
+ updatedAt
317
+ headRefOid
318
+ `;
319
+ /**
320
+ * The selection each {@link GitHubPullRequestEtagInclude} adds to {@link gqlPullRequestEtagFragment}, copied from
321
+ * {@link gqlPullRequestFragment} like it.
322
+ */
323
+ const gqlPullRequestEtagIncludeFragments = {
324
+ mergeable: `
325
+ mergeable
326
+ `,
327
+ reviewDecision: `
328
+ reviewDecision
329
+ `,
330
+ checks: `
331
+ commits(last: 1) {
332
+ nodes {
333
+ commit {
334
+ statusCheckRollup {
335
+ state
336
+ }
337
+ }
338
+ }
339
+ }
340
+ `
341
+ };
342
+ /** The change state an issue's etag reads (see {@link GitHubIssueEtagNode}). */
343
+ const gqlIssueEtagFragment = `
344
+ id
345
+ number
346
+ state
347
+ updatedAt
348
+ `;
349
+ /**
350
+ * The selection each {@link GitHubIssueEtagInclude} adds to {@link gqlIssueEtagFragment}, copied from
351
+ * {@link gqIssueFragment} like it.
352
+ */
353
+ const gqlIssueEtagIncludeFragments = { reactions: `
354
+ reactions(content: THUMBS_UP) {
355
+ totalCount
356
+ }
357
+ ` };
358
+ /**
306
359
  * What an alias's own errors say about its slot in an {@link AliasedGraphqlResult}: `'absent'` only when its node
307
360
  * is null and every error on it is NOT_FOUND; a rejection when a node arrived with an error, or on any other error
308
361
  * (even a NOT_FOUND nested under the node), since neither is trustworthy; `undefined` when the alias has no errors.
@@ -571,7 +624,7 @@ var GitHubApi = class {
571
624
  number
572
625
  }, scope);
573
626
  if (rsp?.repository?.issue == null) return void 0;
574
- return fromGitHubIssue(rsp.repository.issue, provider);
627
+ return fromGitHubIssue(rsp.repository.issue, provider, issueProjection("point", options));
575
628
  } catch (ex) {
576
629
  if (ex instanceof RequestNotFoundError) return void 0;
577
630
  throw this.handleException(ex, provider, scope);
@@ -600,7 +653,7 @@ var GitHubApi = class {
600
653
  number
601
654
  }, scope);
602
655
  if (rsp?.repository?.pullRequest == null) return void 0;
603
- return fromGitHubPullRequestLite(rsp.repository.pullRequest, provider);
656
+ return fromGitHubPullRequestLite(rsp.repository.pullRequest, provider, "point");
604
657
  } catch (ex) {
605
658
  if (ex instanceof RequestNotFoundError) return void 0;
606
659
  throw this.handleException(ex, provider, scope);
@@ -637,7 +690,7 @@ var GitHubApi = class {
637
690
  }, scope))?.repository?.ref?.associatedPullRequests?.nodes?.filter((pr) => pr != null && (!pr.repository.isFork || pr.repository.owner.login === owner));
638
691
  if (prs == null || prs.length === 0) return void 0;
639
692
  if (prs.length > 1) prs.sort((a, b) => (a.repository.owner.login === owner ? -1 : 1) - (b.repository.owner.login === owner ? -1 : 1) || (a.state === "OPEN" ? -1 : 1) - (b.state === "OPEN" ? -1 : 1) || new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
640
- return fromGitHubPullRequestLite(prs[0], provider);
693
+ return fromGitHubPullRequestLite(prs[0], provider, "point");
641
694
  } catch (ex) {
642
695
  if (ex instanceof RequestNotFoundError) return void 0;
643
696
  throw this.handleException(ex, provider, scope);
@@ -674,7 +727,7 @@ var GitHubApi = class {
674
727
  }, scope, cancellation))?.repository?.object?.associatedPullRequests?.nodes?.filter((pr) => pr != null && (!pr.repository.isFork || pr.repository.owner.login === owner));
675
728
  if (prs == null || prs.length === 0) return void 0;
676
729
  if (prs.length > 1) prs.sort((a, b) => (a.repository.owner.login === owner ? -1 : 1) - (b.repository.owner.login === owner ? -1 : 1) || (a.state === "MERGED" ? -1 : 1) - (b.state === "MERGED" ? -1 : 1) || new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
677
- return fromGitHubPullRequestLite(prs[0], provider);
730
+ return fromGitHubPullRequestLite(prs[0], provider, "point");
678
731
  } catch (ex) {
679
732
  if (ex instanceof RequestNotFoundError) return void 0;
680
733
  throw this.handleException(ex, provider, scope);
@@ -2040,10 +2093,11 @@ var GitHubApi = class {
2040
2093
  truncated: false
2041
2094
  };
2042
2095
  return {
2043
- values: rsp.search.nodes.map((pr) => options?.summary ? fromGitHubPullRequestLite(pr, provider) : fromGitHubPullRequest(pr, provider)),
2096
+ values: rsp.search.nodes.map((pr) => options?.summary ? fromGitHubPullRequestLite(pr, provider, "search-summary") : fromGitHubPullRequest(pr, provider, "search")),
2044
2097
  cursor: rsp.search.pageInfo.endCursor ?? void 0,
2045
2098
  hasMore: rsp.search.pageInfo.hasNextPage,
2046
- truncated: rsp.search.issueCount > 1e3 && !rsp.search.pageInfo.hasNextPage
2099
+ truncated: rsp.search.issueCount > 1e3 && !rsp.search.pageInfo.hasNextPage,
2100
+ totalCount: rsp.search.issueCount
2047
2101
  };
2048
2102
  } catch (ex) {
2049
2103
  throw this.handleException(ex, provider, scope, options?.silent);
@@ -2124,7 +2178,8 @@ var GitHubApi = class {
2124
2178
  cursor: options?.cursor,
2125
2179
  pageSize: options?.pageSize,
2126
2180
  sort: options?.sort,
2127
- legacySort: unsortedCursorSort
2181
+ legacySort: unsortedCursorSort,
2182
+ projection: "account"
2128
2183
  }, cancellation);
2129
2184
  }
2130
2185
  /**
@@ -2176,7 +2231,8 @@ var GitHubApi = class {
2176
2231
  cursor: options?.cursor,
2177
2232
  pageSize: options?.pageSize,
2178
2233
  sort,
2179
- legacySort: defaultIssueSort
2234
+ legacySort: defaultIssueSort,
2235
+ projection: "search"
2180
2236
  }, cancellation);
2181
2237
  }
2182
2238
  /**
@@ -2295,7 +2351,7 @@ var GitHubApi = class {
2295
2351
  try {
2296
2352
  return {
2297
2353
  status: "fulfilled",
2298
- value: fromGitHubIssue(node, provider)
2354
+ value: fromGitHubIssue(node, provider, issueProjection("batch", options))
2299
2355
  };
2300
2356
  } catch (ex) {
2301
2357
  scope?.warn(`failed to map issue; ${c.owner}/${c.repo}#${c.number}, ex=${ex}`);
@@ -2383,6 +2439,103 @@ var GitHubApi = class {
2383
2439
  }
2384
2440
  }
2385
2441
  /**
2442
+ * The cheap check behind the batch reads' etags: {@link getPullRequestsBatch}'s aliased document, slot rules and
2443
+ * failure handling, selecting only a pull request's change state ({@link gqlPullRequestEtagFragment}) — plus
2444
+ * the selection of each of `etagIncludes` ({@link gqlPullRequestEtagIncludeFragments}). Returns the raw nodes:
2445
+ * the caller maps them through the same conversions a full row takes, so both reads' etags agree.
2446
+ *
2447
+ * Declares no `$avatarSize`: nothing here selects an avatar, and GitHub rejects a document that declares a
2448
+ * variable it never uses.
2449
+ */
2450
+ async getPullRequestsEtagFieldsBatch(provider, token, coordinates, options, cancellation) {
2451
+ const scope = getScopedLogger();
2452
+ if (coordinates.length === 0) return [];
2453
+ const includeFragments = Array.from(new Set(options?.etagIncludes), (include) => gqlPullRequestEtagIncludeFragments[include]);
2454
+ const query = `query getPullRequestsEtagFieldsBatch(
2455
+ ${coordinates.map((_, i) => `$o${i}: String!\n\t\t\t\t$n${i}: String!\n\t\t\t\t$k${i}: Int!`).join("\n ")}
2456
+ ) {
2457
+ ${coordinates.map((_, i) => `p${i}: repository(owner: $o${i}, name: $n${i}) {
2458
+ pullRequest(number: $k${i}) {
2459
+ ${gqlPullRequestEtagFragment}
2460
+ ${includeFragments.join("")}
2461
+ }
2462
+ }`).join("\n ")}
2463
+ }`;
2464
+ const variables = { baseUrl: options?.baseUrl };
2465
+ coordinates.forEach((c, i) => {
2466
+ variables[`o${i}`] = c.owner;
2467
+ variables[`n${i}`] = c.repo;
2468
+ variables[`k${i}`] = c.number;
2469
+ });
2470
+ try {
2471
+ const rsp = await this.graphql(provider, token, query, variables, scope, cancellation, "aliased");
2472
+ if (rsp?.data == null) throw new Error("GitHub returned no data for the pull request etag batch");
2473
+ return coordinates.map((_, i) => {
2474
+ const alias = `p${i}`;
2475
+ const node = rsp.data[alias]?.pullRequest;
2476
+ const verdict = getAliasErrorVerdict(rsp.errors, alias, node);
2477
+ if (verdict === "absent") return {
2478
+ status: "fulfilled",
2479
+ value: void 0
2480
+ };
2481
+ if (verdict != null) return verdict;
2482
+ return {
2483
+ status: "fulfilled",
2484
+ value: node ?? void 0
2485
+ };
2486
+ });
2487
+ } catch (ex) {
2488
+ throw this.handleException(ex, provider, scope);
2489
+ }
2490
+ }
2491
+ /**
2492
+ * The issue twin of {@link getPullRequestsEtagFieldsBatch}: {@link getIssuesBatch}'s aliased document, slot
2493
+ * rules and failure handling, selecting only an issue's change state ({@link gqlIssueEtagFragment}) — plus the
2494
+ * selection of each of `etagIncludes` ({@link gqlIssueEtagIncludeFragments}). Returns the raw nodes, and declares
2495
+ * no `$avatarSize`, for the same reasons.
2496
+ */
2497
+ async getIssuesEtagFieldsBatch(provider, token, coordinates, options, cancellation) {
2498
+ const scope = getScopedLogger();
2499
+ if (coordinates.length === 0) return [];
2500
+ const includeFragments = Array.from(new Set(options?.etagIncludes), (include) => gqlIssueEtagIncludeFragments[include]);
2501
+ const query = `query getIssuesEtagFieldsBatch(
2502
+ ${coordinates.map((_, i) => `$o${i}: String!\n\t\t\t\t$n${i}: String!\n\t\t\t\t$k${i}: Int!`).join("\n ")}
2503
+ ) {
2504
+ ${coordinates.map((_, i) => `i${i}: repository(owner: $o${i}, name: $n${i}) {
2505
+ issue(number: $k${i}) {
2506
+ ${gqlIssueEtagFragment}
2507
+ ${includeFragments.join("")}
2508
+ }
2509
+ }`).join("\n ")}
2510
+ }`;
2511
+ const variables = { baseUrl: options?.baseUrl };
2512
+ coordinates.forEach((c, i) => {
2513
+ variables[`o${i}`] = c.owner;
2514
+ variables[`n${i}`] = c.repo;
2515
+ variables[`k${i}`] = c.number;
2516
+ });
2517
+ try {
2518
+ const rsp = await this.graphql(provider, token, query, variables, scope, cancellation, "aliased");
2519
+ if (rsp?.data == null) throw new Error("GitHub returned no data for the issue etag batch");
2520
+ return coordinates.map((_, i) => {
2521
+ const alias = `i${i}`;
2522
+ const node = rsp.data[alias]?.issue;
2523
+ const verdict = getAliasErrorVerdict(rsp.errors, alias, node);
2524
+ if (verdict === "absent") return {
2525
+ status: "fulfilled",
2526
+ value: void 0
2527
+ };
2528
+ if (verdict != null) return verdict;
2529
+ return {
2530
+ status: "fulfilled",
2531
+ value: node ?? void 0
2532
+ };
2533
+ });
2534
+ } catch (ex) {
2535
+ throw this.handleException(ex, provider, scope);
2536
+ }
2537
+ }
2538
+ /**
2386
2539
  * Finds, for several branches in one request, every pull request whose head is that branch — in any state,
2387
2540
  * most recently updated first, up to `limit` per branch. Each target names the BASE repository the pull
2388
2541
  * requests are opened against, the head branch's short name and, for a branch that lives in a fork,
@@ -2395,9 +2548,12 @@ var GitHubApi = class {
2395
2548
  *
2396
2549
  * `headRefName` matches every fork's branch of that name too, so rows are kept only when their head
2397
2550
  * repository is the base repository itself (`headOwner` omitted) or a fork owned by `headOwner` — otherwise
2398
- * a `main` in the base repository would claim every fork's `main`. That filter runs after the server's
2399
- * `limit`, so `truncated` is set whenever the server matched more rows than it returned, since any of the
2400
- * unfetched ones might have passed it.
2551
+ * a `main` in the base repository would claim every fork's `main`. The fork is matched by
2552
+ * `headRepositoryOwner`, which GitHub keeps after the fork is deleted, so a deleted fork's pull request still
2553
+ * matches its old owner. That filter runs after the server's `limit`, so `truncated` is set whenever the server
2554
+ * matched more rows than it returned, since any of the unfetched ones might have passed it;
2555
+ * {@link getPullRequestNumbersForBranch} settles such a target, though it can't see a deleted fork's pull
2556
+ * request, so its caller keeps the rows matched here as well.
2401
2557
  *
2402
2558
  * Returns POSITIONALLY, with the same per-alias rules as {@link getPullRequestsBatch}: a missing base
2403
2559
  * repository (NOT_FOUND on a null repository) is a PROVEN "none" — an empty list — while any other error on
@@ -2478,6 +2634,45 @@ var GitHubApi = class {
2478
2634
  }
2479
2635
  }
2480
2636
  /**
2637
+ * The numbers of the pull requests into `owner/repo` whose head is `branch` in the repository `headOwner` owns
2638
+ * — the base repository's owner when omitted — in any state, most recently updated first, at most `limit`.
2639
+ * Only the numbers, so a caller resolves the rows through the same read as its by-number lookups.
2640
+ *
2641
+ * REST, because its `head` filter matches the head repository's OWNER and the branch on the server, before the
2642
+ * page is cut, where GraphQL's `headRefName` matches the name across every fork: this settles a target
2643
+ * {@link getPullRequestsForBranches} reported `truncated` only because other forks share its branch name.
2644
+ * Keyed on the ref NAME like that read, so a merged pull request whose branch was deleted still matches; one
2645
+ * whose fork was deleted has no head repository and matches nothing, so this can't prove such a pull request
2646
+ * absent.
2647
+ *
2648
+ * Strict: an empty list means GitHub answered, and any failure throws, a 404 included — the caller has already
2649
+ * read the base repository, so a missing one here proves nothing. A server error or timeout is left to the
2650
+ * calling batch to report once (see `reportRequestFailure`), and an authentication failure prompts nothing,
2651
+ * since one target's refusal isn't the credential's.
2652
+ */
2653
+ async getPullRequestNumbersForBranch(provider, token, owner, repo, branch, options, cancellation) {
2654
+ const scope = getScopedLogger();
2655
+ try {
2656
+ const rsp = await this.request(provider, token, "GET /repos/{owner}/{repo}/pulls", {
2657
+ owner,
2658
+ repo,
2659
+ head: `${options.headOwner ?? owner}:${branch}`,
2660
+ state: "all",
2661
+ sort: "updated",
2662
+ direction: "desc",
2663
+ per_page: options.limit + 1,
2664
+ baseUrl: options.baseUrl
2665
+ }, scope, cancellation, true);
2666
+ if (rsp?.data == null) throw new Error("GitHub returned no data for the pull requests by head");
2667
+ return {
2668
+ numbers: rsp.data.slice(0, options.limit).map((pr) => pr.number),
2669
+ truncated: rsp.data.length > options.limit
2670
+ };
2671
+ } catch (ex) {
2672
+ throw this.handleException(ex, provider, scope, true);
2673
+ }
2674
+ }
2675
+ /**
2481
2676
  * The PR twin of {@link countIssues}: counts pull requests for several scopes in ONE request via aliased
2482
2677
  * `search` fields selecting only `issueCount` with `first: 0`. Same positional/undefined contract as the issue
2483
2678
  * count.
@@ -2623,7 +2818,7 @@ var GitHubApi = class {
2623
2818
  for (const node of rsp[s.alias]?.nodes ?? []) {
2624
2819
  if (node?.id == null) continue;
2625
2820
  try {
2626
- const issue = fromGitHubIssue(node, provider);
2821
+ const issue = fromGitHubIssue(node, provider, issueProjection(options.projection, options));
2627
2822
  if (seen?.has(issue.url) !== true) mapped.push(issue);
2628
2823
  } catch (ex) {
2629
2824
  scope?.warn(`skipped unmappable issue; id=${node.id}, url=${node.url}, ex=${ex}`);
@@ -2798,7 +2993,7 @@ var GitHubApi = class {
2798
2993
  for (const facet of activeFacets) for (const node of rsp[facet.alias]?.nodes ?? []) {
2799
2994
  if (node?.id == null) continue;
2800
2995
  try {
2801
- pullRequests.push(options?.summary ? fromGitHubPullRequestLite(node, provider) : fromGitHubPullRequest(node, provider));
2996
+ pullRequests.push(options?.summary ? fromGitHubPullRequestLite(node, provider, "search-summary") : fromGitHubPullRequest(node, provider, "search"));
2802
2997
  } catch (ex) {
2803
2998
  scope?.warn(`skipped unmappable pull request; id=${node.id}, url=${node.url}, ex=${ex}`);
2804
2999
  }
@@ -2900,7 +3095,7 @@ var GitHubApi = class {
2900
3095
  const rsp = await this.graphql(provider, token, query, variables, scope, cancellation);
2901
3096
  if (rsp == null) return [];
2902
3097
  const results = [];
2903
- for (const { alias } of stateSearches) for (const node of rsp[alias]?.nodes ?? []) results.push(fromGitHubPullRequest(node, provider));
3098
+ for (const { alias } of stateSearches) for (const node of rsp[alias]?.nodes ?? []) results.push(fromGitHubPullRequest(node, provider, "text-search"));
2904
3099
  return [...uniqueBy(filterPullRequestsBySearchState(results, include), (pr) => pr.url, (original, _current) => original)].slice(0, pageSize);
2905
3100
  } catch (ex) {
2906
3101
  throw this.handleException(ex, provider, scope);
@@ -3255,10 +3450,25 @@ __decorate([trace({ args: (provider, token) => ({
3255
3450
  provider: provider.name,
3256
3451
  token: `<token:${token.microHash}>`
3257
3452
  }) })], GitHubApi.prototype, "getPullRequestsBatch", null);
3453
+ __decorate([trace({ args: (provider, token) => ({
3454
+ provider: provider.name,
3455
+ token: `<token:${token.microHash}>`
3456
+ }) })], GitHubApi.prototype, "getPullRequestsEtagFieldsBatch", null);
3457
+ __decorate([trace({ args: (provider, token) => ({
3458
+ provider: provider.name,
3459
+ token: `<token:${token.microHash}>`
3460
+ }) })], GitHubApi.prototype, "getIssuesEtagFieldsBatch", null);
3258
3461
  __decorate([trace({ args: (provider, token) => ({
3259
3462
  provider: provider.name,
3260
3463
  token: `<token:${token.microHash}>`
3261
3464
  }) })], GitHubApi.prototype, "getPullRequestsForBranches", null);
3465
+ __decorate([trace({ args: (provider, token, owner, repo, branch) => ({
3466
+ provider: provider.name,
3467
+ token: `<token:${token.microHash}>`,
3468
+ owner,
3469
+ repo,
3470
+ branch
3471
+ }) })], GitHubApi.prototype, "getPullRequestNumbersForBranch", null);
3262
3472
  __decorate([trace({ args: (provider, token) => ({
3263
3473
  provider: provider.name,
3264
3474
  token: `<token:${token.microHash}>`
@@ -3291,6 +3501,13 @@ __decorate([trace({ args: (provider, token, nodeId, expectedSourceSha) => ({
3291
3501
  nodeId,
3292
3502
  expectedSourceSha
3293
3503
  }) })], GitHubApi.prototype, "mergePullRequest", null);
3504
+ /**
3505
+ * Every issue read's presence table assumes the body was selected, so a read without `includeBody` is left
3506
+ * untagged (unknown) rather than claiming a description it never fetched.
3507
+ */
3508
+ function issueProjection(projection, options) {
3509
+ return options?.includeBody ? projection : void 0;
3510
+ }
3294
3511
  function isGitHubDotCom(options) {
3295
3512
  return options?.baseUrl == null || options.baseUrl === "https://api.github.com";
3296
3513
  }