@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.
- package/CHANGELOG.md +72 -1
- package/dist/git/cache.d.ts +29 -5
- package/dist/git/cache.js +52 -11
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +6 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/errors.d.ts +28 -1
- package/dist/git/errors.js +45 -1
- package/dist/git/errors.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.js +1 -0
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/reflog.d.ts +6 -0
- package/dist/git/models/reflog.js.map +1 -1
- package/dist/git/models/revision.d.ts +0 -1
- package/dist/git/models/revision.js +1 -2
- package/dist/git/models/revision.js.map +1 -1
- package/dist/git/providers/branches.d.ts +5 -1
- package/dist/git/providers/commits.d.ts +44 -2
- package/dist/git/providers/config.d.ts +7 -1
- package/dist/git/providers/operations.d.ts +19 -0
- package/dist/git/providers/provider.d.ts +29 -2
- package/dist/git/providers/refs.d.ts +48 -3
- package/dist/git/providers/revision.d.ts +7 -1
- package/dist/git/providers/staging.d.ts +13 -0
- package/dist/git/providers/stash.d.ts +3 -2
- package/dist/git/providers/status.d.ts +4 -0
- package/dist/git/providers/worktrees.d.ts +23 -3
- package/dist/git/run.types.d.ts +22 -0
- package/dist/git-cli/cliGitProvider.d.ts +39 -2
- package/dist/git-cli/cliGitProvider.js +109 -11
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/commandClassifier.d.ts +31 -0
- package/dist/git-cli/exec/commandClassifier.js +391 -0
- package/dist/git-cli/exec/commandClassifier.js.map +1 -0
- package/dist/git-cli/exec/git.d.ts +36 -5
- package/dist/git-cli/exec/git.js +163 -28
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +4 -1
- package/dist/git-cli/exec/gitQueue.js +1 -1
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/parsers/reflogParser.d.ts +7 -0
- package/dist/git-cli/parsers/reflogParser.js +11 -1
- package/dist/git-cli/parsers/reflogParser.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +10 -1
- package/dist/git-cli/providers/branches.js +31 -22
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +27 -3
- package/dist/git-cli/providers/commits.js +112 -12
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.js +2 -1
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/diff.js +4 -4
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +13 -0
- package/dist/git-cli/providers/operations.js +64 -5
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.js +21 -45
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +20 -3
- package/dist/git-cli/providers/refs.js +140 -10
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/remotes.js +3 -2
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +5 -1
- package/dist/git-cli/providers/revision.js +20 -5
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +9 -0
- package/dist/git-cli/providers/staging.js +63 -6
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts +3 -2
- package/dist/git-cli/providers/stash.js +34 -22
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +2 -0
- package/dist/git-cli/providers/status.js +27 -9
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +31 -2
- package/dist/git-cli/providers/worktrees.js +75 -7
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -3
- package/dist/plus/git-github/api/github.js +237 -24
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
- package/dist/plus/git-github/providers/github/branches.js +2 -1
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/commits.d.ts +4 -2
- package/dist/plus/git-github/providers/github/commits.js +3 -1
- package/dist/plus/git-github/providers/github/commits.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
- package/dist/plus/git-github/providers/github/refs.js +4 -4
- package/dist/plus/git-github/providers/github/refs.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts +4 -1
- package/dist/plus/git-github/providers/github/revision.js +6 -1
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +5 -2
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +35 -9
- package/dist/plus/integrations/integrationService.js +16 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +107 -37
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +128 -13
- package/dist/plus/integrations/models/gitHostIntegration.js +130 -17
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +51 -3
- package/dist/plus/integrations/models/integration.js +125 -18
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
- package/dist/plus/integrations/models/issuesIntegration.js +40 -10
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +13 -17
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
- package/dist/plus/integrations/providers/azure/models.js +112 -1
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +54 -2
- package/dist/plus/integrations/providers/azureDevOps.js +80 -2
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +38 -1
- package/dist/plus/integrations/providers/bitbucket-server.js +33 -1
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +36 -1
- package/dist/plus/integrations/providers/bitbucket.js +29 -1
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +48 -4
- package/dist/plus/integrations/providers/github.js +101 -6
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +1 -1
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +48 -1
- package/dist/plus/integrations/providers/gitlab.js +79 -3
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
- package/dist/plus/integrations/providers/jira-server.js +3 -3
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +12 -1
- package/dist/plus/integrations/providers/models.js +11 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
- package/dist/plus/integrations/providers/providerErrors.js +10 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +59 -0
- package/dist/plus/integrations/providers/providersApi.js +136 -1
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/providers/utils.d.ts +1 -1
- package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
- package/dist/plus/integrations/reads/currentAccount.js +46 -0
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
- package/dist/plus/integrations/reads/drains.d.ts +4 -1
- package/dist/plus/integrations/reads/drains.js +7 -3
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
- package/dist/plus/integrations/reads/issueBatch.js +193 -48
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequests.js +3 -3
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/sweeps.js +3 -3
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +5 -2
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/utils/env/node/exec.js +1 -1
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +90 -36
- package/docs/kepler-git-write-api-parity.md +365 -0
- package/docs/kepler-read-api-parity.md +75 -28
- package/package.json +1 -1
- package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
- package/dist/plus/integrations/reads/trackerIssue.js +0 -60
- 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
|
|
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?.
|
|
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\
|
|
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"}
|