@gitkraken/core-gitlens 0.7.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/dist/git/cache.d.ts +29 -5
  3. package/dist/git/cache.js +52 -11
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/context.d.ts +6 -1
  6. package/dist/git/context.js.map +1 -1
  7. package/dist/git/errors.d.ts +28 -1
  8. package/dist/git/errors.js +45 -1
  9. package/dist/git/errors.js.map +1 -1
  10. package/dist/git/features.d.ts +1 -1
  11. package/dist/git/features.js +1 -0
  12. package/dist/git/features.js.map +1 -1
  13. package/dist/git/models/reflog.d.ts +6 -0
  14. package/dist/git/models/reflog.js.map +1 -1
  15. package/dist/git/models/revision.d.ts +0 -1
  16. package/dist/git/models/revision.js +1 -2
  17. package/dist/git/models/revision.js.map +1 -1
  18. package/dist/git/providers/branches.d.ts +5 -1
  19. package/dist/git/providers/commits.d.ts +44 -2
  20. package/dist/git/providers/config.d.ts +7 -1
  21. package/dist/git/providers/operations.d.ts +19 -0
  22. package/dist/git/providers/provider.d.ts +29 -2
  23. package/dist/git/providers/refs.d.ts +48 -3
  24. package/dist/git/providers/revision.d.ts +7 -1
  25. package/dist/git/providers/staging.d.ts +13 -0
  26. package/dist/git/providers/stash.d.ts +3 -2
  27. package/dist/git/providers/status.d.ts +4 -0
  28. package/dist/git/providers/worktrees.d.ts +23 -3
  29. package/dist/git/run.types.d.ts +22 -0
  30. package/dist/git-cli/cliGitProvider.d.ts +39 -2
  31. package/dist/git-cli/cliGitProvider.js +109 -11
  32. package/dist/git-cli/cliGitProvider.js.map +1 -1
  33. package/dist/git-cli/exec/commandClassifier.d.ts +31 -0
  34. package/dist/git-cli/exec/commandClassifier.js +391 -0
  35. package/dist/git-cli/exec/commandClassifier.js.map +1 -0
  36. package/dist/git-cli/exec/git.d.ts +36 -5
  37. package/dist/git-cli/exec/git.js +163 -28
  38. package/dist/git-cli/exec/git.js.map +1 -1
  39. package/dist/git-cli/exec/gitQueue.d.ts +4 -1
  40. package/dist/git-cli/exec/gitQueue.js +1 -1
  41. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  42. package/dist/git-cli/parsers/reflogParser.d.ts +7 -0
  43. package/dist/git-cli/parsers/reflogParser.js +11 -1
  44. package/dist/git-cli/parsers/reflogParser.js.map +1 -1
  45. package/dist/git-cli/providers/branches.d.ts +10 -1
  46. package/dist/git-cli/providers/branches.js +31 -22
  47. package/dist/git-cli/providers/branches.js.map +1 -1
  48. package/dist/git-cli/providers/commits.d.ts +27 -3
  49. package/dist/git-cli/providers/commits.js +112 -12
  50. package/dist/git-cli/providers/commits.js.map +1 -1
  51. package/dist/git-cli/providers/config.js +2 -1
  52. package/dist/git-cli/providers/config.js.map +1 -1
  53. package/dist/git-cli/providers/diff.js +4 -4
  54. package/dist/git-cli/providers/diff.js.map +1 -1
  55. package/dist/git-cli/providers/operations.d.ts +13 -0
  56. package/dist/git-cli/providers/operations.js +64 -5
  57. package/dist/git-cli/providers/operations.js.map +1 -1
  58. package/dist/git-cli/providers/patch.js +21 -45
  59. package/dist/git-cli/providers/patch.js.map +1 -1
  60. package/dist/git-cli/providers/refs.d.ts +20 -3
  61. package/dist/git-cli/providers/refs.js +140 -10
  62. package/dist/git-cli/providers/refs.js.map +1 -1
  63. package/dist/git-cli/providers/remotes.js +3 -2
  64. package/dist/git-cli/providers/remotes.js.map +1 -1
  65. package/dist/git-cli/providers/revision.d.ts +5 -1
  66. package/dist/git-cli/providers/revision.js +20 -5
  67. package/dist/git-cli/providers/revision.js.map +1 -1
  68. package/dist/git-cli/providers/staging.d.ts +9 -0
  69. package/dist/git-cli/providers/staging.js +63 -6
  70. package/dist/git-cli/providers/staging.js.map +1 -1
  71. package/dist/git-cli/providers/stash.d.ts +3 -2
  72. package/dist/git-cli/providers/stash.js +34 -22
  73. package/dist/git-cli/providers/stash.js.map +1 -1
  74. package/dist/git-cli/providers/status.d.ts +2 -0
  75. package/dist/git-cli/providers/status.js +27 -9
  76. package/dist/git-cli/providers/status.js.map +1 -1
  77. package/dist/git-cli/providers/worktrees.d.ts +31 -2
  78. package/dist/git-cli/providers/worktrees.js +75 -7
  79. package/dist/git-cli/providers/worktrees.js.map +1 -1
  80. package/dist/plus/git-github/api/github.d.ts +64 -3
  81. package/dist/plus/git-github/api/github.js +237 -24
  82. package/dist/plus/git-github/api/github.js.map +1 -1
  83. package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
  84. package/dist/plus/git-github/providers/github/branches.js +2 -1
  85. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  86. package/dist/plus/git-github/providers/github/commits.d.ts +4 -2
  87. package/dist/plus/git-github/providers/github/commits.js +3 -1
  88. package/dist/plus/git-github/providers/github/commits.js.map +1 -1
  89. package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
  90. package/dist/plus/git-github/providers/github/refs.js +4 -4
  91. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  92. package/dist/plus/git-github/providers/github/revision.d.ts +4 -1
  93. package/dist/plus/git-github/providers/github/revision.js +6 -1
  94. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  95. package/dist/plus/integrations/index.d.ts +5 -2
  96. package/dist/plus/integrations/index.js.map +1 -1
  97. package/dist/plus/integrations/integrationService.d.ts +35 -9
  98. package/dist/plus/integrations/integrationService.js +16 -3
  99. package/dist/plus/integrations/integrationService.js.map +1 -1
  100. package/dist/plus/integrations/manager.d.ts +107 -37
  101. package/dist/plus/integrations/models/gitHostIntegration.d.ts +128 -13
  102. package/dist/plus/integrations/models/gitHostIntegration.js +130 -17
  103. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  104. package/dist/plus/integrations/models/integration.d.ts +51 -3
  105. package/dist/plus/integrations/models/integration.js +125 -18
  106. package/dist/plus/integrations/models/integration.js.map +1 -1
  107. package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
  108. package/dist/plus/integrations/models/issuesIntegration.js +40 -10
  109. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  110. package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
  111. package/dist/plus/integrations/providers/azure/azure.js +13 -17
  112. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  113. package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
  114. package/dist/plus/integrations/providers/azure/models.js +112 -1
  115. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  116. package/dist/plus/integrations/providers/azureDevOps.d.ts +54 -2
  117. package/dist/plus/integrations/providers/azureDevOps.js +80 -2
  118. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  119. package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
  120. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  121. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
  122. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
  123. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  124. package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
  125. package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
  126. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  127. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +1 -1
  128. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  129. package/dist/plus/integrations/providers/bitbucket-server.d.ts +38 -1
  130. package/dist/plus/integrations/providers/bitbucket-server.js +33 -1
  131. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  132. package/dist/plus/integrations/providers/bitbucket.d.ts +36 -1
  133. package/dist/plus/integrations/providers/bitbucket.js +29 -1
  134. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  135. package/dist/plus/integrations/providers/github.d.ts +48 -4
  136. package/dist/plus/integrations/providers/github.js +101 -6
  137. package/dist/plus/integrations/providers/github.js.map +1 -1
  138. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
  139. package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
  140. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  141. package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
  142. package/dist/plus/integrations/providers/gitlab/models.js +1 -1
  143. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  144. package/dist/plus/integrations/providers/gitlab.d.ts +48 -1
  145. package/dist/plus/integrations/providers/gitlab.js +79 -3
  146. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  147. package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
  148. package/dist/plus/integrations/providers/jira-server.js +3 -3
  149. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  150. package/dist/plus/integrations/providers/models.d.ts +12 -1
  151. package/dist/plus/integrations/providers/models.js +11 -1
  152. package/dist/plus/integrations/providers/models.js.map +1 -1
  153. package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
  154. package/dist/plus/integrations/providers/providerErrors.js +10 -1
  155. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  156. package/dist/plus/integrations/providers/providersApi.d.ts +59 -0
  157. package/dist/plus/integrations/providers/providersApi.js +136 -1
  158. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  159. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
  160. package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
  161. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  162. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  163. package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
  164. package/dist/plus/integrations/reads/currentAccount.js +46 -0
  165. package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
  166. package/dist/plus/integrations/reads/drains.d.ts +4 -1
  167. package/dist/plus/integrations/reads/drains.js +7 -3
  168. package/dist/plus/integrations/reads/drains.js.map +1 -1
  169. package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
  170. package/dist/plus/integrations/reads/issueBatch.js +193 -48
  171. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  172. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
  173. package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
  174. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
  175. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
  176. package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
  177. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
  178. package/dist/plus/integrations/reads/pullRequests.js +3 -3
  179. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  180. package/dist/plus/integrations/reads/sweeps.js +3 -3
  181. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  182. package/dist/plus/integrations/results.d.ts +5 -2
  183. package/dist/plus/integrations/results.js.map +1 -1
  184. package/dist/utils/env/node/exec.js +1 -1
  185. package/dist/utils/env/node/exec.js.map +1 -1
  186. package/docs/integrations.md +90 -36
  187. package/docs/kepler-git-write-api-parity.md +365 -0
  188. package/docs/kepler-read-api-parity.md +75 -28
  189. package/package.json +1 -1
  190. package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
  191. package/dist/plus/integrations/reads/trackerIssue.js +0 -60
  192. package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
@@ -5,13 +5,14 @@ import { getScopedLogger } from "../../../../utils/logger.scoped.js";
5
5
  import { trace } from "../../../../utils/decorators/log.js";
6
6
  import { joinUriPath, parseUri } from "../../../../utils/uri.js";
7
7
  import __decorate from "../../../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
8
- import { AuthenticationError, RequestClientError, RequestNotFoundError } from "../../../../git/errors.js";
8
+ import { AuthenticationError, RequestClientError, RequestNotFoundError, reportRequestFailure } from "../../../../git/errors.js";
9
9
  import { maybeStopWatch } from "../../../../utils/stopwatch.js";
10
10
  import { PullRequest } from "../../../../git/models/pullRequest.js";
11
11
  import { ProviderFetchError, isRateLimitResponse, toRateLimitError } from "../../errors.js";
12
+ import { selectBranchPullRequests } from "../utils/providerPaging.js";
12
13
  import { baseProviderApiConfig } from "../apiConfig.js";
13
14
  import { selectGitLabUserForCommit } from "./gitlab.utils.js";
14
- import { fromGitLabMergeRequest, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, toGitLabMergeRequestState } from "./models.js";
15
+ import { fromGitLabMergeRequest, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, getRepoNamespace, toGitLabMergeRequestState } from "./models.js";
15
16
  import * as l10n from "@vscode/l10n";
16
17
  //#region ../plus/integrations/src/providers/gitlab/gitlab.ts
17
18
  const gitlabUserIdPrefix = "gid://gitlab/User/";
@@ -194,6 +195,33 @@ var GitLabApi = class {
194
195
  throw this.handleException(ex, provider, scope);
195
196
  }
196
197
  }
