@gitkraken/core-gitlens 0.9.4 → 0.9.5

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 (154) hide show
  1. package/CHANGELOG.md +22 -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 +55 -5
  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/issueSorts.d.ts +1 -0
  80. package/dist/plus/integrations/providers/jira-server.d.ts +1 -0
  81. package/dist/plus/integrations/providers/jira-server.js +9 -6
  82. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  83. package/dist/plus/integrations/providers/jira.d.ts +20 -1
  84. package/dist/plus/integrations/providers/jira.js +101 -6
  85. package/dist/plus/integrations/providers/jira.js.map +1 -1
  86. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +79 -0
  87. package/dist/plus/integrations/providers/jiraIssueByKey.js +58 -7
  88. package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
  89. package/dist/plus/integrations/providers/linear.d.ts +19 -1
  90. package/dist/plus/integrations/providers/linear.js +97 -5
  91. package/dist/plus/integrations/providers/linear.js.map +1 -1
  92. package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +42 -0
  93. package/dist/plus/integrations/providers/linearIssuesEtag.js +94 -0
  94. package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -0
  95. package/dist/plus/integrations/providers/models.d.ts +51 -7
  96. package/dist/plus/integrations/providers/models.js +45 -16
  97. package/dist/plus/integrations/providers/models.js.map +1 -1
  98. package/dist/plus/integrations/providers/providerErrors.js +8 -1
  99. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  100. package/dist/plus/integrations/providers/providersApi.d.ts +62 -3
  101. package/dist/plus/integrations/providers/providersApi.js +145 -4
  102. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  103. package/dist/plus/integrations/providers/pullRequestReviews.d.ts +13 -0
  104. package/dist/plus/integrations/providers/pullRequestReviews.js +30 -6
  105. package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -1
  106. package/dist/plus/integrations/providers/trello.js +10 -7
  107. package/dist/plus/integrations/providers/trello.js.map +1 -1
  108. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +11 -0
  109. package/dist/plus/integrations/providers/utils/providerPaging.js +47 -1
  110. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  111. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  112. package/dist/plus/integrations/reads/batchEtags.d.ts +69 -0
  113. package/dist/plus/integrations/reads/batchEtags.js +114 -0
  114. package/dist/plus/integrations/reads/batchEtags.js.map +1 -0
  115. package/dist/plus/integrations/reads/counts.js +2 -2
  116. package/dist/plus/integrations/reads/counts.js.map +1 -1
  117. package/dist/plus/integrations/reads/currentAccount.js +2 -2
  118. package/dist/plus/integrations/reads/currentAccount.js.map +1 -1
  119. package/dist/plus/integrations/reads/drains.d.ts +13 -3
  120. package/dist/plus/integrations/reads/drains.js +29 -5
  121. package/dist/plus/integrations/reads/drains.js.map +1 -1
  122. package/dist/plus/integrations/reads/etag.d.ts +26 -0
  123. package/dist/plus/integrations/reads/etag.js +108 -0
  124. package/dist/plus/integrations/reads/etag.js.map +1 -0
  125. package/dist/plus/integrations/reads/hierarchy.js +3 -3
  126. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  127. package/dist/plus/integrations/reads/issueBatch.d.ts +47 -16
  128. package/dist/plus/integrations/reads/issueBatch.js +55 -87
  129. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  130. package/dist/plus/integrations/reads/issueTracker.d.ts +1 -1
  131. package/dist/plus/integrations/reads/issueTracker.js +4 -4
  132. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  133. package/dist/plus/integrations/reads/issues.d.ts +1 -1
  134. package/dist/plus/integrations/reads/issues.js +4 -4
  135. package/dist/plus/integrations/reads/issues.js.map +1 -1
  136. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +44 -6
  137. package/dist/plus/integrations/reads/pullRequestBatch.js +31 -34
  138. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -1
  139. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +5 -2
  140. package/dist/plus/integrations/reads/pullRequestBranches.js +4 -3
  141. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
  142. package/dist/plus/integrations/reads/pullRequests.js +8 -4
  143. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  144. package/dist/plus/integrations/reads/sweeps.js +8 -4
  145. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  146. package/dist/plus/integrations/reads/warnings.d.ts +23 -8
  147. package/dist/plus/integrations/reads/warnings.js +43 -19
  148. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  149. package/dist/plus/integrations/results.d.ts +12 -4
  150. package/dist/plus/integrations/results.js +2 -0
  151. package/dist/plus/integrations/results.js.map +1 -1
  152. package/docs/integrations.md +385 -23
  153. package/docs/kepler-read-api-parity.md +16 -2
  154. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  import { Provider } from "../../../../git/models/remoteProvider.js";
2
2
  import { IssueOrPullRequestState } from "../../../../git/models/issueOrPullRequest.js";
3
- import { PullRequest } from "../../../../git/models/pullRequest.js";
4
- import { Integration } from "../../models/integration.js";
3
+ import { PullRequest, PullRequestProjection } from "../../../../git/models/pullRequest.js";
5
4
  import { ProviderPullRequest } from "../models.js";
5
+ import { Integration, IssueEtagFields, IssueEtagInclude, PullRequestEtagFields, PullRequestEtagInclude } from "../../models/integration.js";
6
6
  //#region ../plus/integrations/src/providers/gitlab/models.d.ts
7
7
  export interface GitLabUser {
8
8
  id: number;
@@ -119,7 +119,7 @@ export interface GitLabMergeRequestREST {
119
119
  export declare function fromGitLabMergeRequestREST(pr: GitLabMergeRequestREST, provider: Provider, repo: {
120
120
  owner: string;
121
121
  repo: string;
122
- }): PullRequest;
122
+ }, projection?: PullRequestProjection): PullRequest;
123
123
  export interface GitLabProjectREST {
124
124
  namespace: {
125
125
  path: string;
@@ -134,8 +134,73 @@ export interface GitLabProjectREST {
134
134
  path: string;
135
135
  };
136
136
  }
137
- export declare function fromGitLabMergeRequestProvidersApi(pr: ProviderPullRequest, provider: Integration): PullRequest;
138
- export declare function fromGitLabMergeRequest(pr: GitLabMergeRequestFull, provider: Provider): PullRequest;
137
+ export declare function fromGitLabMergeRequestProvidersApi(pr: ProviderPullRequest, provider: Integration, projection?: PullRequestProjection): PullRequest;
138
+ export declare function fromGitLabMergeRequest(pr: GitLabMergeRequestFull, provider: Provider, projection?: PullRequestProjection): PullRequest;
139
139
  export declare function getRepoNamespace(projectFullPath: string): string;
140
+ /** The most iids one etag read asks for: GitLab's GraphQL page size limit, so every iid's answer fits one page. */
141
+ export declare const gitLabEtagFieldsMaxIids = 100;
142
+ /**
143
+ * The most iids one etag read asks for when it selects the check rollup. GitLab resolves every job of each head
144
+ * pipeline server-side, one merge request after another within a request, so a large request is far slower than a
145
+ * few small ones run concurrently, and slower than the full read it replaces.
146
+ */
147
+ export declare const gitLabEtagFieldsWithChecksMaxIids = 10;
148
+ /**
149
+ * A merge request as the cheap etag read selects it (`GitLabApi.getMergeRequestsEtagFields`): only the fields
150
+ * provider-apis' `getPullRequestForRepo` maps into a full row's etag inputs. Each include's field is present only
151
+ * when that include was requested.
152
+ */
153
+ export interface GitLabMergeRequestEtagNode {
154
+ iid: string;
155
+ state: string;
156
+ draft: boolean;
157
+ updatedAt: string;
158
+ diffRefs: {
159
+ headSha: string | null;
160
+ } | null;
161
+ mergeStatusEnum?: string | null;
162
+ reviewers?: {
163
+ nodes: {
164
+ mergeRequestInteraction: {
165
+ reviewState: string | null;
166
+ } | null;
167
+ }[] | null;
168
+ } | null;
169
+ headPipeline?: {
170
+ stages: {
171
+ nodes: {
172
+ jobs: {
173
+ nodes: {
174
+ status: string | null;
175
+ allowFailure: boolean;
176
+ }[] | null;
177
+ } | null;
178
+ }[] | null;
179
+ } | null;
180
+ } | null;
181
+ }
182
+ /**
183
+ * An issue as the cheap etag read selects it (`GitLabApi.getIssuesEtagFields`). `upvotes` is present only when the
184
+ * `reactions` include was requested.
185
+ */
186
+ export interface GitLabIssueEtagNode {
187
+ iid: string;
188
+ closedAt: string | null;
189
+ updatedAt: string;
190
+ upvotes?: number | null;
191
+ }
192
+ /**
193
+ * A cheap etag read's merge request, as the fields its full batch row's etag reads: provider-apis' mapping (see the
194
+ * tables above), then `fromProviderPullRequest`'s. Neither step is the identity everywhere — a locked merge request
195
+ * reads as merged, a missing head SHA as `''` — so each value takes both rather than a mapping of its own.
196
+ */
197
+ export declare function toGitLabPullRequestEtagFields(node: GitLabMergeRequestEtagNode, etagIncludes: readonly PullRequestEtagInclude[]): PullRequestEtagFields;
198
+ /**
199
+ * A cheap etag read's issue, as the fields its full batch row's etag reads. provider-apis maps a GitLab issue's
200
+ * state to a name without a category, so `toIssueShape` decides `closed` from `closedAt` alone (`closedDate`, which
201
+ * provider-apis sets only for a truthy `closedAt`); GitLab's own `state` never counts. The thumbs-up count is
202
+ * provider-apis' `upvoteCount: upvotes`, which `toIssueShape` reads with `?? undefined`.
203
+ */
204
+ export declare function toGitLabIssueEtagFields(node: GitLabIssueEtagNode, etagIncludes: readonly IssueEtagInclude[]): IssueEtagFields;
140
205
  //#endregion
141
206
  //# sourceMappingURL=models.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import { PullRequest } from "../../../../git/models/pullRequest.js";
2
- import { fromProviderPullRequest } from "../models.js";
2
+ import { decideProviderReviewDecision, fromPullRequestReviewDecision } from "../pullRequestReviews.js";
3
+ import { GitBuildStatusState, GitPullRequestMergeableState, GitPullRequestReviewState, GitPullRequestState, fromProviderPullRequest, fromProviderPullRequestMergeableState, fromProviderPullRequestState, toStatusCheckRollupState } from "../models.js";
3
4
  //#region ../plus/integrations/src/providers/gitlab/models.ts
4
5
  function fromGitLabMergeRequestState(state) {
5
6
  return state === "locked" ? "closed" : state;
@@ -7,26 +8,22 @@ function fromGitLabMergeRequestState(state) {
7
8
  function toGitLabMergeRequestState(state) {
8
9
  return state;
9
10
  }
10
- function fromGitLabMergeRequestREST(pr, provider, repo) {
11
+ function fromGitLabMergeRequestREST(pr, provider, repo, projection) {
11
12
  return new PullRequest(provider, {
12
13
  id: pr.author?.id ?? "",
13
14
  name: pr.author?.name ?? void 0,
14
15
  avatarUrl: pr.author?.avatar_url ?? void 0,
15
16
  url: pr.author?.web_url ?? void 0
16
- }, String(pr.iid), void 0, pr.title, pr.web_url, repo, fromGitLabMergeRequestState(pr.state), new Date(pr.created_at), new Date(pr.updated_at), pr.closed_at == null ? void 0 : new Date(pr.closed_at), pr.merged_at == null ? void 0 : new Date(pr.merged_at));
17
+ }, String(pr.iid), void 0, pr.title, pr.web_url, repo, fromGitLabMergeRequestState(pr.state), new Date(pr.created_at), new Date(pr.updated_at), pr.closed_at == null ? void 0 : new Date(pr.closed_at), pr.merged_at == null ? void 0 : new Date(pr.merged_at), void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, projection);
17
18
  }
18
- function fromGitLabMergeRequestProvidersApi(pr, provider) {
19
+ function fromGitLabMergeRequestProvidersApi(pr, provider, projection) {
19
20
  const wrappedPr = {
20
21
  ...pr,
21
- id: String(pr.number),
22
- permissions: pr.permissions ?? {
23
- canMerge: true,
24
- canMergeAndBypassProtections: false
25
- }
22
+ id: String(pr.number)
26
23
  };
27
- return fromProviderPullRequest(wrappedPr, provider);
24
+ return fromProviderPullRequest(wrappedPr, provider, { projection });
28
25
  }
29
- function fromGitLabMergeRequest(pr, provider) {
26
+ function fromGitLabMergeRequest(pr, provider, projection) {
30
27
  let avatarUrl;
31
28
  try {
32
29
  avatarUrl = new URL(pr.author?.avatarUrl ?? "").toString();
@@ -51,7 +48,7 @@ function fromGitLabMergeRequest(pr, provider) {
51
48
  owner,
52
49
  repo,
53
50
  url: pr.project.webUrl
54
- }, fromGitLabMergeRequestState(pr.state), new Date(pr.createdAt), new Date(pr.updatedAt), pr.state !== "closed" ? void 0 : new Date(pr.updatedAt), pr.mergedAt == null ? void 0 : new Date(pr.mergedAt), "Unknown", void 0, fromGitLabMergeRequestRefs(pr));
51
+ }, fromGitLabMergeRequestState(pr.state), new Date(pr.createdAt), new Date(pr.updatedAt), pr.state !== "closed" ? void 0 : new Date(pr.updatedAt), pr.mergedAt == null ? void 0 : new Date(pr.mergedAt), void 0, void 0, fromGitLabMergeRequestRefs(pr), void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, projection);
55
52
  }
56
53
  function fromGitLabMergeRequestRefs(pr) {
57
54
  if (pr.sourceProject == null) return;
@@ -78,7 +75,103 @@ function fromGitLabMergeRequestRefs(pr) {
78
75
  function getRepoNamespace(projectFullPath) {
79
76
  return projectFullPath.split("/").slice(0, -1).join("/");
80
77
  }
78
+ /** The most iids one etag read asks for: GitLab's GraphQL page size limit, so every iid's answer fits one page. */
79
+ const gitLabEtagFieldsMaxIids = 100;
80
+ /**
81
+ * The most iids one etag read asks for when it selects the check rollup. GitLab resolves every job of each head
82
+ * pipeline server-side, one merge request after another within a request, so a large request is far slower than a
83
+ * few small ones run concurrently, and slower than the full read it replaces.
84
+ */
85
+ const gitLabEtagFieldsWithChecksMaxIids = 10;
86
+ /** provider-apis' merge request `state` map (`Oa`). It has no `locked`, which therefore maps to `undefined`. */
87
+ const gitLabMergeRequestProviderStates = {
88
+ opened: GitPullRequestState.Open,
89
+ merged: GitPullRequestState.Merged,
90
+ closed: GitPullRequestState.Closed
91
+ };
92
+ /** provider-apis' `mergeStatusEnum` map (`va`). */
93
+ const gitLabMergeStatusProviderStates = {
94
+ CAN_BE_MERGED: GitPullRequestMergeableState.Mergeable,
95
+ CANNOT_BE_MERGED: GitPullRequestMergeableState.Conflicts,
96
+ CANNOT_BE_MERGED_RECHECK: GitPullRequestMergeableState.Unknown,
97
+ UNCHECKED: GitPullRequestMergeableState.Unknown,
98
+ CHECKING: GitPullRequestMergeableState.Unknown
99
+ };
100
+ /** provider-apis' reviewer `reviewState` map (`ja`); a reviewer without one reads as review requested. */
101
+ const gitLabReviewProviderStates = {
102
+ APPROVED: GitPullRequestReviewState.Approved,
103
+ REQUESTED_CHANGES: GitPullRequestReviewState.ChangesRequested,
104
+ REVIEWED: GitPullRequestReviewState.Commented,
105
+ UNAPPROVED: GitPullRequestReviewState.ReviewRequested,
106
+ UNREVIEWED: GitPullRequestReviewState.ReviewRequested
107
+ };
108
+ /** provider-apis' CI job `status` map (`Ba`); a failed job that may fail reads as a warning. */
109
+ const gitLabJobProviderStates = {
110
+ CANCELED: GitBuildStatusState.Cancelled,
111
+ CREATED: GitBuildStatusState.Pending,
112
+ FAILED: GitBuildStatusState.Failed,
113
+ MANUAL: GitBuildStatusState.OptionalActionRequired,
114
+ PENDING: GitBuildStatusState.Pending,
115
+ PREPARING: GitBuildStatusState.Running,
116
+ RUNNING: GitBuildStatusState.Running,
117
+ SCHEDULED: GitBuildStatusState.Pending,
118
+ SKIPPED: GitBuildStatusState.Skipped,
119
+ SUCCESS: GitBuildStatusState.Success,
120
+ WAITING_FOR_CALLBACK: GitBuildStatusState.Pending,
121
+ WAITING_FOR_RESOURCE: GitBuildStatusState.Pending
122
+ };
123
+ function toGitLabJobBuildStatus(job) {
124
+ return {
125
+ completedAt: null,
126
+ description: null,
127
+ name: null,
128
+ state: !job.status ? null : job.status === "FAILED" && job.allowFailure ? GitBuildStatusState.Warning : gitLabJobProviderStates[job.status] ?? null,
129
+ stage: null,
130
+ startedAt: null,
131
+ url: ""
132
+ };
133
+ }
134
+ /**
135
+ * A cheap etag read's merge request, as the fields its full batch row's etag reads: provider-apis' mapping (see the
136
+ * tables above), then `fromProviderPullRequest`'s. Neither step is the identity everywhere — a locked merge request
137
+ * reads as merged, a missing head SHA as `''` — so each value takes both rather than a mapping of its own.
138
+ */
139
+ function toGitLabPullRequestEtagFields(node, etagIncludes) {
140
+ const fields = {
141
+ state: fromProviderPullRequestState(gitLabMergeRequestProviderStates[node.state]),
142
+ isDraft: node.draft,
143
+ updatedDate: new Date(node.updatedAt),
144
+ headSha: node.diffRefs?.headSha ?? ""
145
+ };
146
+ if (etagIncludes.includes("mergeable")) {
147
+ const mergeable = node.mergeStatusEnum != null ? gitLabMergeStatusProviderStates[node.mergeStatusEnum] : void 0;
148
+ fields.mergeableState = mergeable ? fromProviderPullRequestMergeableState[mergeable] : void 0;
149
+ }
150
+ if (etagIncludes.includes("reviewDecision")) {
151
+ const decision = decideProviderReviewDecision(node.reviewers?.nodes?.map((r) => r.mergeRequestInteraction?.reviewState ? gitLabReviewProviderStates[r.mergeRequestInteraction.reviewState] : GitPullRequestReviewState.ReviewRequested));
152
+ fields.reviewDecision = decision ? fromPullRequestReviewDecision[decision] : void 0;
153
+ }
154
+ if (etagIncludes.includes("checks")) {
155
+ const statuses = node.headPipeline?.stages?.nodes?.flatMap((stage) => stage.jobs?.nodes?.map(toGitLabJobBuildStatus) ?? []) ?? [];
156
+ fields.statusCheckRollupState = toStatusCheckRollupState(statuses);
157
+ }
158
+ return fields;
159
+ }
160
+ /**
161
+ * A cheap etag read's issue, as the fields its full batch row's etag reads. provider-apis maps a GitLab issue's
162
+ * state to a name without a category, so `toIssueShape` decides `closed` from `closedAt` alone (`closedDate`, which
163
+ * provider-apis sets only for a truthy `closedAt`); GitLab's own `state` never counts. The thumbs-up count is
164
+ * provider-apis' `upvoteCount: upvotes`, which `toIssueShape` reads with `?? undefined`.
165
+ */
166
+ function toGitLabIssueEtagFields(node, etagIncludes) {
167
+ const fields = {
168
+ state: node.closedAt ? "closed" : "opened",
169
+ updatedDate: new Date(node.updatedAt)
170
+ };
171
+ if (etagIncludes.includes("reactions")) fields.thumbsUpCount = node.upvotes ?? void 0;
172
+ return fields;
173
+ }
81
174
  //#endregion
82
- export { fromGitLabMergeRequest, fromGitLabMergeRequestProvidersApi, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, getRepoNamespace, toGitLabMergeRequestState };
175
+ export { fromGitLabMergeRequest, fromGitLabMergeRequestProvidersApi, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, getRepoNamespace, gitLabEtagFieldsMaxIids, gitLabEtagFieldsWithChecksMaxIids, toGitLabIssueEtagFields, toGitLabMergeRequestState, toGitLabPullRequestEtagFields };
83
176
 
84
177
  //# sourceMappingURL=models.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/gitlab/models.ts"],"sourcesContent":["import type { PullRequestRefs, PullRequestState } from '@gitlens/git/models/pullRequest.js';\nimport { PullRequest, PullRequestMergeableState } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type { Integration } from '../../models/integration.js';\nimport type { ProviderPullRequest } from '../models.js';\nimport { fromProviderPullRequest } from '../models.js';\n\nexport interface GitLabUser {\n\tid: number;\n\tname: string;\n\tusername: string;\n\tpublicEmail: string | undefined;\n\tstate: string;\n\tavatarUrl: string | undefined;\n\twebUrl: string;\n}\n\n/** A user's SSH key as returned by `GET /users/:id/keys`. */\nexport interface GitLabSshKey {\n\tid: number;\n\ttitle: string;\n\tkey: string;\n\tcreated_at: string;\n\texpires_at: string | null;\n\t/** Whether the key can be used for authentication, signing, or both. */\n\tusage_type: 'auth' | 'signing' | 'auth_and_signing';\n}\n\nexport interface GitLabCommit {\n\tid: string;\n\tshort_id: string;\n\tcreated_at: Date;\n\tparent_ids: string[];\n\ttitle: string;\n\tmessage: string;\n\tauthor_name: string;\n\tauthor_email: string;\n\tauthored_date: Date;\n\tcommitter_name: string;\n\tcommitter_email: string;\n\tcommitted_date: Date;\n\tstatus: string;\n\tproject_id: number;\n}\n\nexport interface GitLabIssue {\n\tiid: string;\n\tauthor: {\n\t\tname: string;\n\t\tavatarUrl: string | null;\n\t\twebUrl: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tclosedAt: string;\n\twebUrl: string;\n\tstate: 'opened' | 'closed' | 'locked';\n}\n\nexport interface GitLabMergeRequest {\n\tiid: string;\n\tauthor: {\n\t\tid: string;\n\t\tname: string;\n\t\tavatarUrl: string | null;\n\t\twebUrl: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string | null;\n\tstate: GitLabMergeRequestState;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tmergedAt: string | null;\n\twebUrl: string;\n}\n\nexport interface GitLabRepositoryStub {\n\tid: string;\n\tfullPath: string;\n\twebUrl: string;\n}\n\nexport interface GitLabMergeRequestFull extends GitLabMergeRequest {\n\tid: string;\n\ttargetBranch: string;\n\tsourceBranch: string;\n\tdiffRefs: {\n\t\tbaseSha: string | null;\n\t\theadSha: string;\n\t} | null;\n\tproject: GitLabRepositoryStub;\n\tsourceProject: GitLabRepositoryStub | null;\n}\n\nexport type GitLabMergeRequestState = 'opened' | 'closed' | 'locked' | 'merged';\n\nexport function fromGitLabMergeRequestState(state: GitLabMergeRequestState): PullRequestState {\n\treturn state === 'locked' ? 'closed' : state;\n}\n\nexport function toGitLabMergeRequestState(state: PullRequestState): GitLabMergeRequestState {\n\treturn state;\n}\n\nexport interface GitLabMergeRequestREST {\n\tid: number;\n\tiid: number;\n\tauthor: {\n\t\tid: string;\n\t\tname: string;\n\t\tavatar_url?: string;\n\t\tweb_url: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string;\n\tstate: GitLabMergeRequestState;\n\tcreated_at: string;\n\tupdated_at: string;\n\tclosed_at: string | null;\n\tmerged_at: string | null;\n\tdiff_refs: {\n\t\tbase_sha: string;\n\t\thead_sha: string;\n\t\tstart_sha: string;\n\t};\n\tsource_branch: string;\n\tsource_project_id: number;\n\ttarget_branch: string;\n\ttarget_project_id: number;\n\tweb_url: string;\n}\n\nexport function fromGitLabMergeRequestREST(\n\tpr: GitLabMergeRequestREST,\n\tprovider: Provider,\n\trepo: { owner: string; repo: string },\n): PullRequest {\n\treturn new PullRequest(\n\t\tprovider,\n\t\t{\n\t\t\tid: pr.author?.id ?? '',\n\t\t\t// An absent author stays absent — no invented `'Unknown'` name, no `''` url/avatar. See\n\t\t\t// `PullRequestMember.name`.\n\t\t\tname: pr.author?.name ?? undefined,\n\t\t\tavatarUrl: pr.author?.avatar_url ?? undefined,\n\t\t\turl: pr.author?.web_url ?? undefined,\n\t\t},\n\t\tString(pr.iid),\n\t\tundefined,\n\t\tpr.title,\n\t\tpr.web_url,\n\t\trepo,\n\t\tfromGitLabMergeRequestState(pr.state),\n\t\tnew Date(pr.created_at),\n\t\tnew Date(pr.updated_at),\n\t\tpr.closed_at == null ? undefined : new Date(pr.closed_at),\n\t\tpr.merged_at == null ? undefined : new Date(pr.merged_at),\n\t);\n}\n\nexport interface GitLabProjectREST {\n\tnamespace: {\n\t\tpath: string;\n\t\tfull_path: string;\n\t};\n\tpath: string;\n\n\tforked_from_project?: {\n\t\tnamespace: {\n\t\t\tpath: string;\n\t\t\tfull_path: string;\n\t\t};\n\t\tpath: string;\n\t};\n}\n\nexport function fromGitLabMergeRequestProvidersApi(pr: ProviderPullRequest, provider: Integration): PullRequest {\n\tconst wrappedPr: ProviderPullRequest = {\n\t\t...pr,\n\t\t// @gitkraken/providers-api returns global ID as id, while allover GitLens we use internal ID (iid) that is returned as `number`:\n\t\tid: String(pr.number),\n\t\t// Substitute some defaults that are needed to enable PRs because @gitkraken/providers-api always returns null here:\n\t\t// Discussed: https://github.com/gitkraken/provider-apis-package-js/blob/6ee521eb6b46bbb759d9c68646979c3b25681d90/src/providers/gitlab/gitlab.ts#L597\n\t\tpermissions: pr.permissions ?? {\n\t\t\tcanMerge: true,\n\t\t\tcanMergeAndBypassProtections: false,\n\t\t},\n\t};\n\treturn fromProviderPullRequest(wrappedPr, provider);\n}\n\nexport function fromGitLabMergeRequest(pr: GitLabMergeRequestFull, provider: Provider): PullRequest {\n\tlet avatarUrl: string | undefined;\n\ttry {\n\t\tavatarUrl = new URL(pr.author?.avatarUrl ?? '').toString();\n\t} catch {\n\t\ttry {\n\t\t\tconst authorUrl = new URL(pr.author?.webUrl ?? '');\n\t\t\tauthorUrl.pathname = '';\n\t\t\tauthorUrl.search = '';\n\t\t\tauthorUrl.hash = '';\n\t\t\tavatarUrl = pr.author?.avatarUrl ? authorUrl.toString() + pr.author?.avatarUrl : undefined;\n\t\t} catch {\n\t\t\tavatarUrl = undefined;\n\t\t}\n\t}\n\tconst [owner, repo] = pr.project.fullPath.split('/');\n\n\treturn new PullRequest(\n\t\tprovider,\n\t\t{\n\t\t\t// author\n\t\t\tid: pr.author?.id ?? '',\n\t\t\t// An absent author stays absent — no invented `'Unknown'` name, no `''` url. See `PullRequestMember.name`.\n\t\t\tname: pr.author?.name ?? undefined,\n\t\t\tavatarUrl: avatarUrl,\n\t\t\turl: pr.author?.webUrl ?? undefined,\n\t\t},\n\t\tpr.iid, // id\n\t\tpr.id, // nodeId\n\t\tpr.title,\n\t\tpr.webUrl || '',\n\t\t{\n\t\t\t// IssueRepository\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\turl: pr.project.webUrl,\n\t\t},\n\t\tfromGitLabMergeRequestState(pr.state), // PullRequestState\n\t\tnew Date(pr.createdAt),\n\t\tnew Date(pr.updatedAt),\n\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\tpr.state !== 'closed' ? undefined : new Date(pr.updatedAt),\n\t\tpr.mergedAt == null ? undefined : new Date(pr.mergedAt),\n\t\tPullRequestMergeableState.Unknown,\n\t\tundefined, // viewerCanUpdate\n\t\tfromGitLabMergeRequestRefs(pr), // PullRequestRefs\n\t);\n}\n\nfunction fromGitLabMergeRequestRefs(pr: GitLabMergeRequestFull): PullRequestRefs | undefined {\n\tif (pr.sourceProject == null) {\n\t\treturn undefined;\n\t}\n\t// GitLab terminology: sourceBranch = branch with changes (head), targetBranch = merge target (base)\n\treturn {\n\t\thead: {\n\t\t\towner: getRepoNamespace(pr.sourceProject.fullPath),\n\t\t\tbranch: pr.sourceBranch,\n\t\t\texists: true,\n\t\t\turl: pr.sourceProject.webUrl,\n\t\t\trepo: pr.sourceProject.fullPath,\n\t\t\tsha: pr.diffRefs?.headSha || '',\n\t\t},\n\t\tbase: {\n\t\t\towner: getRepoNamespace(pr.project.fullPath),\n\t\t\tbranch: pr.targetBranch,\n\t\t\texists: true,\n\t\t\turl: pr.project.webUrl,\n\t\t\trepo: pr.project.fullPath,\n\t\t\tsha: pr.diffRefs?.baseSha || '',\n\t\t},\n\t\tisCrossRepository: pr.sourceProject.id !== pr.project.id,\n\t};\n}\n\nexport function getRepoNamespace(projectFullPath: string): string {\n\treturn projectFullPath.split('/').slice(0, -1).join('/');\n}\n"],"mappings":";;;AAkGA,SAAgB,4BAA4B,OAAkD;CAC7F,OAAO,UAAU,WAAW,WAAW;AACxC;AAEA,SAAgB,0BAA0B,OAAkD;CAC3F,OAAO;AACR;AA8BA,SAAgB,2BACf,IACA,UACA,MACc;CACd,OAAO,IAAI,YACV,UACA;EACC,IAAI,GAAG,QAAQ,MAAM;EAGrB,MAAM,GAAG,QAAQ,QAAQ,KAAA;EACzB,WAAW,GAAG,QAAQ,cAAc,KAAA;EACpC,KAAK,GAAG,QAAQ,WAAW,KAAA;CAC5B,GACA,OAAO,GAAG,GAAG,GACb,KAAA,GACA,GAAG,OACH,GAAG,SACH,MACA,4BAA4B,GAAG,KAAK,GACpC,IAAI,KAAK,GAAG,UAAU,GACtB,IAAI,KAAK,GAAG,UAAU,GACtB,GAAG,aAAa,OAAO,KAAA,IAAY,IAAI,KAAK,GAAG,SAAS,GACxD,GAAG,aAAa,OAAO,KAAA,IAAY,IAAI,KAAK,GAAG,SAAS,CACzD;AACD;AAkBA,SAAgB,mCAAmC,IAAyB,UAAoC;CAC/G,MAAM,YAAiC;EACtC,GAAG;EAEH,IAAI,OAAO,GAAG,MAAM;EAGpB,aAAa,GAAG,eAAe;GAC9B,UAAU;GACV,8BAA8B;EAC/B;CACD;CACA,OAAO,wBAAwB,WAAW,QAAQ;AACnD;AAEA,SAAgB,uBAAuB,IAA4B,UAAiC;CACnG,IAAI;CACJ,IAAI;EACH,YAAY,IAAI,IAAI,GAAG,QAAQ,aAAa,EAAE,CAAC,CAAC,SAAS;CAC1D,QAAQ;EACP,IAAI;GACH,MAAM,YAAY,IAAI,IAAI,GAAG,QAAQ,UAAU,EAAE;GACjD,UAAU,WAAW;GACrB,UAAU,SAAS;GACnB,UAAU,OAAO;GACjB,YAAY,GAAG,QAAQ,YAAY,UAAU,SAAS,IAAI,GAAG,QAAQ,YAAY,KAAA;EAClF,QAAQ;GACP,YAAY,KAAA;EACb;CACD;CACA,MAAM,CAAC,OAAO,QAAQ,GAAG,QAAQ,SAAS,MAAM,GAAG;CAEnD,OAAO,IAAI,YACV,UACA;EAEC,IAAI,GAAG,QAAQ,MAAM;EAErB,MAAM,GAAG,QAAQ,QAAQ,KAAA;EACd;EACX,KAAK,GAAG,QAAQ,UAAU,KAAA;CAC3B,GACA,GAAG,KACH,GAAG,IACH,GAAG,OACH,GAAG,UAAU,IACb;EAEQ;EACD;EACN,KAAK,GAAG,QAAQ;CACjB,GACA,4BAA4B,GAAG,KAAK,GACpC,IAAI,KAAK,GAAG,SAAS,GACrB,IAAI,KAAK,GAAG,SAAS,GAErB,GAAG,UAAU,WAAW,KAAA,IAAY,IAAI,KAAK,GAAG,SAAS,GACzD,GAAG,YAAY,OAAO,KAAA,IAAY,IAAI,KAAK,GAAG,QAAQ,GAAA,WAEtD,KAAA,GACA,2BAA2B,EAAE,CAC9B;AACD;AAEA,SAAS,2BAA2B,IAAyD;CAC5F,IAAI,GAAG,iBAAiB,MACvB;CAGD,OAAO;EACN,MAAM;GACL,OAAO,iBAAiB,GAAG,cAAc,QAAQ;GACjD,QAAQ,GAAG;GACX,QAAQ;GACR,KAAK,GAAG,cAAc;GACtB,MAAM,GAAG,cAAc;GACvB,KAAK,GAAG,UAAU,WAAW;EAC9B;EACA,MAAM;GACL,OAAO,iBAAiB,GAAG,QAAQ,QAAQ;GAC3C,QAAQ,GAAG;GACX,QAAQ;GACR,KAAK,GAAG,QAAQ;GAChB,MAAM,GAAG,QAAQ;GACjB,KAAK,GAAG,UAAU,WAAW;EAC9B;EACA,mBAAmB,GAAG,cAAc,OAAO,GAAG,QAAQ;CACvD;AACD;AAEA,SAAgB,iBAAiB,iBAAiC;CACjE,OAAO,gBAAgB,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG;AACxD"}
1
+ {"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/gitlab/models.ts"],"sourcesContent":["import type { GitBuildStatus } from '@gitkraken/provider-apis';\nimport type { PullRequestProjection, PullRequestRefs, PullRequestState } from '@gitlens/git/models/pullRequest.js';\nimport { PullRequest } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type {\n\tIntegration,\n\tIssueEtagFields,\n\tIssueEtagInclude,\n\tPullRequestEtagFields,\n\tPullRequestEtagInclude,\n} from '../../models/integration.js';\nimport type { ProviderPullRequest } from '../models.js';\nimport {\n\tfromProviderPullRequest,\n\tfromProviderPullRequestMergeableState,\n\tfromProviderPullRequestState,\n\tGitBuildStatusState,\n\tGitPullRequestMergeableState,\n\tGitPullRequestReviewState,\n\tGitPullRequestState,\n\ttoStatusCheckRollupState,\n} from '../models.js';\nimport { decideProviderReviewDecision, fromPullRequestReviewDecision } from '../pullRequestReviews.js';\n\nexport interface GitLabUser {\n\tid: number;\n\tname: string;\n\tusername: string;\n\tpublicEmail: string | undefined;\n\tstate: string;\n\tavatarUrl: string | undefined;\n\twebUrl: string;\n}\n\n/** A user's SSH key as returned by `GET /users/:id/keys`. */\nexport interface GitLabSshKey {\n\tid: number;\n\ttitle: string;\n\tkey: string;\n\tcreated_at: string;\n\texpires_at: string | null;\n\t/** Whether the key can be used for authentication, signing, or both. */\n\tusage_type: 'auth' | 'signing' | 'auth_and_signing';\n}\n\nexport interface GitLabCommit {\n\tid: string;\n\tshort_id: string;\n\tcreated_at: Date;\n\tparent_ids: string[];\n\ttitle: string;\n\tmessage: string;\n\tauthor_name: string;\n\tauthor_email: string;\n\tauthored_date: Date;\n\tcommitter_name: string;\n\tcommitter_email: string;\n\tcommitted_date: Date;\n\tstatus: string;\n\tproject_id: number;\n}\n\nexport interface GitLabIssue {\n\tiid: string;\n\tauthor: {\n\t\tname: string;\n\t\tavatarUrl: string | null;\n\t\twebUrl: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tclosedAt: string;\n\twebUrl: string;\n\tstate: 'opened' | 'closed' | 'locked';\n}\n\nexport interface GitLabMergeRequest {\n\tiid: string;\n\tauthor: {\n\t\tid: string;\n\t\tname: string;\n\t\tavatarUrl: string | null;\n\t\twebUrl: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string | null;\n\tstate: GitLabMergeRequestState;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tmergedAt: string | null;\n\twebUrl: string;\n}\n\nexport interface GitLabRepositoryStub {\n\tid: string;\n\tfullPath: string;\n\twebUrl: string;\n}\n\nexport interface GitLabMergeRequestFull extends GitLabMergeRequest {\n\tid: string;\n\ttargetBranch: string;\n\tsourceBranch: string;\n\tdiffRefs: {\n\t\tbaseSha: string | null;\n\t\theadSha: string;\n\t} | null;\n\tproject: GitLabRepositoryStub;\n\tsourceProject: GitLabRepositoryStub | null;\n}\n\nexport type GitLabMergeRequestState = 'opened' | 'closed' | 'locked' | 'merged';\n\nexport function fromGitLabMergeRequestState(state: GitLabMergeRequestState): PullRequestState {\n\treturn state === 'locked' ? 'closed' : state;\n}\n\nexport function toGitLabMergeRequestState(state: PullRequestState): GitLabMergeRequestState {\n\treturn state;\n}\n\nexport interface GitLabMergeRequestREST {\n\tid: number;\n\tiid: number;\n\tauthor: {\n\t\tid: string;\n\t\tname: string;\n\t\tavatar_url?: string;\n\t\tweb_url: string;\n\t} | null;\n\ttitle: string;\n\tdescription: string;\n\tstate: GitLabMergeRequestState;\n\tcreated_at: string;\n\tupdated_at: string;\n\tclosed_at: string | null;\n\tmerged_at: string | null;\n\tdiff_refs: {\n\t\tbase_sha: string;\n\t\thead_sha: string;\n\t\tstart_sha: string;\n\t};\n\tsource_branch: string;\n\tsource_project_id: number;\n\ttarget_branch: string;\n\ttarget_project_id: number;\n\tweb_url: string;\n}\n\nexport function fromGitLabMergeRequestREST(\n\tpr: GitLabMergeRequestREST,\n\tprovider: Provider,\n\trepo: { owner: string; repo: string },\n\tprojection?: PullRequestProjection,\n): PullRequest {\n\treturn new PullRequest(\n\t\tprovider,\n\t\t{\n\t\t\tid: pr.author?.id ?? '',\n\t\t\t// An absent author stays absent — no invented `'Unknown'` name, no `''` url/avatar. See\n\t\t\t// `PullRequestMember.name`.\n\t\t\tname: pr.author?.name ?? undefined,\n\t\t\tavatarUrl: pr.author?.avatar_url ?? undefined,\n\t\t\turl: pr.author?.web_url ?? undefined,\n\t\t},\n\t\tString(pr.iid),\n\t\tundefined,\n\t\tpr.title,\n\t\tpr.web_url,\n\t\trepo,\n\t\tfromGitLabMergeRequestState(pr.state),\n\t\tnew Date(pr.created_at),\n\t\tnew Date(pr.updated_at),\n\t\tpr.closed_at == null ? undefined : new Date(pr.closed_at),\n\t\tpr.merged_at == null ? undefined : new Date(pr.merged_at),\n\t\tundefined, // mergeableState\n\t\tundefined, // viewerCanUpdate\n\t\tundefined, // refs\n\t\tundefined, // isDraft\n\t\tundefined, // additions\n\t\tundefined, // deletions\n\t\tundefined, // commentsCount\n\t\tundefined, // thumbsUpCount\n\t\tundefined, // reviewDecision\n\t\tundefined, // reviewRequests\n\t\tundefined, // latestReviews\n\t\tundefined, // assignees\n\t\tundefined, // statusCheckRollupState\n\t\tundefined, // project\n\t\tundefined, // version\n\t\tundefined, // commitCount\n\t\tundefined, // stack\n\t\tundefined, // filesChanged\n\t\tundefined, // body\n\t\tundefined, // number\n\t\tundefined, // authoredByMe\n\t\tprojection,\n\t);\n}\n\nexport interface GitLabProjectREST {\n\tnamespace: {\n\t\tpath: string;\n\t\tfull_path: string;\n\t};\n\tpath: string;\n\n\tforked_from_project?: {\n\t\tnamespace: {\n\t\t\tpath: string;\n\t\t\tfull_path: string;\n\t\t};\n\t\tpath: string;\n\t};\n}\n\nexport function fromGitLabMergeRequestProvidersApi(\n\tpr: ProviderPullRequest,\n\tprovider: Integration,\n\tprojection?: PullRequestProjection,\n): PullRequest {\n\tconst wrappedPr: ProviderPullRequest = {\n\t\t...pr,\n\t\t// @gitkraken/providers-api returns global ID as id, while allover GitLens we use internal ID (iid) that is returned as `number`:\n\t\tid: String(pr.number),\n\t};\n\treturn fromProviderPullRequest(wrappedPr, provider, { projection: projection });\n}\n\nexport function fromGitLabMergeRequest(\n\tpr: GitLabMergeRequestFull,\n\tprovider: Provider,\n\tprojection?: PullRequestProjection,\n): PullRequest {\n\tlet avatarUrl: string | undefined;\n\ttry {\n\t\tavatarUrl = new URL(pr.author?.avatarUrl ?? '').toString();\n\t} catch {\n\t\ttry {\n\t\t\tconst authorUrl = new URL(pr.author?.webUrl ?? '');\n\t\t\tauthorUrl.pathname = '';\n\t\t\tauthorUrl.search = '';\n\t\t\tauthorUrl.hash = '';\n\t\t\tavatarUrl = pr.author?.avatarUrl ? authorUrl.toString() + pr.author?.avatarUrl : undefined;\n\t\t} catch {\n\t\t\tavatarUrl = undefined;\n\t\t}\n\t}\n\tconst [owner, repo] = pr.project.fullPath.split('/');\n\n\treturn new PullRequest(\n\t\tprovider,\n\t\t{\n\t\t\t// author\n\t\t\tid: pr.author?.id ?? '',\n\t\t\t// An absent author stays absent — no invented `'Unknown'` name, no `''` url. See `PullRequestMember.name`.\n\t\t\tname: pr.author?.name ?? undefined,\n\t\t\tavatarUrl: avatarUrl,\n\t\t\turl: pr.author?.webUrl ?? undefined,\n\t\t},\n\t\tpr.iid, // id\n\t\tpr.id, // nodeId\n\t\tpr.title,\n\t\tpr.webUrl || '',\n\t\t{\n\t\t\t// IssueRepository\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\turl: pr.project.webUrl,\n\t\t},\n\t\tfromGitLabMergeRequestState(pr.state), // PullRequestState\n\t\tnew Date(pr.createdAt),\n\t\tnew Date(pr.updatedAt),\n\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\tpr.state !== 'closed' ? undefined : new Date(pr.updatedAt),\n\t\tpr.mergedAt == null ? undefined : new Date(pr.mergedAt),\n\t\tundefined, // mergeableState: not selected\n\t\tundefined, // viewerCanUpdate\n\t\tfromGitLabMergeRequestRefs(pr), // PullRequestRefs\n\t\tundefined, // isDraft\n\t\tundefined, // additions\n\t\tundefined, // deletions\n\t\tundefined, // commentsCount\n\t\tundefined, // thumbsUpCount\n\t\tundefined, // reviewDecision\n\t\tundefined, // reviewRequests\n\t\tundefined, // latestReviews\n\t\tundefined, // assignees\n\t\tundefined, // statusCheckRollupState\n\t\tundefined, // project\n\t\tundefined, // version\n\t\tundefined, // commitCount\n\t\tundefined, // stack\n\t\tundefined, // filesChanged\n\t\tundefined, // body\n\t\tundefined, // number\n\t\tundefined, // authoredByMe\n\t\tprojection,\n\t);\n}\n\nfunction fromGitLabMergeRequestRefs(pr: GitLabMergeRequestFull): PullRequestRefs | undefined {\n\tif (pr.sourceProject == null) {\n\t\treturn undefined;\n\t}\n\t// GitLab terminology: sourceBranch = branch with changes (head), targetBranch = merge target (base)\n\treturn {\n\t\thead: {\n\t\t\towner: getRepoNamespace(pr.sourceProject.fullPath),\n\t\t\tbranch: pr.sourceBranch,\n\t\t\texists: true,\n\t\t\turl: pr.sourceProject.webUrl,\n\t\t\trepo: pr.sourceProject.fullPath,\n\t\t\tsha: pr.diffRefs?.headSha || '',\n\t\t},\n\t\tbase: {\n\t\t\towner: getRepoNamespace(pr.project.fullPath),\n\t\t\tbranch: pr.targetBranch,\n\t\t\texists: true,\n\t\t\turl: pr.project.webUrl,\n\t\t\trepo: pr.project.fullPath,\n\t\t\tsha: pr.diffRefs?.baseSha || '',\n\t\t},\n\t\tisCrossRepository: pr.sourceProject.id !== pr.project.id,\n\t};\n}\n\nexport function getRepoNamespace(projectFullPath: string): string {\n\treturn projectFullPath.split('/').slice(0, -1).join('/');\n}\n\n/** The most iids one etag read asks for: GitLab's GraphQL page size limit, so every iid's answer fits one page. */\nexport const gitLabEtagFieldsMaxIids = 100;\n\n/**\n * The most iids one etag read asks for when it selects the check rollup. GitLab resolves every job of each head\n * pipeline server-side, one merge request after another within a request, so a large request is far slower than a\n * few small ones run concurrently, and slower than the full read it replaces.\n */\nexport const gitLabEtagFieldsWithChecksMaxIids = 10;\n\n/**\n * A merge request as the cheap etag read selects it (`GitLabApi.getMergeRequestsEtagFields`): only the fields\n * provider-apis' `getPullRequestForRepo` maps into a full row's etag inputs. Each include's field is present only\n * when that include was requested.\n */\nexport interface GitLabMergeRequestEtagNode {\n\tiid: string;\n\tstate: string;\n\tdraft: boolean;\n\tupdatedAt: string;\n\tdiffRefs: { headSha: string | null } | null;\n\tmergeStatusEnum?: string | null;\n\treviewers?: {\n\t\tnodes: { mergeRequestInteraction: { reviewState: string | null } | null }[] | null;\n\t} | null;\n\theadPipeline?: {\n\t\tstages: {\n\t\t\tnodes: { jobs: { nodes: { status: string | null; allowFailure: boolean }[] | null } | null }[] | null;\n\t\t} | null;\n\t} | null;\n}\n\n/**\n * An issue as the cheap etag read selects it (`GitLabApi.getIssuesEtagFields`). `upvotes` is present only when the\n * `reactions` include was requested.\n */\nexport interface GitLabIssueEtagNode {\n\tiid: string;\n\tclosedAt: string | null;\n\tupdatedAt: string;\n\tupvotes?: number | null;\n}\n\ntype ProviderPullRequestState = Parameters<typeof fromProviderPullRequestState>[0];\ntype ProviderMergeableState = keyof typeof fromProviderPullRequestMergeableState;\ntype ProviderReviewState = keyof typeof fromPullRequestReviewDecision;\ntype ProviderBuildStatusState = NonNullable<GitBuildStatus['state']>;\n\n// The tables below mirror provider-apis' (0.61.0) GitLab merge request mapping behind `getPullRequestForRepo` (`rs`\n// and its helpers in the bundle), which it doesn't export. A full batch row takes these values on through\n// `fromProviderPullRequest`, so the cheap check composes the same steps to compute the same etag.\n\n/** provider-apis' merge request `state` map (`Oa`). It has no `locked`, which therefore maps to `undefined`. */\nconst gitLabMergeRequestProviderStates: Partial<Record<string, ProviderPullRequestState>> = {\n\topened: GitPullRequestState.Open,\n\tmerged: GitPullRequestState.Merged,\n\tclosed: GitPullRequestState.Closed,\n};\n\n/** provider-apis' `mergeStatusEnum` map (`va`). */\nconst gitLabMergeStatusProviderStates: Partial<Record<string, ProviderMergeableState>> = {\n\tCAN_BE_MERGED: GitPullRequestMergeableState.Mergeable,\n\tCANNOT_BE_MERGED: GitPullRequestMergeableState.Conflicts,\n\tCANNOT_BE_MERGED_RECHECK: GitPullRequestMergeableState.Unknown,\n\tUNCHECKED: GitPullRequestMergeableState.Unknown,\n\tCHECKING: GitPullRequestMergeableState.Unknown,\n};\n\n/** provider-apis' reviewer `reviewState` map (`ja`); a reviewer without one reads as review requested. */\nconst gitLabReviewProviderStates: Partial<Record<string, ProviderReviewState>> = {\n\tAPPROVED: GitPullRequestReviewState.Approved,\n\tREQUESTED_CHANGES: GitPullRequestReviewState.ChangesRequested,\n\tREVIEWED: GitPullRequestReviewState.Commented,\n\tUNAPPROVED: GitPullRequestReviewState.ReviewRequested,\n\tUNREVIEWED: GitPullRequestReviewState.ReviewRequested,\n};\n\n/** provider-apis' CI job `status` map (`Ba`); a failed job that may fail reads as a warning. */\nconst gitLabJobProviderStates: Partial<Record<string, ProviderBuildStatusState>> = {\n\tCANCELED: GitBuildStatusState.Cancelled,\n\tCREATED: GitBuildStatusState.Pending,\n\tFAILED: GitBuildStatusState.Failed,\n\tMANUAL: GitBuildStatusState.OptionalActionRequired,\n\tPENDING: GitBuildStatusState.Pending,\n\tPREPARING: GitBuildStatusState.Running,\n\tRUNNING: GitBuildStatusState.Running,\n\tSCHEDULED: GitBuildStatusState.Pending,\n\tSKIPPED: GitBuildStatusState.Skipped,\n\tSUCCESS: GitBuildStatusState.Success,\n\tWAITING_FOR_CALLBACK: GitBuildStatusState.Pending,\n\tWAITING_FOR_RESOURCE: GitBuildStatusState.Pending,\n};\n\nfunction toGitLabJobBuildStatus(job: { status: string | null; allowFailure: boolean }): GitBuildStatus {\n\tconst state = !job.status\n\t\t? null\n\t\t: job.status === 'FAILED' && job.allowFailure\n\t\t\t? GitBuildStatusState.Warning\n\t\t\t: (gitLabJobProviderStates[job.status] ?? null);\n\t// The rollup reads only `state`.\n\treturn { completedAt: null, description: null, name: null, state: state, stage: null, startedAt: null, url: '' };\n}\n\n/**\n * A cheap etag read's merge request, as the fields its full batch row's etag reads: provider-apis' mapping (see the\n * tables above), then `fromProviderPullRequest`'s. Neither step is the identity everywhere — a locked merge request\n * reads as merged, a missing head SHA as `''` — so each value takes both rather than a mapping of its own.\n */\nexport function toGitLabPullRequestEtagFields(\n\tnode: GitLabMergeRequestEtagNode,\n\tetagIncludes: readonly PullRequestEtagInclude[],\n): PullRequestEtagFields {\n\tconst fields: PullRequestEtagFields = {\n\t\t// A locked merge request passes `undefined` here, as its full row does.\n\t\tstate: fromProviderPullRequestState(gitLabMergeRequestProviderStates[node.state] as ProviderPullRequestState),\n\t\tisDraft: node.draft,\n\t\tupdatedDate: new Date(node.updatedAt),\n\t\theadSha: node.diffRefs?.headSha ?? '',\n\t};\n\n\tif (etagIncludes.includes('mergeable')) {\n\t\tconst mergeable =\n\t\t\tnode.mergeStatusEnum != null ? gitLabMergeStatusProviderStates[node.mergeStatusEnum] : undefined;\n\t\tfields.mergeableState = mergeable ? fromProviderPullRequestMergeableState[mergeable] : undefined;\n\t}\n\n\tif (etagIncludes.includes('reviewDecision')) {\n\t\t// A review state provider-apis doesn't know maps to `undefined`, which never outranks the decision so far.\n\t\tconst decision = decideProviderReviewDecision(\n\t\t\tnode.reviewers?.nodes?.map(r =>\n\t\t\t\tr.mergeRequestInteraction?.reviewState\n\t\t\t\t\t? gitLabReviewProviderStates[r.mergeRequestInteraction.reviewState]\n\t\t\t\t\t: GitPullRequestReviewState.ReviewRequested,\n\t\t\t),\n\t\t);\n\t\tfields.reviewDecision = decision ? fromPullRequestReviewDecision[decision] : undefined;\n\t}\n\n\tif (etagIncludes.includes('checks')) {\n\t\tconst statuses =\n\t\t\tnode.headPipeline?.stages?.nodes?.flatMap(stage => stage.jobs?.nodes?.map(toGitLabJobBuildStatus) ?? []) ??\n\t\t\t[];\n\t\tfields.statusCheckRollupState = toStatusCheckRollupState(statuses);\n\t}\n\n\treturn fields;\n}\n\n/**\n * A cheap etag read's issue, as the fields its full batch row's etag reads. provider-apis maps a GitLab issue's\n * state to a name without a category, so `toIssueShape` decides `closed` from `closedAt` alone (`closedDate`, which\n * provider-apis sets only for a truthy `closedAt`); GitLab's own `state` never counts. The thumbs-up count is\n * provider-apis' `upvoteCount: upvotes`, which `toIssueShape` reads with `?? undefined`.\n */\nexport function toGitLabIssueEtagFields(\n\tnode: GitLabIssueEtagNode,\n\tetagIncludes: readonly IssueEtagInclude[],\n): IssueEtagFields {\n\tconst fields: IssueEtagFields = {\n\t\tstate: node.closedAt ? 'closed' : 'opened',\n\t\tupdatedDate: new Date(node.updatedAt),\n\t};\n\n\tif (etagIncludes.includes('reactions')) {\n\t\tfields.thumbsUpCount = node.upvotes ?? undefined;\n\t}\n\n\treturn fields;\n}\n"],"mappings":"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"}
@@ -10,11 +10,11 @@ import { PullRequestUrlIdentity } from "../../../git/utils/pullRequest.utils.js"
10
10
  import { ProviderAuthenticationSession } from "../authentication/models.js";
11
11
  import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from "../constants.js";
12
12
  import { ProviderOrganization } from "../results.js";
13
+ import { ProviderApiPagedResult, ProviderHierarchyResult, ProviderPullRequest, ProviderRepository } from "./models.js";
13
14
  import { ProvidersApi } from "./providersApi.js";
14
15
  import { AccountWideIssuesResult, SearchMyIssuesOptions } from "../models/issueReads.js";
15
16
  import { GitHostIntegration, SearchMyPullRequestsOptions, SearchPullRequestsOptions } from "../models/gitHostIntegration.js";
16
- import "../models/integration.js";
17
- import { ProviderApiPagedResult, ProviderHierarchyResult, ProviderPullRequest, ProviderRepository } from "./models.js";
17
+ import { IssueEtagFields, IssueEtagInclude, PullRequestEtagFields, PullRequestEtagInclude } from "../models/integration.js";
18
18
  import { IntegrationConnectionChangeEvent } from "../integrationService.js";
19
19
  import { IntegrationAuthenticationService } from "../authentication/integrationAuthenticationService.js";
20
20
  import { IntegrationAuthenticationProviderDescriptor } from "../authentication/integrationAuthenticationProvider.js";
@@ -82,6 +82,35 @@ declare abstract class GitLabIntegrationBase<ID extends GitLabIntegrationIds> ex
82
82
  username?: string;
83
83
  };
84
84
  } | undefined, cancellation?: AbortSignal): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined>;