198
+ /**
199
+ * Whether `owner/repo` has issue `iid`. Strict like {@link getPullRequest}'s `strict`: `false` only for a `null`
200
+ * project or issue, which is how GitLab's GraphQL answers a missing one; GraphQL `errors`, an empty response and
201
+ * any HTTP error (a 404 means a wrong endpoint) all throw instead of reading as absent.
202
+ */
203
+ async hasIssue(provider, token, owner, repo, iid, options, cancellation) {
204
+ const scope = getScopedLogger();
205
+ try {
206
+ const rsp = await this.graphql(provider, token, options.baseUrl, `query hasIssue(
207
+ $fullPath: ID!
208
+ $iid: String!
209
+ ) {
210
+ project(fullPath: $fullPath) {
211
+ issue(iid: $iid) {
212
+ iid
213
+ }
214
+ }
215
+ }`, {
216
+ fullPath: `${owner}/${repo}`,
217
+ iid: String(iid)
218
+ }, cancellation, scope, options.deferFailure);
219
+ if (rsp?.data == null) throw new Error("GitLab returned no data for the issue");
220
+ return rsp.data.project?.issue != null;
221
+ } catch (ex) {
222
+ throw this.handleException(ex, provider, scope);
223
+ }
224
+ }
197
225
  async getPullRequestForBranch(provider, token, owner, repo, branch, options, cancellation) {
198
226
  const scope = getScopedLogger();
199
227
  try {
@@ -324,12 +352,91 @@ var GitLabApi = class {
324
352
  }`, {
325
353
  fullPath: `${owner}/${repo}`,
326
354
  iid: String(id)
327
- }, cancellation, scope);
328
- if (rsp?.data?.project?.mergeRequest == null) return void 0;
355
+ }, cancellation, scope, options?.deferFailure);
356
+ if (rsp?.data == null) {
357
+ if (options?.strict) throw new Error("GitLab returned no data for the merge request");
358
+ return;
359
+ }
360
+ if (rsp.data.project?.mergeRequest == null) return void 0;
329
361
  const pr = rsp.data.project.mergeRequest;
330
362
  return fromGitLabMergeRequest(pr, provider);
331
363
  } catch (ex) {
332
- if (ex instanceof RequestNotFoundError) return void 0;
364
+ if (!options?.strict && ex instanceof RequestNotFoundError) return void 0;
365
+ throw this.handleException(ex, provider, scope);
366
+ }
367
+ }
368
+ /**
369
+ * The iids of the merge requests into `owner/repo` whose source is `branch`, in any state, newest first, at most
370
+ * `limit`: from the project itself when `headOwner` is omitted, otherwise from a fork in the `headOwner`
371
+ * namespace. Only the iids, so a caller resolves the rows through the same read as its by-number lookups.
372
+ *
373
+ * Keyed on the source branch NAME, so a merged request whose branch was deleted still matches. Strict like
374
+ * {@link getPullRequest}'s `strict`: an empty list means GitLab answered, a `null` project included; a 404 or
375
+ * an empty response means the endpoint is wrong and throws. Requests from a deleted fork carry no source
376
+ * project and so match nothing.
377
+ */
378
+ async getPullRequestNumbersForBranch(provider, token, owner, repo, branch, options, cancellation) {
379
+ const scope = getScopedLogger();
380
+ try {
381
+ const rsp = await this.graphql(provider, token, options.baseUrl, `query getMergeRequestsForBranch(
382
+ $fullPath: ID!
383
+ $branches: [String!]
384
+ $limit: Int!
385
+ ) {
386
+ project(fullPath: $fullPath) {
387
+ mergeRequests(sourceBranches: $branches, state: all, sort: UPDATED_DESC, first: $limit) {
388
+ count
389
+ pageInfo {
390
+ hasNextPage
391
+ }
392
+ nodes {
393
+ iid
394
+ updatedAt
395
+ sourceBranch
396
+ project {
397
+ id
398
+ }
399
+ sourceProject {
400
+ id
401
+ fullPath
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }`, {
407
+ fullPath: `${owner}/${repo}`,
408
+ branches: [branch],
409
+ limit: options.limit
410
+ }, cancellation, scope, options.deferFailure);
411
+ if (rsp?.data == null) throw new Error("GitLab returned no data for the merge requests by branch");
412
+ const project = rsp.data.project;
413
+ if (project == null) return {
414
+ numbers: [],
415
+ truncated: false
416
+ };
417
+ const connection = project.mergeRequests;
418
+ if (connection == null) throw new Error(`GitLab returned no merge requests for ${owner}/${repo}:${branch}`);
419
+ const headOwner = options.headOwner;
420
+ const { values, truncated } = selectBranchPullRequests(connection.nodes, {
421
+ matchesHead: (mr) => {
422
+ if (mr.sourceBranch !== branch || mr.sourceProject == null) return false;
423
+ if (headOwner == null) return mr.sourceProject.id === mr.project.id;
424
+ return mr.sourceProject.id !== mr.project.id && equalsIgnoreCase(getRepoNamespace(mr.sourceProject.fullPath), headOwner);
425
+ },
426
+ updatedAt: (mr) => Date.parse(mr.updatedAt),
427
+ map: (mr) => {
428
+ const iid = Number(mr.iid);
429
+ if (!Number.isSafeInteger(iid)) throw new Error(`GitLab returned a merge request iid '${mr.iid}'`);
430
+ return iid;
431
+ },
432
+ limit: options.limit,
433
+ more: connection.pageInfo.hasNextPage || connection.count > connection.nodes.length
434
+ });
435
+ return {
436
+ numbers: values,
437
+ truncated
438
+ };
439
+ } catch (ex) {
333
440
  throw this.handleException(ex, provider, scope);
334
441
  }
335
442
  }
@@ -505,7 +612,7 @@ $search: String!
505
612
  return;
506
613
  }
507
614
  }
508
- async graphql(provider, token, baseUrl, query, variables, cancellation, scope) {
615
+ async graphql(provider, token, baseUrl, query, variables, cancellation, scope, deferFailure) {
509
616
  const { accessToken } = token;
510
617
  let rsp;
511
618
  try {
@@ -535,7 +642,7 @@ $search: String!
535
642
  sw?.stop({ message });
536
643
  }
537
644
  } catch (ex) {
538
- if (ex instanceof ProviderFetchError || ex.name === "AbortError") this.handleRequestError(provider, token, ex, scope);
645
+ if (ex instanceof ProviderFetchError || ex.name === "AbortError") this.handleRequestError(provider, token, ex, scope, deferFailure);
539
646
  else if (_logger.isDebugging) this.config.onError?.(`GitLab request failed: ${ex.message}`);
540
647
  throw ex;
541
648
  }
@@ -562,12 +669,12 @@ $search: String!
562
669
  sw?.stop();
563
670
  }
564
671
  } catch (ex) {
565
- if (ex instanceof ProviderFetchError || ex.name === "AbortError") this.handleRequestError(provider, token, ex, scope);
672
+ if (ex instanceof ProviderFetchError || ex.name === "AbortError") this.handleRequestError(provider, token, ex, scope, void 0);
566
673
  else if (_logger.isDebugging) this.config.onError?.(`GitLab request failed: ${ex.message}`);
567
674
  throw ex;
568
675
  }
569
676
  }
570
- handleRequestError(provider, token, ex, scope) {
677
+ handleRequestError(provider, token, ex, scope, deferFailure) {
571
678
  if (ex.name === "AbortError" || !(ex instanceof ProviderFetchError)) throw new CancellationError(ex);
572
679
  const { accessToken, ...tokenInfo } = token;
573
680
  switch (ex.status) {
@@ -581,16 +688,12 @@ $search: String!
581
688
  throw new AuthenticationError(tokenInfo, 3, ex);
582
689
  case 500:
583
690
  scope?.error(ex);
584
- if (ex.response != null) {
585
- provider?.trackRequestException();
586
- this.config.onRequestFailed?.(provider == null || provider.id === "gitlab" ? l10n.t("{0} failed to respond and might be experiencing issues. Please visit the [GitLab status page](https://status.gitlab.com) for more information.", provider?.name ?? "GitLab") : l10n.t("{0} failed to respond and might be experiencing issues.", provider.name));
587
- }
691
+ if (ex.response != null) reportRequestFailure(provider, ex, () => this.config.onRequestFailed?.(provider == null || provider.id === "gitlab" ? l10n.t("{0} failed to respond and might be experiencing issues. Please visit the [GitLab status page](https://status.gitlab.com) for more information.", provider?.name ?? "GitLab") : l10n.t("{0} failed to respond and might be experiencing issues.", provider.name)), deferFailure);
588
692
  return;
589
693
  case 502:
590
694
  scope?.error(ex);
591
695
  if (ex.message.includes("timeout")) {
592
- provider?.trackRequestException();
593
- this.config.onRequestTimedOut?.(provider?.name ?? "GitLab");
696
+ reportRequestFailure(provider, ex, () => this.config.onRequestTimedOut?.(provider?.name ?? "GitLab"), deferFailure);
594
697
  return;
595
698
  }
596
699
  break;
@@ -643,6 +746,13 @@ __decorate([trace({ args: (provider, token, owner, repo, number) => ({
643
746
  repo,
644
747
  number
645
748
  }) })], GitLabApi.prototype, "getIssueOrPullRequest", null);
749
+ __decorate([trace({ args: (provider, token, owner, repo, iid) => ({
750
+ provider: provider.name,
751
+ token: `<token:${token.microHash}>`,
752
+ owner,
753
+ repo,
754
+ iid
755
+ }) })], GitLabApi.prototype, "hasIssue", null);
646
756
  __decorate([trace({ args: (provider, token, owner, repo, branch) => ({
647
757
  provider: provider.name,
648
758
  token: `<token:${token.microHash}>`,
@@ -664,6 +774,13 @@ __decorate([trace({ args: (provider, token, owner, repo, id) => ({
664
774
  repo,
665
775
  id
666
776
  }) })], GitLabApi.prototype, "getPullRequest", null);
777
+ __decorate([trace({ args: (provider, token, owner, repo, branch) => ({
778
+ provider: provider.name,
779
+ token: `<token:${token.microHash}>`,
780
+ owner,
781
+ repo,
782
+ branch
783
+ }) })], GitLabApi.prototype, "getPullRequestNumbersForBranch", null);
667
784
  __decorate([trace({ args: (provider, token, owner, repo) => ({
668
785
  provider: provider.name,
669
786
  token: `<token:${token.microHash}>`,
@@ -1 +1 @@
1
- {"version":3,"file":"gitlab.js","names":["Logger"],"sources":["../../../../../../plus/integrations/src/providers/gitlab/gitlab.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport type { Account } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { IssueOrPullRequest } from '@gitlens/git/models/issueOrPullRequest.js';\nimport { PullRequest } from '@gitlens/git/models/pullRequest.js';\nimport type { PullRequestState } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { trace } from '@gitlens/utils/decorators/log.js';\nimport type { Disposable } from '@gitlens/utils/disposable.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport type { ScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { maybeStopWatch } from '@gitlens/utils/stopwatch.js';\nimport { equalsIgnoreCase } from '@gitlens/utils/string.js';\nimport { joinUriPath, parseUri } from '@gitlens/utils/uri.js';\nimport type { TokenWithInfo } from '../../authentication/models.js';\nimport type { IntegrationServiceContext } from '../../context.js';\nimport {\n\tAuthenticationError,\n\tAuthenticationErrorReason,\n\tisRateLimitResponse,\n\tProviderFetchError,\n\tRequestClientError,\n\tRequestNotFoundError,\n\ttoRateLimitError,\n} from '../../errors.js';\nimport type { ProviderApiConfig } from '../apiConfig.js';\nimport { baseProviderApiConfig } from '../apiConfig.js';\nimport { selectGitLabUserForCommit } from './gitlab.utils.js';\nimport type {\n\tGitLabCommit,\n\tGitLabIssue,\n\tGitLabMergeRequest,\n\tGitLabMergeRequestFull,\n\tGitLabMergeRequestREST,\n\tGitLabMergeRequestState,\n\tGitLabProjectREST,\n\tGitLabSshKey,\n\tGitLabUser,\n} from './models.js';\nimport {\n\tfromGitLabMergeRequest,\n\tfromGitLabMergeRequestREST,\n\tfromGitLabMergeRequestState,\n\ttoGitLabMergeRequestState,\n} from './models.js';\n\n// drop it as soon as we switch to @gitkraken/providers-api\nconst gitlabUserIdPrefix = 'gid://gitlab/User/';\nconst gitlabMergeRequestIdPrefix = 'gid://gitlab/MergeRequest/';\n\nfunction buildGitLabUserId(id: string | number | undefined): string | undefined {\n\treturn typeof id === 'string' && id?.startsWith(gitlabUserIdPrefix)\n\t\t? id.substring(gitlabUserIdPrefix.length)\n\t\t: String(id);\n}\n\nexport class GitLabApi implements Disposable {\n\tprivate readonly _disposable: Disposable | undefined;\n\tprivate _projectIds = new Map<string, Promise<string | undefined>>();\n\n\tconstructor(private readonly config: ProviderApiConfig) {\n\t\tthis._disposable = config.onConfigChanged?.(() => this.resetCaches());\n\t}\n\n\tdispose(): void {\n\t\tthis._disposable?.dispose();\n\t}\n\n\tprivate resetCaches(): void {\n\t\tthis._projectIds.clear();\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, rev) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\trev: rev,\n\t\t}),\n\t})\n\tasync getAccountForCommit(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<Account | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst commit = await this.request<GitLabCommit>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}/repository/commits/${rev}?stats=false`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tlet users = await this.findUser(provider, token, commit.author_name, options, cancellation);\n\t\t\tlet user = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);\n\n\t\t\t// If the name search was ambiguous (multiple users share the name), try an email-scoped search to\n\t\t\t// disambiguate before giving up — otherwise we'd show a stranger's avatar (see #2205)\n\t\t\tif (user == null && commit.author_email) {\n\t\t\t\tconst exactNameMatches = users.filter(u => equalsIgnoreCase(u.name, commit.author_name)).length;\n\t\t\t\tif (exactNameMatches > 1) {\n\t\t\t\t\tusers = await this.findUser(provider, token, commit.author_email, options, cancellation);\n\t\t\t\t\tuser = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (user == null) return undefined;\n\n\t\t\t// If the avatarUrl is a relative URL, make it absolute using the webUrl (assuming the webUrl is the root URL with the username tacked on)\n\t\t\tif (user.avatarUrl && !/^([a-zA-Z][\\w+.-]+):/.test(user.avatarUrl)) {\n\t\t\t\tuser.avatarUrl = joinUriPath(parseUri(user.webUrl), '..', user.avatarUrl).toString();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tid: String(user.id),\n\t\t\t\tname: user.name || undefined,\n\t\t\t\temail: commit.author_email || undefined,\n\t\t\t\tavatarUrl: user.avatarUrl || undefined,\n\t\t\t\tusername: user.username || undefined,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, _owner, _repo, email) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\temail: email,\n\t\t}),\n\t})\n\tasync getAccountForEmail(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\t_owner: string,\n\t\t_repo: string,\n\t\temail: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\ttry {\n\t\t\tconst [user] = await this.findUser(provider, token, email, options);\n\t\t\tif (user == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tid: String(user.id),\n\t\t\t\tname: user.name || undefined,\n\t\t\t\temail: user.publicEmail || undefined,\n\t\t\t\tavatarUrl: user.avatarUrl || undefined,\n\t\t\t\tusername: user.username || undefined,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, userId) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\tuserId: userId,\n\t\t}),\n\t})\n\tasync getUserSigningKeys(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tuserId: string | number,\n\t\toptions?: { baseUrl?: string },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitLabSshKey[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\t// SSH keys are public, so this works for any user with the current token (covered by the `read_user` scope).\n\t\ttry {\n\t\t\tconst keys = await this.request<GitLabSshKey[]>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/users/${userId}/keys`,\n\t\t\t\t{ method: 'GET' },\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\t// Exclude auth-only keys — only signing-capable keys belong in an allowed_signers file.\n\t\t\treturn keys?.filter(k => k.usage_type === 'signing' || k.usage_type === 'auth_and_signing') ?? [];\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t}),\n\t})\n\tasync getDefaultBranch(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<DefaultBranch | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject:\n\t\t\t\t\t| {\n\t\t\t\t\t\t\trepository: { rootRef: string } | null | undefined;\n\t\t\t\t\t }\n\t\t\t\t\t| null\n\t\t\t\t\t| undefined;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getDefaultBranch(\n\t$fullPath: ID!\n) {\n\tproject(fullPath: $fullPath) {\n\t\trepository {\n\t\t\trootRef\n\t\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst defaultBranch = rsp?.data?.project?.repository?.rootRef ?? undefined;\n\t\t\tif (defaultBranch == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tname: defaultBranch,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, number) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tnumber: number,\n\t\t}),\n\t})\n\tasync getIssueOrPullRequest(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tnumber: number,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequest: GitLabMergeRequest | null;\n\t\t\t\t\tissue: GitLabIssue | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getIssueOrMergeRequest(\n\t$fullPath: ID!\n\t$iid: String!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequest(iid: $iid) {\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tiid\n\t\t\ttitle\n\t\t\tdescription\n\t\t\tstate\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tmergedAt\n\t\t\twebUrl\n\t\t}\n\t\tissue(iid: $iid) {\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tiid\n\t\t\ttitle\n\t\t\tdescription\n\t\t\tstate\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tclosedAt\n\t\t\twebUrl\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tiid: String(number),\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tif (rsp?.data?.project?.issue != null) {\n\t\t\t\tconst issue = rsp.data.project.issue;\n\t\t\t\treturn {\n\t\t\t\t\tprovider: provider,\n\t\t\t\t\ttype: 'issue',\n\t\t\t\t\tid: issue.iid,\n\t\t\t\t\tnodeId: undefined,\n\t\t\t\t\tcreatedDate: new Date(issue.createdAt),\n\t\t\t\t\tupdatedDate: new Date(issue.updatedAt),\n\t\t\t\t\ttitle: issue.title,\n\t\t\t\t\tclosed: issue.state === 'closed',\n\t\t\t\t\tclosedDate: issue.closedAt == null ? undefined : new Date(issue.closedAt),\n\t\t\t\t\turl: issue.webUrl,\n\t\t\t\t\tstate: issue.state === 'locked' ? 'closed' : issue.state,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rsp?.data?.project?.mergeRequest != null) {\n\t\t\t\tconst mergeRequest = rsp.data.project.mergeRequest;\n\t\t\t\treturn {\n\t\t\t\t\tprovider: provider,\n\t\t\t\t\ttype: 'pullrequest',\n\t\t\t\t\tid: mergeRequest.iid,\n\t\t\t\t\tnodeId: undefined,\n\t\t\t\t\tcreatedDate: new Date(mergeRequest.createdAt),\n\t\t\t\t\tupdatedDate: new Date(mergeRequest.updatedAt),\n\t\t\t\t\ttitle: mergeRequest.title,\n\t\t\t\t\tclosed: mergeRequest.state === 'closed',\n\t\t\t\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\t\t\t\tclosedDate: mergeRequest.state === 'closed' ? new Date(mergeRequest.updatedAt) : undefined,\n\t\t\t\t\turl: mergeRequest.webUrl,\n\t\t\t\t\tstate: mergeRequest.state === 'locked' ? 'closed' : mergeRequest.state,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, branch) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tbranch: branch,\n\t\t}),\n\t})\n\tasync getPullRequestForBranch(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tbranch: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: GitLabMergeRequestState[];\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequests?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\topened?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\tclosed?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\tmerged?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst fragment = `\n\t\t\tnodes {\n\t\t\t\tiid\n\t\t\t\tauthor {\n\t\t\t\t\tid\n\t\t\t\t\tname\n\t\t\t\t\tavatarUrl\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t\ttitle\n\t\t\t\tdescription\n\t\t\t\tstate\n\t\t\t\tcreatedAt\n\t\t\t\tupdatedAt\n\t\t\t\tmergedAt\n\t\t\t\twebUrl\n\t\t\t}`;\n\n\t\t\tconst query = `query getMergeRequestForBranch(\n\t$fullPath: ID!\n\t$branches: [String!]\n) {\n\tproject(fullPath: $fullPath) {\n\t\t${\n\t\t\toptions?.include == null\n\t\t\t\t? `mergeRequests(sourceBranches: $branches sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('opened')\n\t\t\t\t? `opened: mergeRequests(sourceBranches: $branches state: opened sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('merged')\n\t\t\t\t? `merged: mergeRequests(sourceBranches: $branches state: merged sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('closed')\n\t\t\t\t? `closed: mergeRequests(sourceBranches: $branches state: closed sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tbranches: [branch],\n\t\t\t\t\tstate: options?.include,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tlet pr: GitLabMergeRequest | undefined;\n\n\t\t\tif (options?.include == null) {\n\t\t\t\tpr = rsp?.data?.project?.mergeRequests?.nodes?.[0];\n\t\t\t} else {\n\t\t\t\tfor (const state of options.include) {\n\t\t\t\t\tlet mr;\n\t\t\t\t\tif (state === 'opened') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.opened?.nodes?.[0];\n\t\t\t\t\t} else if (state === 'merged') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.merged?.nodes?.[0];\n\t\t\t\t\t} else if (state === 'closed') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.closed?.nodes?.[0];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mr != null && (pr == null || new Date(mr.updatedAt) > new Date(pr.updatedAt))) {\n\t\t\t\t\t\tpr = mr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pr == null) return undefined;\n\n\t\t\treturn new PullRequest(\n\t\t\t\tprovider,\n\t\t\t\t{\n\t\t\t\t\tid: buildGitLabUserId(pr.author?.id) ?? '',\n\t\t\t\t\t// An absent author stays absent: no `'Unknown'` name a consumer can't tell from a real one, and no\n\t\t\t\t\t// `''` url/avatar that passes a presence check and renders as a link to nowhere. Matches\n\t\t\t\t\t// `fromProviderAccount`/`toIssueShape`.\n\t\t\t\t\tname: pr.author?.name ?? undefined,\n\t\t\t\t\tavatarUrl: pr.author?.avatarUrl ?? undefined,\n\t\t\t\t\turl: pr.author?.webUrl ?? undefined,\n\t\t\t\t},\n\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\tString(pr.iid),\n\t\t\t\tundefined,\n\t\t\t\tpr.title,\n\t\t\t\tpr.webUrl,\n\t\t\t\t{ owner: owner, repo: repo },\n\t\t\t\tfromGitLabMergeRequestState(pr.state),\n\t\t\t\tnew Date(pr.createdAt),\n\t\t\t\tnew Date(pr.updatedAt),\n\t\t\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\t\t\tpr.state !== 'closed' ? undefined : new Date(pr.updatedAt),\n\t\t\t\tpr.mergedAt == null ? undefined : new Date(pr.mergedAt),\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, rev) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\trev: rev,\n\t\t}),\n\t})\n\tasync getPullRequestForCommit(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst mrs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}/repository/commits/${rev}/merge_requests`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (mrs == null || mrs.length === 0) return undefined;\n\n\t\t\tif (mrs.length > 1) {\n\t\t\t\tmrs.sort(\n\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t(a.state === 'opened' ? -1 : 1) - (b.state === 'opened' ? -1 : 1) ||\n\t\t\t\t\t\tnew Date(b.updated_at).getTime() - new Date(a.updated_at).getTime(),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn fromGitLabMergeRequestREST(mrs[0], provider, { owner: owner, repo: repo });\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, id) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tid: id,\n\t\t}),\n\t})\n\tasync getPullRequest(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tid: number,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequest: GitLabMergeRequestFull | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getMergeRequest(\n\t$fullPath: ID!\n\t$iid: String!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequest(iid: $iid) {\n\t\t\tid,\n\t\t\tiid\n\t\t\tstate,\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tdiffRefs {\n\t\t\t\tbaseSha\n\t\t\t\theadSha\n\t\t\t}\n\t\t\ttitle\n\t\t\tdescription\n\t\t\twebUrl\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tmergedAt\n\t\t\ttargetBranch\n\t\t\tsourceBranch\n\t\t\tproject {\n\t\t\t\tid\n\t\t\t\tfullPath\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tsourceProject {\n\t\t\t\tid\n\t\t\t\tfullPath\n\t\t\t\twebUrl\n\t\t\t}\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tiid: String(id),\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tif (rsp?.data?.project?.mergeRequest == null) return undefined;\n\n\t\t\tconst pr = rsp.data.project.mergeRequest;\n\t\t\treturn fromGitLabMergeRequest(pr, provider);\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t}),\n\t})\n\tasync getRepositoryMetadata(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst proj = await this.request<GitLabProjectREST>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (proj == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\towner: proj.namespace.full_path,\n\t\t\t\tname: proj.path,\n\t\t\t\tisFork: proj.forked_from_project != null,\n\t\t\t\tparent:\n\t\t\t\t\tproj.forked_from_project != null\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\towner: proj.forked_from_project.namespace.full_path,\n\t\t\t\t\t\t\t\tname: proj.forked_from_project.path,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t} satisfies RepositoryMetadata;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })\n\tasync searchPullRequests(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\toptions?: {\n\t\t\tsearch?: string;\n\t\t\tuser?: string;\n\t\t\trepos?: string[];\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest[]> {\n\t\tconst scope = getScopedLogger();\n\t\tconst search = options?.search;\n\t\tif (!search) {\n\t\t\treturn [];\n\t\t}\n\n\t\ttry {\n\t\t\tconst perPageLimit = 20; // with bigger amount we exceed the max GraphQL complexity in the next query\n\t\t\tconst include = options?.include?.length ? options.include : undefined;\n\t\t\t// GitLab's search API takes a single `state` value, so push it server-side when exactly one state is\n\t\t\t// requested; that keeps the requested state from being crowded out of the `perPageLimit` slice. For\n\t\t\t// multiple states there's no single-value qualifier, so those are filtered client-side below.\n\t\t\tlet searchPath = `v4/search/?scope=merge_requests&search=${encodeURIComponent(search)}&per_page=${perPageLimit}`;\n\t\t\tif (include?.length === 1) {\n\t\t\t\tsearchPath += `&state=${encodeURIComponent(toGitLabMergeRequestState(include[0]))}`;\n\t\t\t}\n\n\t\t\tlet restPRs: GitLabMergeRequestREST[];\n\t\t\tif (include == null) {\n\t\t\t\t// Unfiltered search returns the first page as-is (as it did before state filtering existed).\n\t\t\t\trestPRs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\t\tprovider,\n\t\t\t\t\ttoken,\n\t\t\t\t\toptions?.baseUrl,\n\t\t\t\t\tsearchPath,\n\t\t\t\t\t{ method: 'GET' },\n\t\t\t\t\tcancellation,\n\t\t\t\t\tscope,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// The search API returns MRs of all states in relevance order, so the requested state(s) may not\n\t\t\t\t// appear on the first page. Server-side `&state=` narrows the single-state case when honored, but it\n\t\t\t\t// can't express multiple states, so page through the results and accumulate matches until we fill the\n\t\t\t\t// detail-query cap (`perPageLimit`) or exhaust the search results. This keeps correctness whether\n\t\t\t\t// or not `&state=` takes effect. Bounded by `maxSearchPages` like the other paged provider drains in\n\t\t\t\t// this package so a large, low-match result set can't fan out into an unbounded request loop.\n\t\t\t\tconst maxSearchPages = 20;\n\t\t\t\tconst matches: GitLabMergeRequestREST[] = [];\n\t\t\t\tfor (let page = 1; page <= maxSearchPages; page++) {\n\t\t\t\t\tconst pagePRs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t\toptions?.baseUrl,\n\t\t\t\t\t\t`${searchPath}&page=${page}`,\n\t\t\t\t\t\t{ method: 'GET' },\n\t\t\t\t\t\tcancellation,\n\t\t\t\t\t\tscope,\n\t\t\t\t\t);\n\t\t\t\t\tfor (const pr of pagePRs) {\n\t\t\t\t\t\tif (include.includes(fromGitLabMergeRequestState(pr.state))) {\n\t\t\t\t\t\t\tmatches.push(pr);\n\t\t\t\t\t\t\tif (matches.length >= perPageLimit) break;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Stop once we've filled the cap or hit the last (partial or empty) page.\n\t\t\t\t\tif (matches.length >= perPageLimit || pagePRs.length < perPageLimit) break;\n\t\t\t\t}\n\t\t\t\trestPRs = matches;\n\t\t\t}\n\t\t\tif (restPRs.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tinterface QueryResult {\n\t\t\t\tdata: Record<`mergeRequest_${number}`, GitLabMergeRequestFull>;\n\t\t\t}\n\n\t\t\tconst queryArgs = restPRs.map((_, i) => `$id_${i}: MergeRequestID!`).join('\\n');\n\t\t\tconst queryFields = restPRs\n\t\t\t\t.map((_, i) => `mergeRequest_${i}: mergeRequest(id: $id_${i}) { ...mergeRequestFields }`)\n\t\t\t\t.join('\\n');\n\t\t\t// Set of fields includes only additional fields that are not included in GitLabMergeRequestREST.\n\t\t\t// It's limited as much as possible to reduce complexity of the query.\n\t\t\tconst queryMrFields = `fragment mergeRequestFields on MergeRequest {\n\t\t\t\tdiffRefs {\n\t\t\t\t\tbaseSha\n\t\t\t\t\theadSha\n\t\t\t\t}\n\t\t\t\tproject {\n\t\t\t\t\tid\n\t\t\t\t\tfullPath\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t\tsourceProject {\n\t\t\t\t\tid\n\t\t\t\t\tfullPath\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t}`;\n\t\t\tconst query = `query getMergeRequests (${queryArgs}) {${queryFields}} ${queryMrFields}`;\n\n\t\t\tconst params = restPRs.reduce<Record<`id_${number}`, string>>((ids, gitlabRestPr, i) => {\n\t\t\t\tids[`id_${i}`] = `${gitlabMergeRequestIdPrefix}${gitlabRestPr.id}`;\n\t\t\t\treturn ids;\n\t\t\t}, {});\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\tparams,\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (rsp?.data != null) {\n\t\t\t\tconst resultPRs = restPRs.reduce<PullRequest[]>((accum, restPR, i) => {\n\t\t\t\t\tconst graphQlPR = rsp.data[`mergeRequest_${i}`];\n\t\t\t\t\tif (graphQlPR == null) {\n\t\t\t\t\t\treturn accum;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fullPr: GitLabMergeRequestFull = {\n\t\t\t\t\t\t...graphQlPR,\n\t\t\t\t\t\tiid: String(restPR.iid),\n\t\t\t\t\t\tid: String(restPR.id),\n\t\t\t\t\t\tstate: restPR.state,\n\t\t\t\t\t\t// An absent REST author stays absent (`null`, as GitLab's own shape expresses it) rather than a\n\t\t\t\t\t\t// synthesized `'Unknown'` stub: `fromGitLabMergeRequest` collapses `null` to an absent\n\t\t\t\t\t\t// `PullRequestMember.name`, whereas a placeholder here would launder into a real-looking name.\n\t\t\t\t\t\tauthor:\n\t\t\t\t\t\t\trestPR.author != null\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tid: buildGitLabUserId(restPR.author.id) ?? '',\n\t\t\t\t\t\t\t\t\t\tname: restPR.author.name,\n\t\t\t\t\t\t\t\t\t\tavatarUrl: restPR.author.avatar_url ?? null,\n\t\t\t\t\t\t\t\t\t\twebUrl: restPR.author.web_url,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\ttitle: restPR.title,\n\t\t\t\t\t\tdescription: restPR.description,\n\t\t\t\t\t\twebUrl: restPR.web_url,\n\t\t\t\t\t\tcreatedAt: restPR.created_at,\n\t\t\t\t\t\tupdatedAt: restPR.updated_at,\n\t\t\t\t\t\tmergedAt: restPR.merged_at,\n\t\t\t\t\t\tsourceBranch: restPR.source_branch,\n\t\t\t\t\t\ttargetBranch: restPR.target_branch,\n\t\t\t\t\t};\n\t\t\t\t\taccum.push(fromGitLabMergeRequest(fullPr, provider));\n\t\t\t\t\treturn accum;\n\t\t\t\t}, []);\n\t\t\t\treturn resultPRs;\n\t\t\t}\n\t\t\treturn [];\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\tprivate async findUser(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tsearch: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitLabUser[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tusers: {\n\t\t\t\t\tnodes: {\n\t\t\t\t\t\tid: string;\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\tusername: string;\n\t\t\t\t\t\tpublicEmail?: string;\n\t\t\t\t\t\tstate: string;\n\t\t\t\t\t\tavatarUrl: string;\n\t\t\t\t\t\twebUrl: string;\n\t\t\t\t\t}[];\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query findUser(\n$search: String!\n) {\n\tusers(search: $search) {\n\t\tnodes {\n\t\t\tid\n\t\t\tname\n\t\t\tusername,\n\t\t\tpublicEmail,\n\t\t\tstate\n\t\t\tavatarUrl\n\t\t\twebUrl\n\t\t}\n\t}\n}`;\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tsearch: search,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst matches = rsp?.data?.users?.nodes;\n\t\t\tif (matches == null || matches.length === 0) return [];\n\n\t\t\tconst users: GitLabUser[] = [];\n\n\t\t\tfor (const user of matches) {\n\t\t\t\tconst match = /gid:\\/\\/gitlab\\/User\\/([0-9]+)\\b/.exec(user.id);\n\t\t\t\tif (match == null) continue;\n\n\t\t\t\tusers.push({\n\t\t\t\t\tid: parseInt(match[1], 10),\n\t\t\t\t\tname: user.name,\n\t\t\t\t\tusername: user.username,\n\t\t\t\t\tpublicEmail: user.publicEmail || undefined,\n\t\t\t\t\tstate: user.state,\n\t\t\t\t\tavatarUrl: user.avatarUrl,\n\t\t\t\t\twebUrl: user.webUrl,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn users;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tgetProjectId(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tgroup: string,\n\t\trepo: string,\n\t\tbaseUrl: string | undefined,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<string | undefined> {\n\t\tconst { accessToken } = token;\n\t\tconst key = `${accessToken}|${group}/${repo}`;\n\n\t\tlet projectId = this._projectIds.get(key);\n\t\tif (projectId == null) {\n\t\t\tprojectId = this.getProjectIdCore(provider, token, group, repo, baseUrl, cancellation);\n\t\t\tthis._projectIds.set(key, projectId);\n\t\t}\n\n\t\treturn projectId;\n\t}\n\n\tprivate async getProjectIdCore(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tgroup: string,\n\t\trepo: string,\n\t\tbaseUrl: string | undefined,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<string | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: { project: { id: string } };\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getProjectId(\n\t$fullPath: ID!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tid\n\t}\n}`;\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\tbaseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${group}/${repo}`,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst gid = rsp?.data?.project?.id;\n\t\t\tif (gid == null) return undefined;\n\n\t\t\tconst match = /gid:\\/\\/gitlab\\/Project\\/([0-9]+)\\b/.exec(gid);\n\t\t\tif (match == null) return undefined;\n\n\t\t\tconst projectId = match[1];\n\n\t\t\tscope?.addExitInfo(`projectId=${projectId}`);\n\t\t\treturn projectId;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async graphql<T extends object>(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tbaseUrl: string | undefined,\n\t\tquery: string,\n\t\tvariables: Record<string, any>,\n\t\tcancellation: AbortSignal | undefined,\n\t\tscope: ScopedLogger | undefined,\n\t): Promise<T | undefined> {\n\t\tconst { accessToken } = token;\n\t\tlet rsp: Response;\n\t\ttry {\n\t\t\tconst sw = maybeStopWatch(`[GITLAB] POST ${baseUrl}`, { log: { onlyExit: true } });\n\n\t\t\ttry {\n\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\trsp = await this.config.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () =>\n\t\t\t\t\tthis.config.fetch(`${baseUrl ?? 'https://gitlab.com/api'}/graphql`, {\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n\t\t\t\t\t\tsignal: cancellation,\n\t\t\t\t\t\tbody: JSON.stringify({ query: query, variables: variables }),\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tif (rsp.ok) {\n\t\t\t\t\tconst data = (await rsp.json()) as T | { errors: { message: string }[] };\n\n\t\t\t\t\tif ('errors' in data) throw new ProviderFetchError('GitLab', rsp, data.errors);\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Reads the body so the 403 branch below can tell a throttled request from a permission failure.\n\t\t\t\tthrow await ProviderFetchError.fromResponse('GitLab', rsp);\n\t\t\t} finally {\n\t\t\t\tconst match = /(^[^({\\n]+)/.exec(query);\n\t\t\t\tconst message = ` ${match?.[1].trim() ?? query}`;\n\n\t\t\t\tsw?.stop({ message: message });\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof ProviderFetchError || ex.name === 'AbortError') {\n\t\t\t\tthis.handleRequestError(provider, token, ex, scope);\n\t\t\t} else if (Logger.isDebugging) {\n\t\t\t\tthis.config.onError?.(`GitLab request failed: ${ex.message}`);\n\t\t\t}\n\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate async request<T>(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tbaseUrl: string | undefined,\n\t\troute: string,\n\t\toptions: { method: RequestInit['method'] } & Record<string, unknown>,\n\t\tcancellation: AbortSignal | undefined,\n\t\tscope: ScopedLogger | undefined,\n\t): Promise<T> {\n\t\tconst { accessToken } = token;\n\t\tconst url = `${baseUrl ?? 'https://gitlab.com/api'}/${route}`;\n\n\t\tlet rsp: Response;\n\t\ttry {\n\t\t\tconst sw = maybeStopWatch(`[GITLAB] ${options?.method ?? 'GET'} ${url}`, { log: { onlyExit: true } });\n\n\t\t\ttry {\n\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\trsp = await this.config.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () =>\n\t\t\t\t\tthis.config.fetch(url, {\n\t\t\t\t\t\theaders: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n\t\t\t\t\t\tsignal: cancellation,\n\t\t\t\t\t\t...options,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tif (rsp.ok) {\n\t\t\t\t\treturn (await rsp.json()) as T;\n\t\t\t\t}\n\n\t\t\t\t// Reads the body so the 403 branch below can tell a throttled request from a permission failure.\n\t\t\t\tthrow await ProviderFetchError.fromResponse('GitLab', rsp);\n\t\t\t} finally {\n\t\t\t\tsw?.stop();\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof ProviderFetchError || ex.name === 'AbortError') {\n\t\t\t\tthis.handleRequestError(provider, token, ex, scope);\n\t\t\t} else if (Logger.isDebugging) {\n\t\t\t\tthis.config.onError?.(`GitLab request failed: ${ex.message}`);\n\t\t\t}\n\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate handleRequestError(\n\t\tprovider: Provider | undefined,\n\t\ttoken: TokenWithInfo,\n\t\tex: ProviderFetchError | (Error & { name: 'AbortError' }),\n\t\tscope: ScopedLogger | undefined,\n\t): void {\n\t\tif (ex.name === 'AbortError' || !(ex instanceof ProviderFetchError)) throw new CancellationError(ex);\n\n\t\tconst { accessToken, ...tokenInfo } = token;\n\t\tswitch (ex.status) {\n\t\t\tcase 404: // Not found\n\t\t\tcase 410: // Gone\n\t\t\tcase 422: // Unprocessable Entity\n\t\t\t\tthrow new RequestNotFoundError(ex);\n\t\t\tcase 429: // Too Many Requests\n\t\t\t\tthrow toRateLimitError(ex, accessToken);\n\t\t\tcase 401: // Unauthorized\n\t\t\t\tthrow new AuthenticationError(tokenInfo, AuthenticationErrorReason.Unauthorized, ex);\n\t\t\tcase 403: // Forbidden\n\t\t\t\t// GitLab returns 403 for both a permission failure and a throttled request, so the message is the\n\t\t\t\t// discriminant (see `isRateLimitResponse`, shared with Bitbucket/Azure).\n\t\t\t\tif (isRateLimitResponse(ex)) throw toRateLimitError(ex, accessToken);\n\n\t\t\t\tthrow new AuthenticationError(tokenInfo, AuthenticationErrorReason.Forbidden, ex);\n\t\t\tcase 500: // Internal Server Error\n\t\t\t\tscope?.error(ex);\n\t\t\t\tif (ex.response != null) {\n\t\t\t\t\tprovider?.trackRequestException();\n\t\t\t\t\tthis.config.onRequestFailed?.(\n\t\t\t\t\t\tprovider == null || provider.id === 'gitlab'\n\t\t\t\t\t\t\t? l10n.t(\n\t\t\t\t\t\t\t\t\t'{0} failed to respond and might be experiencing issues. Please visit the [GitLab status page](https://status.gitlab.com) for more information.',\n\t\t\t\t\t\t\t\t\tprovider?.name ?? 'GitLab',\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: l10n.t('{0} failed to respond and might be experiencing issues.', provider.name),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase 502: // Bad Gateway\n\t\t\t\tscope?.error(ex);\n\t\t\t\t// GitHub seems to return this status code for timeouts\n\t\t\t\tif (ex.message.includes('timeout')) {\n\t\t\t\t\tprovider?.trackRequestException();\n\t\t\t\t\tthis.config.onRequestTimedOut?.(provider?.name ?? 'GitLab');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif (ex.status >= 400 && ex.status < 500) throw new RequestClientError(ex);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tscope?.error(ex);\n\t\tif (Logger.isDebugging) {\n\t\t\tthis.config.onError?.(`GitLab request failed: ${(ex.response as any)?.errors?.[0]?.message ?? ex.message}`);\n\t\t}\n\t}\n\n\tprivate handleException(ex: Error, provider: Provider, scope: ScopedLogger | undefined): Error {\n\t\tscope?.error(ex);\n\t\t// debugger;\n\n\t\tif (ex instanceof AuthenticationError) {\n\t\t\tvoid this.showAuthenticationErrorMessage(ex, provider);\n\t\t}\n\t\treturn ex;\n\t}\n\n\tprivate async showAuthenticationErrorMessage(ex: AuthenticationError, provider: Provider) {\n\t\tif (ex.reason === AuthenticationErrorReason.Unauthorized || ex.reason === AuthenticationErrorReason.Forbidden) {\n\t\t\tconst reauthenticate = await this.config.onReauthenticationRequired?.(\n\t\t\t\tex.reason === AuthenticationErrorReason.Forbidden\n\t\t\t\t\t? l10n.t('{0}. Would you like to try reauthenticating to provide additional access?', ex.message)\n\t\t\t\t\t: l10n.t('{0}. Would you like to try reauthenticating?', ex.message),\n\t\t\t);\n\n\t\t\tif (reauthenticate) {\n\t\t\t\tawait provider.reauthenticate();\n\t\t\t\tthis.resetCaches();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.config.onError?.(ex.message);\n\t\t}\n\t}\n}\n\n/** Wires a {@link GitLabApi} from the full runtime context, mapping `ctx` down to the narrow config. */\nexport function createGitLabApi(ctx: IntegrationServiceContext): GitLabApi {\n\tconst config: ProviderApiConfig = {\n\t\t...baseProviderApiConfig(ctx),\n\t\t// Self-hosted GitLab keys its API base off `remotes`, so reset on both HTTP proxy and remotes changes.\n\t\tonConfigChanged: listener =>\n\t\t\tctx.config.onDidChange(e => {\n\t\t\t\tif (e.httpProxy || e.remotes) {\n\t\t\t\t\tlistener();\n\t\t\t\t}\n\t\t\t}),\n\t\tonReauthenticationRequired: message =>\n\t\t\tctx.hooks?.onReauthenticationRequired?.(message) ?? Promise.resolve(false),\n\t\tonRequestTimedOut: providerName => ctx.hooks?.ui?.onRequestTimedOut?.(providerName),\n\t};\n\n\treturn new GitLabApi(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gitlab.js","names":["Logger"],"sources":["../../../../../../plus/integrations/src/providers/gitlab/gitlab.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport { reportRequestFailure } from '@gitlens/git/errors.js';\nimport type { Account } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { IssueOrPullRequest } from '@gitlens/git/models/issueOrPullRequest.js';\nimport { PullRequest } from '@gitlens/git/models/pullRequest.js';\nimport type { PullRequestState } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { trace } from '@gitlens/utils/decorators/log.js';\nimport type { Disposable } from '@gitlens/utils/disposable.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport type { ScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { maybeStopWatch } from '@gitlens/utils/stopwatch.js';\nimport { equalsIgnoreCase } from '@gitlens/utils/string.js';\nimport { joinUriPath, parseUri } from '@gitlens/utils/uri.js';\nimport type { TokenWithInfo } from '../../authentication/models.js';\nimport type { IntegrationServiceContext } from '../../context.js';\nimport {\n\tAuthenticationError,\n\tAuthenticationErrorReason,\n\tisRateLimitResponse,\n\tProviderFetchError,\n\tRequestClientError,\n\tRequestNotFoundError,\n\ttoRateLimitError,\n} from '../../errors.js';\nimport type { ProviderApiConfig } from '../apiConfig.js';\nimport { baseProviderApiConfig } from '../apiConfig.js';\nimport { selectBranchPullRequests } from '../utils/providerPaging.js';\nimport { selectGitLabUserForCommit } from './gitlab.utils.js';\nimport type {\n\tGitLabCommit,\n\tGitLabIssue,\n\tGitLabMergeRequest,\n\tGitLabMergeRequestFull,\n\tGitLabMergeRequestREST,\n\tGitLabMergeRequestState,\n\tGitLabProjectREST,\n\tGitLabSshKey,\n\tGitLabUser,\n} from './models.js';\nimport {\n\tfromGitLabMergeRequest,\n\tfromGitLabMergeRequestREST,\n\tfromGitLabMergeRequestState,\n\tgetRepoNamespace,\n\ttoGitLabMergeRequestState,\n} from './models.js';\n\n// drop it as soon as we switch to @gitkraken/providers-api\nconst gitlabUserIdPrefix = 'gid://gitlab/User/';\nconst gitlabMergeRequestIdPrefix = 'gid://gitlab/MergeRequest/';\n\nfunction buildGitLabUserId(id: string | number | undefined): string | undefined {\n\treturn typeof id === 'string' && id?.startsWith(gitlabUserIdPrefix)\n\t\t? id.substring(gitlabUserIdPrefix.length)\n\t\t: String(id);\n}\n\nexport class GitLabApi implements Disposable {\n\tprivate readonly _disposable: Disposable | undefined;\n\tprivate _projectIds = new Map<string, Promise<string | undefined>>();\n\n\tconstructor(private readonly config: ProviderApiConfig) {\n\t\tthis._disposable = config.onConfigChanged?.(() => this.resetCaches());\n\t}\n\n\tdispose(): void {\n\t\tthis._disposable?.dispose();\n\t}\n\n\tprivate resetCaches(): void {\n\t\tthis._projectIds.clear();\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, rev) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\trev: rev,\n\t\t}),\n\t})\n\tasync getAccountForCommit(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<Account | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst commit = await this.request<GitLabCommit>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}/repository/commits/${rev}?stats=false`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tlet users = await this.findUser(provider, token, commit.author_name, options, cancellation);\n\t\t\tlet user = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);\n\n\t\t\t// If the name search was ambiguous (multiple users share the name), try an email-scoped search to\n\t\t\t// disambiguate before giving up — otherwise we'd show a stranger's avatar (see #2205)\n\t\t\tif (user == null && commit.author_email) {\n\t\t\t\tconst exactNameMatches = users.filter(u => equalsIgnoreCase(u.name, commit.author_name)).length;\n\t\t\t\tif (exactNameMatches > 1) {\n\t\t\t\t\tusers = await this.findUser(provider, token, commit.author_email, options, cancellation);\n\t\t\t\t\tuser = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (user == null) return undefined;\n\n\t\t\t// If the avatarUrl is a relative URL, make it absolute using the webUrl (assuming the webUrl is the root URL with the username tacked on)\n\t\t\tif (user.avatarUrl && !/^([a-zA-Z][\\w+.-]+):/.test(user.avatarUrl)) {\n\t\t\t\tuser.avatarUrl = joinUriPath(parseUri(user.webUrl), '..', user.avatarUrl).toString();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tid: String(user.id),\n\t\t\t\tname: user.name || undefined,\n\t\t\t\temail: commit.author_email || undefined,\n\t\t\t\tavatarUrl: user.avatarUrl || undefined,\n\t\t\t\tusername: user.username || undefined,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, _owner, _repo, email) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\temail: email,\n\t\t}),\n\t})\n\tasync getAccountForEmail(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\t_owner: string,\n\t\t_repo: string,\n\t\temail: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\ttry {\n\t\t\tconst [user] = await this.findUser(provider, token, email, options);\n\t\t\tif (user == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tid: String(user.id),\n\t\t\t\tname: user.name || undefined,\n\t\t\t\temail: user.publicEmail || undefined,\n\t\t\t\tavatarUrl: user.avatarUrl || undefined,\n\t\t\t\tusername: user.username || undefined,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, userId) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\tuserId: userId,\n\t\t}),\n\t})\n\tasync getUserSigningKeys(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tuserId: string | number,\n\t\toptions?: { baseUrl?: string },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitLabSshKey[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\t// SSH keys are public, so this works for any user with the current token (covered by the `read_user` scope).\n\t\ttry {\n\t\t\tconst keys = await this.request<GitLabSshKey[]>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/users/${userId}/keys`,\n\t\t\t\t{ method: 'GET' },\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\t// Exclude auth-only keys — only signing-capable keys belong in an allowed_signers file.\n\t\t\treturn keys?.filter(k => k.usage_type === 'signing' || k.usage_type === 'auth_and_signing') ?? [];\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t}),\n\t})\n\tasync getDefaultBranch(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<DefaultBranch | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject:\n\t\t\t\t\t| {\n\t\t\t\t\t\t\trepository: { rootRef: string } | null | undefined;\n\t\t\t\t\t }\n\t\t\t\t\t| null\n\t\t\t\t\t| undefined;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getDefaultBranch(\n\t$fullPath: ID!\n) {\n\tproject(fullPath: $fullPath) {\n\t\trepository {\n\t\t\trootRef\n\t\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst defaultBranch = rsp?.data?.project?.repository?.rootRef ?? undefined;\n\t\t\tif (defaultBranch == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\tname: defaultBranch,\n\t\t\t};\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, number) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tnumber: number,\n\t\t}),\n\t})\n\tasync getIssueOrPullRequest(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tnumber: number,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequest: GitLabMergeRequest | null;\n\t\t\t\t\tissue: GitLabIssue | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getIssueOrMergeRequest(\n\t$fullPath: ID!\n\t$iid: String!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequest(iid: $iid) {\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tiid\n\t\t\ttitle\n\t\t\tdescription\n\t\t\tstate\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tmergedAt\n\t\t\twebUrl\n\t\t}\n\t\tissue(iid: $iid) {\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tiid\n\t\t\ttitle\n\t\t\tdescription\n\t\t\tstate\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tclosedAt\n\t\t\twebUrl\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tiid: String(number),\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tif (rsp?.data?.project?.issue != null) {\n\t\t\t\tconst issue = rsp.data.project.issue;\n\t\t\t\treturn {\n\t\t\t\t\tprovider: provider,\n\t\t\t\t\ttype: 'issue',\n\t\t\t\t\tid: issue.iid,\n\t\t\t\t\tnodeId: undefined,\n\t\t\t\t\tcreatedDate: new Date(issue.createdAt),\n\t\t\t\t\tupdatedDate: new Date(issue.updatedAt),\n\t\t\t\t\ttitle: issue.title,\n\t\t\t\t\tclosed: issue.state === 'closed',\n\t\t\t\t\tclosedDate: issue.closedAt == null ? undefined : new Date(issue.closedAt),\n\t\t\t\t\turl: issue.webUrl,\n\t\t\t\t\tstate: issue.state === 'locked' ? 'closed' : issue.state,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rsp?.data?.project?.mergeRequest != null) {\n\t\t\t\tconst mergeRequest = rsp.data.project.mergeRequest;\n\t\t\t\treturn {\n\t\t\t\t\tprovider: provider,\n\t\t\t\t\ttype: 'pullrequest',\n\t\t\t\t\tid: mergeRequest.iid,\n\t\t\t\t\tnodeId: undefined,\n\t\t\t\t\tcreatedDate: new Date(mergeRequest.createdAt),\n\t\t\t\t\tupdatedDate: new Date(mergeRequest.updatedAt),\n\t\t\t\t\ttitle: mergeRequest.title,\n\t\t\t\t\tclosed: mergeRequest.state === 'closed',\n\t\t\t\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\t\t\t\tclosedDate: mergeRequest.state === 'closed' ? new Date(mergeRequest.updatedAt) : undefined,\n\t\t\t\t\turl: mergeRequest.webUrl,\n\t\t\t\t\tstate: mergeRequest.state === 'locked' ? 'closed' : mergeRequest.state,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t/**\n\t * Whether `owner/repo` has issue `iid`. Strict like {@link getPullRequest}'s `strict`: `false` only for a `null`\n\t * project or issue, which is how GitLab's GraphQL answers a missing one; GraphQL `errors`, an empty response and\n\t * any HTTP error (a 404 means a wrong endpoint) all throw instead of reading as absent.\n\t */\n\t@trace({\n\t\targs: (provider, token, owner, repo, iid) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tiid: iid,\n\t\t}),\n\t})\n\tasync hasIssue(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tiid: number,\n\t\toptions: { baseUrl?: string; deferFailure?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<boolean> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: { project: { issue: { iid: string } | null } | null } | null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query hasIssue(\n\t$fullPath: ID!\n\t$iid: String!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tissue(iid: $iid) {\n\t\t\tiid\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{ fullPath: `${owner}/${repo}`, iid: String(iid) },\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t\toptions.deferFailure,\n\t\t\t);\n\t\t\tif (rsp?.data == null) throw new Error('GitLab returned no data for the issue');\n\n\t\t\treturn rsp.data.project?.issue != null;\n\t\t} catch (ex) {\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, branch) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tbranch: branch,\n\t\t}),\n\t})\n\tasync getPullRequestForBranch(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tbranch: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: GitLabMergeRequestState[];\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequests?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\topened?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\tclosed?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t\tmerged?: {\n\t\t\t\t\t\tnodes: GitLabMergeRequest[];\n\t\t\t\t\t} | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst fragment = `\n\t\t\tnodes {\n\t\t\t\tiid\n\t\t\t\tauthor {\n\t\t\t\t\tid\n\t\t\t\t\tname\n\t\t\t\t\tavatarUrl\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t\ttitle\n\t\t\t\tdescription\n\t\t\t\tstate\n\t\t\t\tcreatedAt\n\t\t\t\tupdatedAt\n\t\t\t\tmergedAt\n\t\t\t\twebUrl\n\t\t\t}`;\n\n\t\t\tconst query = `query getMergeRequestForBranch(\n\t$fullPath: ID!\n\t$branches: [String!]\n) {\n\tproject(fullPath: $fullPath) {\n\t\t${\n\t\t\toptions?.include == null\n\t\t\t\t? `mergeRequests(sourceBranches: $branches sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('opened')\n\t\t\t\t? `opened: mergeRequests(sourceBranches: $branches state: opened sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('merged')\n\t\t\t\t? `merged: mergeRequests(sourceBranches: $branches state: merged sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t\t${\n\t\t\toptions?.include?.includes('closed')\n\t\t\t\t? `closed: mergeRequests(sourceBranches: $branches state: closed sort: UPDATED_DESC first: 1) {\n\t\t\t${fragment}\n\t\t}`\n\t\t\t\t: ''\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tbranches: [branch],\n\t\t\t\t\tstate: options?.include,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tlet pr: GitLabMergeRequest | undefined;\n\n\t\t\tif (options?.include == null) {\n\t\t\t\tpr = rsp?.data?.project?.mergeRequests?.nodes?.[0];\n\t\t\t} else {\n\t\t\t\tfor (const state of options.include) {\n\t\t\t\t\tlet mr;\n\t\t\t\t\tif (state === 'opened') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.opened?.nodes?.[0];\n\t\t\t\t\t} else if (state === 'merged') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.merged?.nodes?.[0];\n\t\t\t\t\t} else if (state === 'closed') {\n\t\t\t\t\t\tmr = rsp?.data?.project?.closed?.nodes?.[0];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mr != null && (pr == null || new Date(mr.updatedAt) > new Date(pr.updatedAt))) {\n\t\t\t\t\t\tpr = mr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pr == null) return undefined;\n\n\t\t\treturn new PullRequest(\n\t\t\t\tprovider,\n\t\t\t\t{\n\t\t\t\t\tid: buildGitLabUserId(pr.author?.id) ?? '',\n\t\t\t\t\t// An absent author stays absent: no `'Unknown'` name a consumer can't tell from a real one, and no\n\t\t\t\t\t// `''` url/avatar that passes a presence check and renders as a link to nowhere. Matches\n\t\t\t\t\t// `fromProviderAccount`/`toIssueShape`.\n\t\t\t\t\tname: pr.author?.name ?? undefined,\n\t\t\t\t\tavatarUrl: pr.author?.avatarUrl ?? undefined,\n\t\t\t\t\turl: pr.author?.webUrl ?? undefined,\n\t\t\t\t},\n\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\tString(pr.iid),\n\t\t\t\tundefined,\n\t\t\t\tpr.title,\n\t\t\t\tpr.webUrl,\n\t\t\t\t{ owner: owner, repo: repo },\n\t\t\t\tfromGitLabMergeRequestState(pr.state),\n\t\t\t\tnew Date(pr.createdAt),\n\t\t\t\tnew Date(pr.updatedAt),\n\t\t\t\t// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL\n\t\t\t\tpr.state !== 'closed' ? undefined : new Date(pr.updatedAt),\n\t\t\t\tpr.mergedAt == null ? undefined : new Date(pr.mergedAt),\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, rev) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\trev: rev,\n\t\t}),\n\t})\n\tasync getPullRequestForCommit(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst mrs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}/repository/commits/${rev}/merge_requests`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (mrs == null || mrs.length === 0) return undefined;\n\n\t\t\tif (mrs.length > 1) {\n\t\t\t\tmrs.sort(\n\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t(a.state === 'opened' ? -1 : 1) - (b.state === 'opened' ? -1 : 1) ||\n\t\t\t\t\t\tnew Date(b.updated_at).getTime() - new Date(a.updated_at).getTime(),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn fromGitLabMergeRequestREST(mrs[0], provider, { owner: owner, repo: repo });\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo, id) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tid: id,\n\t\t}),\n\t})\n\tasync getPullRequest(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tid: number,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\t/**\n\t\t\t * Returns `undefined` only for a `null` project or merge request, which is how GitLab's GraphQL\n\t\t\t * answers a missing one. A thrown not-found or an empty response means the endpoint is wrong, so\n\t\t\t * both throw instead of reading as absent.\n\t\t\t */\n\t\t\tstrict?: boolean;\n\t\t\tdeferFailure?: boolean;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequest: GitLabMergeRequestFull | null;\n\t\t\t\t} | null;\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getMergeRequest(\n\t$fullPath: ID!\n\t$iid: String!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequest(iid: $iid) {\n\t\t\tid,\n\t\t\tiid\n\t\t\tstate,\n\t\t\tauthor {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t\tavatarUrl\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tdiffRefs {\n\t\t\t\tbaseSha\n\t\t\t\theadSha\n\t\t\t}\n\t\t\ttitle\n\t\t\tdescription\n\t\t\twebUrl\n\t\t\tcreatedAt\n\t\t\tupdatedAt\n\t\t\tmergedAt\n\t\t\ttargetBranch\n\t\t\tsourceBranch\n\t\t\tproject {\n\t\t\t\tid\n\t\t\t\tfullPath\n\t\t\t\twebUrl\n\t\t\t}\n\t\t\tsourceProject {\n\t\t\t\tid\n\t\t\t\tfullPath\n\t\t\t\twebUrl\n\t\t\t}\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${owner}/${repo}`,\n\t\t\t\t\tiid: String(id),\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t\toptions?.deferFailure,\n\t\t\t);\n\n\t\t\tif (rsp?.data == null) {\n\t\t\t\tif (options?.strict) throw new Error('GitLab returned no data for the merge request');\n\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (rsp.data.project?.mergeRequest == null) return undefined;\n\n\t\t\tconst pr = rsp.data.project.mergeRequest;\n\t\t\treturn fromGitLabMergeRequest(pr, provider);\n\t\t} catch (ex) {\n\t\t\tif (!options?.strict && ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t/**\n\t * The iids of the merge requests into `owner/repo` whose source is `branch`, in any state, newest first, at most\n\t * `limit`: from the project itself when `headOwner` is omitted, otherwise from a fork in the `headOwner`\n\t * namespace. Only the iids, so a caller resolves the rows through the same read as its by-number lookups.\n\t *\n\t * Keyed on the source branch NAME, so a merged request whose branch was deleted still matches. Strict like\n\t * {@link getPullRequest}'s `strict`: an empty list means GitLab answered, a `null` project included; a 404 or\n\t * an empty response means the endpoint is wrong and throws. Requests from a deleted fork carry no source\n\t * project and so match nothing.\n\t */\n\t@trace({\n\t\targs: (provider, token, owner, repo, branch) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t\tbranch: branch,\n\t\t}),\n\t})\n\tasync getPullRequestNumbersForBranch(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\tbranch: string,\n\t\toptions: { baseUrl?: string; headOwner?: string; limit: number; deferFailure?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<{ numbers: number[]; truncated: boolean }> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface MergeRequestHead {\n\t\t\tiid: string;\n\t\t\tupdatedAt: string;\n\t\t\tsourceBranch: string;\n\t\t\tproject: { id: string };\n\t\t\tsourceProject: { id: string; fullPath: string } | null;\n\t\t}\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: {\n\t\t\t\t\tmergeRequests: {\n\t\t\t\t\t\tcount: number;\n\t\t\t\t\t\tpageInfo: { hasNextPage: boolean };\n\t\t\t\t\t\tnodes: MergeRequestHead[];\n\t\t\t\t\t} | null;\n\t\t\t\t} | null;\n\t\t\t} | null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getMergeRequestsForBranch(\n\t$fullPath: ID!\n\t$branches: [String!]\n\t$limit: Int!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequests(sourceBranches: $branches, state: all, sort: UPDATED_DESC, first: $limit) {\n\t\t\tcount\n\t\t\tpageInfo {\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tiid\n\t\t\t\tupdatedAt\n\t\t\t\tsourceBranch\n\t\t\t\tproject {\n\t\t\t\t\tid\n\t\t\t\t}\n\t\t\t\tsourceProject {\n\t\t\t\t\tid\n\t\t\t\t\tfullPath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}`;\n\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{ fullPath: `${owner}/${repo}`, branches: [branch], limit: options.limit },\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t\toptions.deferFailure,\n\t\t\t);\n\t\t\tif (rsp?.data == null) throw new Error('GitLab returned no data for the merge requests by branch');\n\n\t\t\tconst project = rsp.data.project;\n\t\t\tif (project == null) return { numbers: [], truncated: false };\n\n\t\t\tconst connection = project.mergeRequests;\n\t\t\tif (connection == null) {\n\t\t\t\tthrow new Error(`GitLab returned no merge requests for ${owner}/${repo}:${branch}`);\n\t\t\t}\n\n\t\t\tconst headOwner = options.headOwner;\n\t\t\tconst { values, truncated } = selectBranchPullRequests(connection.nodes, {\n\t\t\t\tmatchesHead: mr => {\n\t\t\t\t\tif (mr.sourceBranch !== branch || mr.sourceProject == null) return false;\n\t\t\t\t\tif (headOwner == null) return mr.sourceProject.id === mr.project.id;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\tmr.sourceProject.id !== mr.project.id &&\n\t\t\t\t\t\tequalsIgnoreCase(getRepoNamespace(mr.sourceProject.fullPath), headOwner)\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tupdatedAt: mr => Date.parse(mr.updatedAt),\n\t\t\t\tmap: mr => {\n\t\t\t\t\tconst iid = Number(mr.iid);\n\t\t\t\t\tif (!Number.isSafeInteger(iid)) throw new Error(`GitLab returned a merge request iid '${mr.iid}'`);\n\n\t\t\t\t\treturn iid;\n\t\t\t\t},\n\t\t\t\tlimit: options.limit,\n\t\t\t\tmore: connection.pageInfo.hasNextPage || connection.count > connection.nodes.length,\n\t\t\t});\n\t\t\treturn { numbers: values, truncated: truncated };\n\t\t} catch (ex) {\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({\n\t\targs: (provider, token, owner, repo) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\towner: owner,\n\t\t\trepo: repo,\n\t\t}),\n\t})\n\tasync getRepositoryMetadata(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\towner: string,\n\t\trepo: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);\n\t\tif (!projectId) return undefined;\n\n\t\ttry {\n\t\t\tconst proj = await this.request<GitLabProjectREST>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\t`v4/projects/${projectId}`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t// ...options,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (proj == null) return undefined;\n\n\t\t\treturn {\n\t\t\t\tprovider: provider,\n\t\t\t\towner: proj.namespace.full_path,\n\t\t\t\tname: proj.path,\n\t\t\t\tisFork: proj.forked_from_project != null,\n\t\t\t\tparent:\n\t\t\t\t\tproj.forked_from_project != null\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\towner: proj.forked_from_project.namespace.full_path,\n\t\t\t\t\t\t\t\tname: proj.forked_from_project.path,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t} satisfies RepositoryMetadata;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t@trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })\n\tasync searchPullRequests(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\toptions?: {\n\t\t\tsearch?: string;\n\t\t\tuser?: string;\n\t\t\trepos?: string[];\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PullRequest[]> {\n\t\tconst scope = getScopedLogger();\n\t\tconst search = options?.search;\n\t\tif (!search) {\n\t\t\treturn [];\n\t\t}\n\n\t\ttry {\n\t\t\tconst perPageLimit = 20; // with bigger amount we exceed the max GraphQL complexity in the next query\n\t\t\tconst include = options?.include?.length ? options.include : undefined;\n\t\t\t// GitLab's search API takes a single `state` value, so push it server-side when exactly one state is\n\t\t\t// requested; that keeps the requested state from being crowded out of the `perPageLimit` slice. For\n\t\t\t// multiple states there's no single-value qualifier, so those are filtered client-side below.\n\t\t\tlet searchPath = `v4/search/?scope=merge_requests&search=${encodeURIComponent(search)}&per_page=${perPageLimit}`;\n\t\t\tif (include?.length === 1) {\n\t\t\t\tsearchPath += `&state=${encodeURIComponent(toGitLabMergeRequestState(include[0]))}`;\n\t\t\t}\n\n\t\t\tlet restPRs: GitLabMergeRequestREST[];\n\t\t\tif (include == null) {\n\t\t\t\t// Unfiltered search returns the first page as-is (as it did before state filtering existed).\n\t\t\t\trestPRs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\t\tprovider,\n\t\t\t\t\ttoken,\n\t\t\t\t\toptions?.baseUrl,\n\t\t\t\t\tsearchPath,\n\t\t\t\t\t{ method: 'GET' },\n\t\t\t\t\tcancellation,\n\t\t\t\t\tscope,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// The search API returns MRs of all states in relevance order, so the requested state(s) may not\n\t\t\t\t// appear on the first page. Server-side `&state=` narrows the single-state case when honored, but it\n\t\t\t\t// can't express multiple states, so page through the results and accumulate matches until we fill the\n\t\t\t\t// detail-query cap (`perPageLimit`) or exhaust the search results. This keeps correctness whether\n\t\t\t\t// or not `&state=` takes effect. Bounded by `maxSearchPages` like the other paged provider drains in\n\t\t\t\t// this package so a large, low-match result set can't fan out into an unbounded request loop.\n\t\t\t\tconst maxSearchPages = 20;\n\t\t\t\tconst matches: GitLabMergeRequestREST[] = [];\n\t\t\t\tfor (let page = 1; page <= maxSearchPages; page++) {\n\t\t\t\t\tconst pagePRs = await this.request<GitLabMergeRequestREST[]>(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t\toptions?.baseUrl,\n\t\t\t\t\t\t`${searchPath}&page=${page}`,\n\t\t\t\t\t\t{ method: 'GET' },\n\t\t\t\t\t\tcancellation,\n\t\t\t\t\t\tscope,\n\t\t\t\t\t);\n\t\t\t\t\tfor (const pr of pagePRs) {\n\t\t\t\t\t\tif (include.includes(fromGitLabMergeRequestState(pr.state))) {\n\t\t\t\t\t\t\tmatches.push(pr);\n\t\t\t\t\t\t\tif (matches.length >= perPageLimit) break;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Stop once we've filled the cap or hit the last (partial or empty) page.\n\t\t\t\t\tif (matches.length >= perPageLimit || pagePRs.length < perPageLimit) break;\n\t\t\t\t}\n\t\t\t\trestPRs = matches;\n\t\t\t}\n\t\t\tif (restPRs.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tinterface QueryResult {\n\t\t\t\tdata: Record<`mergeRequest_${number}`, GitLabMergeRequestFull>;\n\t\t\t}\n\n\t\t\tconst queryArgs = restPRs.map((_, i) => `$id_${i}: MergeRequestID!`).join('\\n');\n\t\t\tconst queryFields = restPRs\n\t\t\t\t.map((_, i) => `mergeRequest_${i}: mergeRequest(id: $id_${i}) { ...mergeRequestFields }`)\n\t\t\t\t.join('\\n');\n\t\t\t// Set of fields includes only additional fields that are not included in GitLabMergeRequestREST.\n\t\t\t// It's limited as much as possible to reduce complexity of the query.\n\t\t\tconst queryMrFields = `fragment mergeRequestFields on MergeRequest {\n\t\t\t\tdiffRefs {\n\t\t\t\t\tbaseSha\n\t\t\t\t\theadSha\n\t\t\t\t}\n\t\t\t\tproject {\n\t\t\t\t\tid\n\t\t\t\t\tfullPath\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t\tsourceProject {\n\t\t\t\t\tid\n\t\t\t\t\tfullPath\n\t\t\t\t\twebUrl\n\t\t\t\t}\n\t\t\t}`;\n\t\t\tconst query = `query getMergeRequests (${queryArgs}) {${queryFields}} ${queryMrFields}`;\n\n\t\t\tconst params = restPRs.reduce<Record<`id_${number}`, string>>((ids, gitlabRestPr, i) => {\n\t\t\t\tids[`id_${i}`] = `${gitlabMergeRequestIdPrefix}${gitlabRestPr.id}`;\n\t\t\t\treturn ids;\n\t\t\t}, {});\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\tparams,\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\t\t\tif (rsp?.data != null) {\n\t\t\t\tconst resultPRs = restPRs.reduce<PullRequest[]>((accum, restPR, i) => {\n\t\t\t\t\tconst graphQlPR = rsp.data[`mergeRequest_${i}`];\n\t\t\t\t\tif (graphQlPR == null) {\n\t\t\t\t\t\treturn accum;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fullPr: GitLabMergeRequestFull = {\n\t\t\t\t\t\t...graphQlPR,\n\t\t\t\t\t\tiid: String(restPR.iid),\n\t\t\t\t\t\tid: String(restPR.id),\n\t\t\t\t\t\tstate: restPR.state,\n\t\t\t\t\t\t// An absent REST author stays absent (`null`, as GitLab's own shape expresses it) rather than a\n\t\t\t\t\t\t// synthesized `'Unknown'` stub: `fromGitLabMergeRequest` collapses `null` to an absent\n\t\t\t\t\t\t// `PullRequestMember.name`, whereas a placeholder here would launder into a real-looking name.\n\t\t\t\t\t\tauthor:\n\t\t\t\t\t\t\trestPR.author != null\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tid: buildGitLabUserId(restPR.author.id) ?? '',\n\t\t\t\t\t\t\t\t\t\tname: restPR.author.name,\n\t\t\t\t\t\t\t\t\t\tavatarUrl: restPR.author.avatar_url ?? null,\n\t\t\t\t\t\t\t\t\t\twebUrl: restPR.author.web_url,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\ttitle: restPR.title,\n\t\t\t\t\t\tdescription: restPR.description,\n\t\t\t\t\t\twebUrl: restPR.web_url,\n\t\t\t\t\t\tcreatedAt: restPR.created_at,\n\t\t\t\t\t\tupdatedAt: restPR.updated_at,\n\t\t\t\t\t\tmergedAt: restPR.merged_at,\n\t\t\t\t\t\tsourceBranch: restPR.source_branch,\n\t\t\t\t\t\ttargetBranch: restPR.target_branch,\n\t\t\t\t\t};\n\t\t\t\t\taccum.push(fromGitLabMergeRequest(fullPr, provider));\n\t\t\t\t\treturn accum;\n\t\t\t\t}, []);\n\t\t\t\treturn resultPRs;\n\t\t\t}\n\t\t\treturn [];\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\tprivate async findUser(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tsearch: string,\n\t\toptions?: {\n\t\t\tbaseUrl?: string;\n\t\t\tavatarSize?: number;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitLabUser[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tusers: {\n\t\t\t\t\tnodes: {\n\t\t\t\t\t\tid: string;\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\tusername: string;\n\t\t\t\t\t\tpublicEmail?: string;\n\t\t\t\t\t\tstate: string;\n\t\t\t\t\t\tavatarUrl: string;\n\t\t\t\t\t\twebUrl: string;\n\t\t\t\t\t}[];\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query findUser(\n$search: String!\n) {\n\tusers(search: $search) {\n\t\tnodes {\n\t\t\tid\n\t\t\tname\n\t\t\tusername,\n\t\t\tpublicEmail,\n\t\t\tstate\n\t\t\tavatarUrl\n\t\t\twebUrl\n\t\t}\n\t}\n}`;\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\toptions?.baseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tsearch: search,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst matches = rsp?.data?.users?.nodes;\n\t\t\tif (matches == null || matches.length === 0) return [];\n\n\t\t\tconst users: GitLabUser[] = [];\n\n\t\t\tfor (const user of matches) {\n\t\t\t\tconst match = /gid:\\/\\/gitlab\\/User\\/([0-9]+)\\b/.exec(user.id);\n\t\t\t\tif (match == null) continue;\n\n\t\t\t\tusers.push({\n\t\t\t\t\tid: parseInt(match[1], 10),\n\t\t\t\t\tname: user.name,\n\t\t\t\t\tusername: user.username,\n\t\t\t\t\tpublicEmail: user.publicEmail || undefined,\n\t\t\t\t\tstate: user.state,\n\t\t\t\t\tavatarUrl: user.avatarUrl,\n\t\t\t\t\twebUrl: user.webUrl,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn users;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return [];\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tgetProjectId(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tgroup: string,\n\t\trepo: string,\n\t\tbaseUrl: string | undefined,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<string | undefined> {\n\t\tconst { accessToken } = token;\n\t\tconst key = `${accessToken}|${group}/${repo}`;\n\n\t\tlet projectId = this._projectIds.get(key);\n\t\tif (projectId == null) {\n\t\t\tprojectId = this.getProjectIdCore(provider, token, group, repo, baseUrl, cancellation);\n\t\t\tthis._projectIds.set(key, projectId);\n\t\t}\n\n\t\treturn projectId;\n\t}\n\n\tprivate async getProjectIdCore(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tgroup: string,\n\t\trepo: string,\n\t\tbaseUrl: string | undefined,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<string | undefined> {\n\t\tconst scope = getScopedLogger();\n\n\t\tinterface QueryResult {\n\t\t\tdata: { project: { id: string } };\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getProjectId(\n\t$fullPath: ID!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tid\n\t}\n}`;\n\t\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\t\tprovider,\n\t\t\t\ttoken,\n\t\t\t\tbaseUrl,\n\t\t\t\tquery,\n\t\t\t\t{\n\t\t\t\t\tfullPath: `${group}/${repo}`,\n\t\t\t\t},\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t);\n\n\t\t\tconst gid = rsp?.data?.project?.id;\n\t\t\tif (gid == null) return undefined;\n\n\t\t\tconst match = /gid:\\/\\/gitlab\\/Project\\/([0-9]+)\\b/.exec(gid);\n\t\t\tif (match == null) return undefined;\n\n\t\t\tconst projectId = match[1];\n\n\t\t\tscope?.addExitInfo(`projectId=${projectId}`);\n\t\t\treturn projectId;\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof RequestNotFoundError) return undefined;\n\n\t\t\tthis.handleException(ex, provider, scope);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async graphql<T extends object>(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tbaseUrl: string | undefined,\n\t\tquery: string,\n\t\tvariables: Record<string, any>,\n\t\tcancellation: AbortSignal | undefined,\n\t\tscope: ScopedLogger | undefined,\n\t\tdeferFailure?: boolean,\n\t): Promise<T | undefined> {\n\t\tconst { accessToken } = token;\n\t\tlet rsp: Response;\n\t\ttry {\n\t\t\tconst sw = maybeStopWatch(`[GITLAB] POST ${baseUrl}`, { log: { onlyExit: true } });\n\n\t\t\ttry {\n\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\trsp = await this.config.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () =>\n\t\t\t\t\tthis.config.fetch(`${baseUrl ?? 'https://gitlab.com/api'}/graphql`, {\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n\t\t\t\t\t\tsignal: cancellation,\n\t\t\t\t\t\tbody: JSON.stringify({ query: query, variables: variables }),\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tif (rsp.ok) {\n\t\t\t\t\tconst data = (await rsp.json()) as T | { errors: { message: string }[] };\n\n\t\t\t\t\tif ('errors' in data) throw new ProviderFetchError('GitLab', rsp, data.errors);\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Reads the body so the 403 branch below can tell a throttled request from a permission failure.\n\t\t\t\tthrow await ProviderFetchError.fromResponse('GitLab', rsp);\n\t\t\t} finally {\n\t\t\t\tconst match = /(^[^({\\n]+)/.exec(query);\n\t\t\t\tconst message = ` ${match?.[1].trim() ?? query}`;\n\n\t\t\t\tsw?.stop({ message: message });\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof ProviderFetchError || ex.name === 'AbortError') {\n\t\t\t\tthis.handleRequestError(provider, token, ex, scope, deferFailure);\n\t\t\t} else if (Logger.isDebugging) {\n\t\t\t\tthis.config.onError?.(`GitLab request failed: ${ex.message}`);\n\t\t\t}\n\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate async request<T>(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tbaseUrl: string | undefined,\n\t\troute: string,\n\t\toptions: { method: RequestInit['method'] } & Record<string, unknown>,\n\t\tcancellation: AbortSignal | undefined,\n\t\tscope: ScopedLogger | undefined,\n\t): Promise<T> {\n\t\tconst { accessToken } = token;\n\t\tconst url = `${baseUrl ?? 'https://gitlab.com/api'}/${route}`;\n\n\t\tlet rsp: Response;\n\t\ttry {\n\t\t\tconst sw = maybeStopWatch(`[GITLAB] ${options?.method ?? 'GET'} ${url}`, { log: { onlyExit: true } });\n\n\t\t\ttry {\n\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\trsp = await this.config.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () =>\n\t\t\t\t\tthis.config.fetch(url, {\n\t\t\t\t\t\theaders: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n\t\t\t\t\t\tsignal: cancellation,\n\t\t\t\t\t\t...options,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tif (rsp.ok) {\n\t\t\t\t\treturn (await rsp.json()) as T;\n\t\t\t\t}\n\n\t\t\t\t// Reads the body so the 403 branch below can tell a throttled request from a permission failure.\n\t\t\t\tthrow await ProviderFetchError.fromResponse('GitLab', rsp);\n\t\t\t} finally {\n\t\t\t\tsw?.stop();\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof ProviderFetchError || ex.name === 'AbortError') {\n\t\t\t\tthis.handleRequestError(provider, token, ex, scope, undefined);\n\t\t\t} else if (Logger.isDebugging) {\n\t\t\t\tthis.config.onError?.(`GitLab request failed: ${ex.message}`);\n\t\t\t}\n\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate handleRequestError(\n\t\tprovider: Provider | undefined,\n\t\ttoken: TokenWithInfo,\n\t\tex: ProviderFetchError | (Error & { name: 'AbortError' }),\n\t\tscope: ScopedLogger | undefined,\n\t\tdeferFailure: boolean | undefined,\n\t): void {\n\t\tif (ex.name === 'AbortError' || !(ex instanceof ProviderFetchError)) throw new CancellationError(ex);\n\n\t\tconst { accessToken, ...tokenInfo } = token;\n\t\tswitch (ex.status) {\n\t\t\tcase 404: // Not found\n\t\t\tcase 410: // Gone\n\t\t\tcase 422: // Unprocessable Entity\n\t\t\t\tthrow new RequestNotFoundError(ex);\n\t\t\tcase 429: // Too Many Requests\n\t\t\t\tthrow toRateLimitError(ex, accessToken);\n\t\t\tcase 401: // Unauthorized\n\t\t\t\tthrow new AuthenticationError(tokenInfo, AuthenticationErrorReason.Unauthorized, ex);\n\t\t\tcase 403: // Forbidden\n\t\t\t\t// GitLab returns 403 for both a permission failure and a throttled request, so the message is the\n\t\t\t\t// discriminant (see `isRateLimitResponse`, shared with Bitbucket/Azure).\n\t\t\t\tif (isRateLimitResponse(ex)) throw toRateLimitError(ex, accessToken);\n\n\t\t\t\tthrow new AuthenticationError(tokenInfo, AuthenticationErrorReason.Forbidden, ex);\n\t\t\tcase 500: // Internal Server Error\n\t\t\t\tscope?.error(ex);\n\t\t\t\tif (ex.response != null) {\n\t\t\t\t\treportRequestFailure(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\tex,\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\tthis.config.onRequestFailed?.(\n\t\t\t\t\t\t\t\tprovider == null || provider.id === 'gitlab'\n\t\t\t\t\t\t\t\t\t? l10n.t(\n\t\t\t\t\t\t\t\t\t\t\t'{0} failed to respond and might be experiencing issues. Please visit the [GitLab status page](https://status.gitlab.com) for more information.',\n\t\t\t\t\t\t\t\t\t\t\tprovider?.name ?? 'GitLab',\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: l10n.t('{0} failed to respond and might be experiencing issues.', provider.name),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tdeferFailure,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase 502: // Bad Gateway\n\t\t\t\tscope?.error(ex);\n\t\t\t\t// GitHub seems to return this status code for timeouts\n\t\t\t\tif (ex.message.includes('timeout')) {\n\t\t\t\t\treportRequestFailure(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\tex,\n\t\t\t\t\t\t() => this.config.onRequestTimedOut?.(provider?.name ?? 'GitLab'),\n\t\t\t\t\t\tdeferFailure,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif (ex.status >= 400 && ex.status < 500) throw new RequestClientError(ex);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tscope?.error(ex);\n\t\tif (Logger.isDebugging) {\n\t\t\tthis.config.onError?.(`GitLab request failed: ${(ex.response as any)?.errors?.[0]?.message ?? ex.message}`);\n\t\t}\n\t}\n\n\tprivate handleException(ex: Error, provider: Provider, scope: ScopedLogger | undefined): Error {\n\t\tscope?.error(ex);\n\t\t// debugger;\n\n\t\tif (ex instanceof AuthenticationError) {\n\t\t\tvoid this.showAuthenticationErrorMessage(ex, provider);\n\t\t}\n\t\treturn ex;\n\t}\n\n\tprivate async showAuthenticationErrorMessage(ex: AuthenticationError, provider: Provider) {\n\t\tif (ex.reason === AuthenticationErrorReason.Unauthorized || ex.reason === AuthenticationErrorReason.Forbidden) {\n\t\t\tconst reauthenticate = await this.config.onReauthenticationRequired?.(\n\t\t\t\tex.reason === AuthenticationErrorReason.Forbidden\n\t\t\t\t\t? l10n.t('{0}. Would you like to try reauthenticating to provide additional access?', ex.message)\n\t\t\t\t\t: l10n.t('{0}. Would you like to try reauthenticating?', ex.message),\n\t\t\t);\n\n\t\t\tif (reauthenticate) {\n\t\t\t\tawait provider.reauthenticate();\n\t\t\t\tthis.resetCaches();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.config.onError?.(ex.message);\n\t\t}\n\t}\n}\n\n/** Wires a {@link GitLabApi} from the full runtime context, mapping `ctx` down to the narrow config. */\nexport function createGitLabApi(ctx: IntegrationServiceContext): GitLabApi {\n\tconst config: ProviderApiConfig = {\n\t\t...baseProviderApiConfig(ctx),\n\t\t// Self-hosted GitLab keys its API base off `remotes`, so reset on both HTTP proxy and remotes changes.\n\t\tonConfigChanged: listener =>\n\t\t\tctx.config.onDidChange(e => {\n\t\t\t\tif (e.httpProxy || e.remotes) {\n\t\t\t\t\tlistener();\n\t\t\t\t}\n\t\t\t}),\n\t\tonReauthenticationRequired: message =>\n\t\t\tctx.hooks?.onReauthenticationRequired?.(message) ?? Promise.resolve(false),\n\t\tonRequestTimedOut: providerName => ctx.hooks?.ui?.onRequestTimedOut?.(providerName),\n\t};\n\n\treturn new GitLabApi(config);\n}\n"],"mappings":"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"}
@@ -136,5 +136,6 @@ export interface GitLabProjectREST {
136
136
  }
137
137
  export declare function fromGitLabMergeRequestProvidersApi(pr: ProviderPullRequest, provider: Integration): PullRequest;
138
138
  export declare function fromGitLabMergeRequest(pr: GitLabMergeRequestFull, provider: Provider): PullRequest;
139
+ export declare function getRepoNamespace(projectFullPath: string): string;
139
140
  //#endregion
140
141
  //# sourceMappingURL=models.d.ts.map
@@ -79,6 +79,6 @@ function getRepoNamespace(projectFullPath) {
79
79
  return projectFullPath.split("/").slice(0, -1).join("/");
80
80
  }
81
81
  //#endregion
82
- export { fromGitLabMergeRequest, fromGitLabMergeRequestProvidersApi, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, toGitLabMergeRequestState };
82
+ export { fromGitLabMergeRequest, fromGitLabMergeRequestProvidersApi, fromGitLabMergeRequestREST, fromGitLabMergeRequestState, getRepoNamespace, toGitLabMergeRequestState };
83
83
 
84
84
  //# 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\nfunction getRepoNamespace(projectFullPath: 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,SAAS,iBAAiB,iBAAyB;CAClD,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 { 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"}