85
+ /**
86
+ * The cheap check behind the batch issue read's etags: GitLens' own GitLab client reads each project's issues by
87
+ * iid, up to {@link gitLabEtagFieldsMaxIids} in ONE request, where {@link getProviderIssuesBatch} sends one or
88
+ * two per target. Each row is converted as provider-apis and `toIssueShape` convert the full one, so both reads
89
+ * compute the same etag, and `'reactions'` adds the upvote count the full row's `thumbsUpCount` comes from. A
90
+ * request that throws rejects only its own targets' slots.
91
+ */
92
+ protected getProviderIssuesEtagFields(session: ProviderAuthenticationSession, coordinates: readonly {
93
+ owner: string;
94
+ repo: string;
95
+ number: number;
96
+ project?: string;
97
+ }[], options: {
98
+ etagIncludes?: readonly IssueEtagInclude[];
99
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined>;
100
+ /**
101
+ * The cheap check behind the batch pull request read's etags: {@link getProviderIssuesEtagFields}'s requests and
102
+ * failure isolation over merge requests, selecting a merge request's change state plus the fields of each of
103
+ * `options.etagIncludes`. Every include is meaningful here: a full row carries a mergeability, a review decision
104
+ * and a check rollup, each of which can change without moving `updatedAt`.
105
+ */
106
+ protected getProviderPullRequestsEtagFields(session: ProviderAuthenticationSession, coordinates: readonly {
107
+ owner: string;
108
+ repo: string;
109
+ number: number;
110
+ project?: string;
111
+ }[], options: {
112
+ etagIncludes?: readonly PullRequestEtagInclude[];
113
+ }, cancellation?: AbortSignal): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined>;
85
114
  /**
86
115
  * Two steps, because provider-apis has no source-branch filter: GitLens' own GitLab client finds each branch's
87
116
  * matching iids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is
@@ -7,10 +7,10 @@ import "../constants.js";
7
7
  import { toCollectionScopeFailure } from "../collectionMetadata.js";
8
8
  import { toTokenWithInfo } from "../authentication/models.js";
9
9
  import "../providerFilters.js";
10
- import { collectProviderPagedResult, mergeCollectionMetadata, resolveBranchPullRequests } from "./utils/providerPaging.js";
10
+ import { collectProviderPagedResult, mergeCollectionMetadata, readEtagFieldsByRepository, resolveBranchPullRequests } from "./utils/providerPaging.js";
11
11
  import { ProviderPullRequestReviewState, fromProviderPullRequest, getProviderPullRequestIdentity, providersMetadata, toIssueShape, toProviderPullRequestStates } from "./models.js";
12
12
  import { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from "./gitlab/gitlab.utils.js";
13
- import { fromGitLabMergeRequestProvidersApi } from "./gitlab/models.js";
13
+ import { fromGitLabMergeRequestProvidersApi, toGitLabIssueEtagFields, toGitLabPullRequestEtagFields } from "./gitlab/models.js";
14
14
  import { GitHostIntegration } from "../models/gitHostIntegration.js";
15
15
  import * as l10n from "@vscode/l10n";
16
16
  //#region ../plus/integrations/src/providers/gitlab.ts
@@ -108,7 +108,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
108
108
  isPAT: this.isEnterprise,
109
109
  baseUrl: this.enterpriseBaseUrlFor(session)
110
110
  });
111
- const issue = apiResult != null ? toIssueShape(apiResult, this) : void 0;
111
+ const issue = apiResult != null ? toIssueShape(apiResult, this, { projection: "point" }) : void 0;
112
112
  return issue != null ? {
113
113
  ...issue,
114
114
  type: "issue"
@@ -151,7 +151,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
151
151
  baseUrl
152
152
  });
153
153
  if (issue != null) {
154
- const shape = toIssueShape(issue, this);
154
+ const shape = toIssueShape(issue, this, { projection: "batch" });
155
155
  if (shape == null) throw new Error(`GitLab returned issue ${c.number} without a URL or update time`);
156
156
  return shape;
157
157
  }
@@ -180,7 +180,10 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
180
180
  isPAT: this.isEnterprise,
181
181
  baseUrl
182
182
  });
183
- if (pr != null) return fromProviderPullRequest(pr, this, { currentAccount: options?.currentAccount });
183
+ if (pr != null) return fromProviderPullRequest(pr, this, {
184
+ currentAccount: options?.currentAccount,
185
+ projection: "batch"
186
+ });
184
187
  const gitlab = await this.authenticationService.apis.gitlab;
185
188
  if (gitlab == null) throw new IntegrationReadUnavailableError(this.name, "cannot confirm a missing merge request");
186
189
  if (await gitlab.getPullRequest(this, tokenWithInfo, c.owner, c.repo, c.number, {
@@ -191,6 +194,43 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
191
194
  });
192
195
  }
193
196
  /**
197
+ * The cheap check behind the batch issue read's etags: GitLens' own GitLab client reads each project's issues by
198
+ * iid, up to {@link gitLabEtagFieldsMaxIids} in ONE request, where {@link getProviderIssuesBatch} sends one or
199
+ * two per target. Each row is converted as provider-apis and `toIssueShape` convert the full one, so both reads
200
+ * compute the same etag, and `'reactions'` adds the upvote count the full row's `thumbsUpCount` comes from. A
201
+ * request that throws rejects only its own targets' slots.
202
+ */
203
+ async getProviderIssuesEtagFields(session, coordinates, options, cancellation) {
204
+ const gitlab = await this.authenticationService.apis.gitlab;
205
+ if (gitlab == null) return void 0;
206
+ const tokenWithInfo = toTokenWithInfo(this.id, session);
207
+ const baseUrl = this.apiBaseUrlFor(session);
208
+ const etagIncludes = options.etagIncludes ?? [];
209
+ return readEtagFieldsByRepository(coordinates, 100, (owner, repo, iids) => gitlab.getIssuesEtagFields(this, tokenWithInfo, `${owner}/${repo}`, iids, {
210
+ baseUrl,
211
+ etagIncludes,
212
+ deferFailure: true
213
+ }, cancellation), (node) => toGitLabIssueEtagFields(node, etagIncludes));
214
+ }
215
+ /**
216
+ * The cheap check behind the batch pull request read's etags: {@link getProviderIssuesEtagFields}'s requests and
217
+ * failure isolation over merge requests, selecting a merge request's change state plus the fields of each of
218
+ * `options.etagIncludes`. Every include is meaningful here: a full row carries a mergeability, a review decision
219
+ * and a check rollup, each of which can change without moving `updatedAt`.
220
+ */
221
+ async getProviderPullRequestsEtagFields(session, coordinates, options, cancellation) {
222
+ const gitlab = await this.authenticationService.apis.gitlab;
223
+ if (gitlab == null) return void 0;
224
+ const tokenWithInfo = toTokenWithInfo(this.id, session);
225
+ const baseUrl = this.apiBaseUrlFor(session);
226
+ const etagIncludes = options.etagIncludes ?? [];
227
+ return readEtagFieldsByRepository(coordinates, etagIncludes.includes("checks") ? 10 : 100, (owner, repo, iids) => gitlab.getMergeRequestsEtagFields(this, tokenWithInfo, `${owner}/${repo}`, iids, {
228
+ baseUrl,
229
+ etagIncludes,
230
+ deferFailure: true
231
+ }, cancellation), (node) => toGitLabPullRequestEtagFields(node, etagIncludes));
232
+ }
233
+ /**
194
234
  * Two steps, because provider-apis has no source-branch filter: GitLens' own GitLab client finds each branch's
195
235
  * matching iids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is
196
236
  * the one `getPullRequestsBatch` returns for that merge request, `url` and `authoredByMe` included.
@@ -285,7 +325,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
285
325
  const isRequestedReviewer = pr.reviews?.some((review) => review.reviewer?.username === username && review.state === ProviderPullRequestReviewState.ReviewRequested);
286
326
  const isAuthor = pr.author?.username === username;
287
327
  return isAssignee || isRequestedReviewer || isAuthor;
288
- }).map((pr) => fromGitLabMergeRequestProvidersApi(pr, this))], (r) => r.url, (original, _current) => original)];
328
+ }).map((pr) => fromGitLabMergeRequestProvidersApi(pr, this, "search"))], (r) => r.url, (original, _current) => original)];
289
329
  }
290
330
  async getProviderMyPullRequestsForUser(session, options) {
291
331
  const username = (await this.getProviderCurrentAccount(session))?.username;
@@ -370,7 +410,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
370
410
  return (await providerApi.getIssuesForRepos(toTokenWithInfo(this.id, session), repoInput, {
371
411
  isPAT: this.isEnterprise,
372
412
  baseUrl: this.enterpriseBaseUrlFor(session)
373
- })).values.map((issue) => toIssueShape(issue, this)).filter((result) => result != null);
413
+ })).values.map((issue) => toIssueShape(issue, this, { projection: "account" })).filter((result) => result != null);
374
414
  }
375
415
  /**
376
416
  * Account-wide "my issues" for GitLab. GitLab's repo-scoped issue read bails without repos, and GitLab has
@@ -426,7 +466,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
426
466
  return page;
427
467
  }, maxPages, { providerId: this.id });
428
468
  for (const issue of result.values) {
429
- const shape = toIssueShape(issue, this);
469
+ const shape = toIssueShape(issue, this, { projection: "account" });
430
470
  if (shape != null && !issuesByUrl.has(shape.url)) issuesByUrl.set(shape.url, shape);
431
471
  }
432
472
  truncated ||= result.truncated === true;