@gitkraken/core-gitlens 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/dist/git/models/issue.d.ts +25 -2
- package/dist/git/models/issue.js +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/models/pullRequest.d.ts +62 -7
- package/dist/git/models/pullRequest.js +5 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/utils/issue.utils.d.ts +4 -0
- package/dist/git/utils/issue.utils.js +4 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +4 -0
- package/dist/git/utils/pullRequest.utils.js +8 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -4
- package/dist/plus/git-github/api/github.js +232 -15
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +48 -6
- package/dist/plus/git-github/models.js +11 -10
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/integrations/fieldPresence.d.ts +75 -0
- package/dist/plus/integrations/fieldPresence.js +381 -0
- package/dist/plus/integrations/fieldPresence.js.map +1 -0
- package/dist/plus/integrations/index.d.ts +6 -4
- package/dist/plus/integrations/index.js +2 -1
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +7 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +56 -6
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +103 -9
- package/dist/plus/integrations/models/gitHostIntegration.js +116 -5
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +91 -4
- package/dist/plus/integrations/models/integration.js +56 -7
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +44 -3
- package/dist/plus/integrations/models/issuesIntegration.js +51 -1
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +3 -3
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +36 -4
- package/dist/plus/integrations/providers/azure/models.js +118 -8
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +102 -5
- package/dist/plus/integrations/providers/azureDevOps.js +264 -45
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +30 -6
- package/dist/plus/integrations/providers/azureDevOpsServer.js +82 -21
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +21 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +74 -10
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +40 -3
- package/dist/plus/integrations/providers/bitbucket/models.js +30 -7
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +2 -6
- package/dist/plus/integrations/providers/bitbucket-server/models.js +1 -3
- package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +3 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +4 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +2 -2
- package/dist/plus/integrations/providers/bitbucket-server.js +7 -5
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +22 -2
- package/dist/plus/integrations/providers/bitbucket.js +29 -6
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +40 -3
- package/dist/plus/integrations/providers/github.js +133 -11
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +34 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.js +118 -4
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +70 -5
- package/dist/plus/integrations/providers/gitlab/models.js +106 -13
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +31 -2
- package/dist/plus/integrations/providers/gitlab.js +48 -8
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +1 -0
- package/dist/plus/integrations/providers/jira-server.js +9 -6
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +20 -1
- package/dist/plus/integrations/providers/jira.js +101 -6
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +79 -0
- package/dist/plus/integrations/providers/jiraIssueByKey.js +58 -7
- package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
- package/dist/plus/integrations/providers/linear.d.ts +19 -1
- package/dist/plus/integrations/providers/linear.js +97 -5
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +42 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.js +94 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -0
- package/dist/plus/integrations/providers/models.d.ts +51 -7
- package/dist/plus/integrations/providers/models.js +46 -17
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.js +8 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +62 -3
- package/dist/plus/integrations/providers/providersApi.js +145 -4
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts +13 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js +30 -6
- package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -1
- package/dist/plus/integrations/providers/trello.js +10 -7
- package/dist/plus/integrations/providers/trello.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +11 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +47 -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/batchEtags.d.ts +69 -0
- package/dist/plus/integrations/reads/batchEtags.js +114 -0
- package/dist/plus/integrations/reads/batchEtags.js.map +1 -0
- package/dist/plus/integrations/reads/counts.js +2 -2
- package/dist/plus/integrations/reads/counts.js.map +1 -1
- package/dist/plus/integrations/reads/currentAccount.js +2 -2
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +12 -3
- package/dist/plus/integrations/reads/drains.js +29 -5
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/etag.d.ts +26 -0
- package/dist/plus/integrations/reads/etag.js +108 -0
- package/dist/plus/integrations/reads/etag.js.map +1 -0
- package/dist/plus/integrations/reads/hierarchy.js +3 -3
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +47 -16
- package/dist/plus/integrations/reads/issueBatch.js +55 -87
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +4 -4
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +1 -1
- package/dist/plus/integrations/reads/issues.js +4 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +44 -6
- package/dist/plus/integrations/reads/pullRequestBatch.js +31 -34
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +5 -2
- package/dist/plus/integrations/reads/pullRequestBranches.js +4 -3
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.js +8 -4
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/sweeps.js +8 -4
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/reads/warnings.d.ts +23 -8
- package/dist/plus/integrations/reads/warnings.js +43 -19
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +12 -4
- package/dist/plus/integrations/results.js +2 -0
- package/dist/plus/integrations/results.js.map +1 -1
- package/docs/integrations.md +385 -23
- package/docs/kepler-read-api-parity.md +16 -2
- package/package.json +1 -1
|
@@ -6,8 +6,9 @@ import { Account } from "../../../../git/models/author.js";
|
|
|
6
6
|
import { DefaultBranch } from "../../../../git/models/defaultBranch.js";
|
|
7
7
|
import { RepositoryMetadata } from "../../../../git/models/repositoryMetadata.js";
|
|
8
8
|
import { TokenWithInfo } from "../../authentication/models.js";
|
|
9
|
+
import { IssueEtagInclude, PullRequestEtagInclude } from "../../models/integration.js";
|
|
9
10
|
import { ProviderApiConfig } from "../apiConfig.js";
|
|
10
|
-
import { GitLabMergeRequestState, GitLabSshKey } from "./models.js";
|
|
11
|
+
import { GitLabIssueEtagNode, GitLabMergeRequestEtagNode, GitLabMergeRequestState, GitLabSshKey } from "./models.js";
|
|
11
12
|
import { IntegrationServiceContext } from "../../context.js";
|
|
12
13
|
//#region ../plus/integrations/src/providers/gitlab/gitlab.d.ts
|
|
13
14
|
export declare class GitLabApi implements Disposable {
|
|
@@ -81,6 +82,38 @@ export declare class GitLabApi implements Disposable {
|
|
|
81
82
|
numbers: number[];
|
|
82
83
|
truncated: boolean;
|
|
83
84
|
}>;
|
|
85
|
+
/**
|
|
86
|
+
* The change state of merge requests `iids` in `fullPath` — the cheap check behind the batch pull request read's
|
|
87
|
+
* etags. Selects only what provider-apis' `getPullRequestForRepo` maps into a full row's etag inputs, plus the
|
|
88
|
+
* fields of each of `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One
|
|
89
|
+
* entry per input iid, in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).
|
|
90
|
+
*/
|
|
91
|
+
getMergeRequestsEtagFields(provider: Provider, token: TokenWithInfo, fullPath: string, iids: readonly number[], options: {
|
|
92
|
+
baseUrl?: string;
|
|
93
|
+
etagIncludes: readonly PullRequestEtagInclude[];
|
|
94
|
+
deferFailure?: boolean;
|
|
95
|
+
}, cancellation?: AbortSignal): Promise<(GitLabMergeRequestEtagNode | undefined)[]>;
|
|
96
|
+
/**
|
|
97
|
+
* The change state of issues `iids` in `fullPath` — the cheap check behind the batch issue read's etags — selecting
|
|
98
|
+
* only what provider-apis' issue read maps into a full row's etag inputs, plus the field of each of
|
|
99
|
+
* `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One entry per input iid,
|
|
100
|
+
* in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).
|
|
101
|
+
*/
|
|
102
|
+
getIssuesEtagFields(provider: Provider, token: TokenWithInfo, fullPath: string, iids: readonly number[], options: {
|
|
103
|
+
baseUrl?: string;
|
|
104
|
+
etagIncludes: readonly IssueEtagInclude[];
|
|
105
|
+
deferFailure?: boolean;
|
|
106
|
+
}, cancellation?: AbortSignal): Promise<(GitLabIssueEtagNode | undefined)[]>;
|
|
107
|
+
/**
|
|
108
|
+
* Runs an etag read's `query` and maps its `connection`'s nodes back to `iids`, positionally.
|
|
109
|
+
*
|
|
110
|
+
* Strict like {@link getPullRequest}'s `strict`: an iid is absent only when the project is `null`, or when it is
|
|
111
|
+
* missing from a complete page of an error-free reply — the answers that prove a miss to the full read's own
|
|
112
|
+
* confirming read. GraphQL `errors`, an empty response, a `null` connection, a page that has more and any HTTP
|
|
113
|
+
* error (a 404 means a wrong endpoint) throw instead. The query asks for `state: all`, so no default state filter
|
|
114
|
+
* can hide a closed or merged item and have it read as missing.
|
|
115
|
+
*/
|
|
116
|
+
private getEtagFieldsByIid;
|
|
84
117
|
getRepositoryMetadata(provider: Provider, token: TokenWithInfo, owner: string, repo: string, options?: {
|
|
85
118
|
baseUrl?: string;
|
|
86
119
|
}, cancellation?: AbortSignal): Promise<RepositoryMetadata | undefined>;
|
|
@@ -284,7 +284,7 @@ var GitLabApi = class {
|
|
|
284
284
|
}, String(pr.iid), void 0, pr.title, pr.webUrl, {
|
|
285
285
|
owner,
|
|
286
286
|
repo
|
|
287
|
-
}, fromGitLabMergeRequestState(pr.state), new Date(pr.createdAt), new Date(pr.updatedAt), pr.state !== "closed" ? void 0 : new Date(pr.updatedAt), pr.mergedAt == null ? void 0 : new Date(pr.mergedAt));
|
|
287
|
+
}, fromGitLabMergeRequestState(pr.state), new Date(pr.createdAt), new Date(pr.updatedAt), pr.state !== "closed" ? void 0 : new Date(pr.updatedAt), pr.mergedAt == null ? void 0 : new Date(pr.mergedAt), void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, "point");
|
|
288
288
|
} catch (ex) {
|
|
289
289
|
if (ex instanceof RequestNotFoundError) return void 0;
|
|
290
290
|
throw this.handleException(ex, provider, scope);
|
|
@@ -301,7 +301,7 @@ var GitLabApi = class {
|
|
|
301
301
|
return fromGitLabMergeRequestREST(mrs[0], provider, {
|
|
302
302
|
owner,
|
|
303
303
|
repo
|
|
304
|
-
});
|
|
304
|
+
}, "point");
|
|
305
305
|
} catch (ex) {
|
|
306
306
|
if (ex instanceof RequestNotFoundError) return void 0;
|
|
307
307
|
throw this.handleException(ex, provider, scope);
|
|
@@ -359,7 +359,7 @@ var GitLabApi = class {
|
|
|
359
359
|
}
|
|
360
360
|
if (rsp.data.project?.mergeRequest == null) return void 0;
|
|
361
361
|
const pr = rsp.data.project.mergeRequest;
|
|
362
|
-
return fromGitLabMergeRequest(pr, provider);
|
|
362
|
+
return fromGitLabMergeRequest(pr, provider, "point");
|
|
363
363
|
} catch (ex) {
|
|
364
364
|
if (!options?.strict && ex instanceof RequestNotFoundError) return void 0;
|
|
365
365
|
throw this.handleException(ex, provider, scope);
|
|
@@ -440,6 +440,108 @@ var GitLabApi = class {
|
|
|
440
440
|
throw this.handleException(ex, provider, scope);
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* The change state of merge requests `iids` in `fullPath` — the cheap check behind the batch pull request read's
|
|
445
|
+
* etags. Selects only what provider-apis' `getPullRequestForRepo` maps into a full row's etag inputs, plus the
|
|
446
|
+
* fields of each of `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One
|
|
447
|
+
* entry per input iid, in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).
|
|
448
|
+
*/
|
|
449
|
+
async getMergeRequestsEtagFields(provider, token, fullPath, iids, options, cancellation) {
|
|
450
|
+
const scope = getScopedLogger();
|
|
451
|
+
const selections = [
|
|
452
|
+
"iid",
|
|
453
|
+
"state",
|
|
454
|
+
"draft",
|
|
455
|
+
"updatedAt",
|
|
456
|
+
"diffRefs { headSha }"
|
|
457
|
+
];
|
|
458
|
+
if (options.etagIncludes.includes("mergeable")) selections.push("mergeStatusEnum");
|
|
459
|
+
if (options.etagIncludes.includes("reviewDecision")) selections.push("reviewers { nodes { mergeRequestInteraction { reviewState } } }");
|
|
460
|
+
if (options.etagIncludes.includes("checks")) selections.push("headPipeline { stages { nodes { jobs { nodes { status allowFailure } } } } }");
|
|
461
|
+
try {
|
|
462
|
+
const query = `query getMergeRequestsEtagFields(
|
|
463
|
+
$fullPath: ID!
|
|
464
|
+
$iids: [String!]
|
|
465
|
+
$first: Int!
|
|
466
|
+
) {
|
|
467
|
+
project(fullPath: $fullPath) {
|
|
468
|
+
mergeRequests(iids: $iids, state: all, first: $first) {
|
|
469
|
+
pageInfo {
|
|
470
|
+
hasNextPage
|
|
471
|
+
}
|
|
472
|
+
nodes {
|
|
473
|
+
${selections.join("\n ")}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}`;
|
|
478
|
+
return await this.getEtagFieldsByIid(provider, token, options.baseUrl, query, "mergeRequests", fullPath, iids, cancellation, scope, options.deferFailure);
|
|
479
|
+
} catch (ex) {
|
|
480
|
+
throw this.handleException(ex, provider, scope);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* The change state of issues `iids` in `fullPath` — the cheap check behind the batch issue read's etags — selecting
|
|
485
|
+
* only what provider-apis' issue read maps into a full row's etag inputs, plus the field of each of
|
|
486
|
+
* `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One entry per input iid,
|
|
487
|
+
* in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).
|
|
488
|
+
*/
|
|
489
|
+
async getIssuesEtagFields(provider, token, fullPath, iids, options, cancellation) {
|
|
490
|
+
const scope = getScopedLogger();
|
|
491
|
+
const selections = [
|
|
492
|
+
"iid",
|
|
493
|
+
"closedAt",
|
|
494
|
+
"updatedAt"
|
|
495
|
+
];
|
|
496
|
+
if (options.etagIncludes.includes("reactions")) selections.push("upvotes");
|
|
497
|
+
try {
|
|
498
|
+
const query = `query getIssuesEtagFields(
|
|
499
|
+
$fullPath: ID!
|
|
500
|
+
$iids: [String!]
|
|
501
|
+
$first: Int!
|
|
502
|
+
) {
|
|
503
|
+
project(fullPath: $fullPath) {
|
|
504
|
+
issues(iids: $iids, state: all, first: $first) {
|
|
505
|
+
pageInfo {
|
|
506
|
+
hasNextPage
|
|
507
|
+
}
|
|
508
|
+
nodes {
|
|
509
|
+
${selections.join("\n ")}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}`;
|
|
514
|
+
return await this.getEtagFieldsByIid(provider, token, options.baseUrl, query, "issues", fullPath, iids, cancellation, scope, options.deferFailure);
|
|
515
|
+
} catch (ex) {
|
|
516
|
+
throw this.handleException(ex, provider, scope);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Runs an etag read's `query` and maps its `connection`'s nodes back to `iids`, positionally.
|
|
521
|
+
*
|
|
522
|
+
* Strict like {@link getPullRequest}'s `strict`: an iid is absent only when the project is `null`, or when it is
|
|
523
|
+
* missing from a complete page of an error-free reply — the answers that prove a miss to the full read's own
|
|
524
|
+
* confirming read. GraphQL `errors`, an empty response, a `null` connection, a page that has more and any HTTP
|
|
525
|
+
* error (a 404 means a wrong endpoint) throw instead. The query asks for `state: all`, so no default state filter
|
|
526
|
+
* can hide a closed or merged item and have it read as missing.
|
|
527
|
+
*/
|
|
528
|
+
async getEtagFieldsByIid(provider, token, baseUrl, query, connection, fullPath, iids, cancellation, scope, deferFailure) {
|
|
529
|
+
if (!iids.length) return [];
|
|
530
|
+
if (iids.length > 100) throw new Error(`Cannot read more than 100 GitLab iids in one request`);
|
|
531
|
+
const rsp = await this.graphql(provider, token, baseUrl, query, {
|
|
532
|
+
fullPath,
|
|
533
|
+
iids: iids.map(String),
|
|
534
|
+
first: iids.length
|
|
535
|
+
}, cancellation, scope, deferFailure);
|
|
536
|
+
if (rsp?.data == null) throw new Error(`GitLab returned no data for the ${connection} of ${fullPath}`);
|
|
537
|
+
const project = rsp.data.project;
|
|
538
|
+
if (project == null) return iids.map(() => void 0);
|
|
539
|
+
const page = project[connection];
|
|
540
|
+
if (page?.nodes == null) throw new Error(`GitLab returned no ${connection} for ${fullPath}`);
|
|
541
|
+
if (page.pageInfo.hasNextPage) throw new Error(`GitLab returned a partial page of ${connection}`);
|
|
542
|
+
const byIid = new Map(page.nodes.map((node) => [node.iid, node]));
|
|
543
|
+
return iids.map((iid) => byIid.get(String(iid)));
|
|
544
|
+
}
|
|
443
545
|
async getRepositoryMetadata(provider, token, owner, repo, options, cancellation) {
|
|
444
546
|
const scope = getScopedLogger();
|
|
445
547
|
const projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);
|
|
@@ -531,7 +633,7 @@ var GitLabApi = class {
|
|
|
531
633
|
sourceBranch: restPR.source_branch,
|
|
532
634
|
targetBranch: restPR.target_branch
|
|
533
635
|
};
|
|
534
|
-
accum.push(fromGitLabMergeRequest(fullPr, provider));
|
|
636
|
+
accum.push(fromGitLabMergeRequest(fullPr, provider, "text-search"));
|
|
535
637
|
return accum;
|
|
536
638
|
}, []);
|
|
537
639
|
return [];
|
|
@@ -781,6 +883,18 @@ __decorate([trace({ args: (provider, token, owner, repo, branch) => ({
|
|
|
781
883
|
repo,
|
|
782
884
|
branch
|
|
783
885
|
}) })], GitLabApi.prototype, "getPullRequestNumbersForBranch", null);
|
|
886
|
+
__decorate([trace({ args: (provider, token, fullPath, iids) => ({
|
|
887
|
+
provider: provider.name,
|
|
888
|
+
token: `<token:${token.microHash}>`,
|
|
889
|
+
fullPath,
|
|
890
|
+
iids: iids.length
|
|
891
|
+
}) })], GitLabApi.prototype, "getMergeRequestsEtagFields", null);
|
|
892
|
+
__decorate([trace({ args: (provider, token, fullPath, iids) => ({
|
|
893
|
+
provider: provider.name,
|
|
894
|
+
token: `<token:${token.microHash}>`,
|
|
895
|
+
fullPath,
|
|
896
|
+
iids: iids.length
|
|
897
|
+
}) })], GitLabApi.prototype, "getIssuesEtagFields", null);
|
|
784
898
|
__decorate([trace({ args: (provider, token, owner, repo) => ({
|
|
785
899
|
provider: provider.name,
|
|
786
900
|
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 { 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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"}
|
|
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 { IssueEtagInclude, PullRequestEtagInclude } from '../../models/integration.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\tGitLabIssueEtagNode,\n\tGitLabMergeRequest,\n\tGitLabMergeRequestEtagNode,\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\tgitLabEtagFieldsMaxIids,\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\tundefined, // mergeableState\n\t\t\t\tundefined, // viewerCanUpdate\n\t\t\t\tundefined, // refs\n\t\t\t\tundefined, // isDraft\n\t\t\t\tundefined, // additions\n\t\t\t\tundefined, // deletions\n\t\t\t\tundefined, // commentsCount\n\t\t\t\tundefined, // thumbsUpCount\n\t\t\t\tundefined, // reviewDecision\n\t\t\t\tundefined, // reviewRequests\n\t\t\t\tundefined, // latestReviews\n\t\t\t\tundefined, // assignees\n\t\t\t\tundefined, // statusCheckRollupState\n\t\t\t\tundefined, // project\n\t\t\t\tundefined, // version\n\t\t\t\tundefined, // commitCount\n\t\t\t\tundefined, // stack\n\t\t\t\tundefined, // filesChanged\n\t\t\t\tundefined, // body\n\t\t\t\tundefined, // number\n\t\t\t\tundefined, // authoredByMe\n\t\t\t\t'point',\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 }, 'point');\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, 'point');\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/**\n\t * The change state of merge requests `iids` in `fullPath` — the cheap check behind the batch pull request read's\n\t * etags. Selects only what provider-apis' `getPullRequestForRepo` maps into a full row's etag inputs, plus the\n\t * fields of each of `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One\n\t * entry per input iid, in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).\n\t */\n\t@trace({\n\t\targs: (provider, token, fullPath, iids) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\tfullPath: fullPath,\n\t\t\tiids: iids.length,\n\t\t}),\n\t})\n\tasync getMergeRequestsEtagFields(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tfullPath: string,\n\t\tiids: readonly number[],\n\t\toptions: { baseUrl?: string; etagIncludes: readonly PullRequestEtagInclude[]; deferFailure?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<(GitLabMergeRequestEtagNode | undefined)[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst selections = ['iid', 'state', 'draft', 'updatedAt', 'diffRefs { headSha }'];\n\t\tif (options.etagIncludes.includes('mergeable')) {\n\t\t\tselections.push('mergeStatusEnum');\n\t\t}\n\t\tif (options.etagIncludes.includes('reviewDecision')) {\n\t\t\tselections.push('reviewers { nodes { mergeRequestInteraction { reviewState } } }');\n\t\t}\n\t\tif (options.etagIncludes.includes('checks')) {\n\t\t\tselections.push('headPipeline { stages { nodes { jobs { nodes { status allowFailure } } } } }');\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getMergeRequestsEtagFields(\n\t$fullPath: ID!\n\t$iids: [String!]\n\t$first: Int!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tmergeRequests(iids: $iids, state: all, first: $first) {\n\t\t\tpageInfo {\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\t${selections.join('\\n\\t\\t\\t\\t')}\n\t\t\t}\n\t\t}\n\t}\n}`;\n\n\t\t\treturn await this.getEtagFieldsByIid<GitLabMergeRequestEtagNode>(\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'mergeRequests',\n\t\t\t\tfullPath,\n\t\t\t\tiids,\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t\toptions.deferFailure,\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t/**\n\t * The change state of issues `iids` in `fullPath` — the cheap check behind the batch issue read's etags — selecting\n\t * only what provider-apis' issue read maps into a full row's etag inputs, plus the field of each of\n\t * `options.etagIncludes`, in ONE request for up to {@link gitLabEtagFieldsMaxIids} iids. One entry per input iid,\n\t * in order; `undefined` is a PROVEN ABSENCE (see {@link getEtagFieldsByIid}).\n\t */\n\t@trace({\n\t\targs: (provider, token, fullPath, iids) => ({\n\t\t\tprovider: provider.name,\n\t\t\ttoken: `<token:${token.microHash}>`,\n\t\t\tfullPath: fullPath,\n\t\t\tiids: iids.length,\n\t\t}),\n\t})\n\tasync getIssuesEtagFields(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tfullPath: string,\n\t\tiids: readonly number[],\n\t\toptions: { baseUrl?: string; etagIncludes: readonly IssueEtagInclude[]; deferFailure?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<(GitLabIssueEtagNode | undefined)[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst selections = ['iid', 'closedAt', 'updatedAt'];\n\t\tif (options.etagIncludes.includes('reactions')) {\n\t\t\tselections.push('upvotes');\n\t\t}\n\n\t\ttry {\n\t\t\tconst query = `query getIssuesEtagFields(\n\t$fullPath: ID!\n\t$iids: [String!]\n\t$first: Int!\n) {\n\tproject(fullPath: $fullPath) {\n\t\tissues(iids: $iids, state: all, first: $first) {\n\t\t\tpageInfo {\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\t${selections.join('\\n\\t\\t\\t\\t')}\n\t\t\t}\n\t\t}\n\t}\n}`;\n\n\t\t\treturn await this.getEtagFieldsByIid<GitLabIssueEtagNode>(\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'issues',\n\t\t\t\tfullPath,\n\t\t\t\tiids,\n\t\t\t\tcancellation,\n\t\t\t\tscope,\n\t\t\t\toptions.deferFailure,\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tthrow this.handleException(ex, provider, scope);\n\t\t}\n\t}\n\n\t/**\n\t * Runs an etag read's `query` and maps its `connection`'s nodes back to `iids`, positionally.\n\t *\n\t * Strict like {@link getPullRequest}'s `strict`: an iid is absent only when the project is `null`, or when it is\n\t * missing from a complete page of an error-free reply — the answers that prove a miss to the full read's own\n\t * confirming read. GraphQL `errors`, an empty response, a `null` connection, a page that has more and any HTTP\n\t * error (a 404 means a wrong endpoint) throw instead. The query asks for `state: all`, so no default state filter\n\t * can hide a closed or merged item and have it read as missing.\n\t */\n\tprivate async getEtagFieldsByIid<T extends { iid: string }>(\n\t\tprovider: Provider,\n\t\ttoken: TokenWithInfo,\n\t\tbaseUrl: string | undefined,\n\t\tquery: string,\n\t\tconnection: 'mergeRequests' | 'issues',\n\t\tfullPath: string,\n\t\tiids: readonly number[],\n\t\tcancellation: AbortSignal | undefined,\n\t\tscope: ScopedLogger | undefined,\n\t\tdeferFailure: boolean | undefined,\n\t): Promise<(T | undefined)[]> {\n\t\tif (!iids.length) return [];\n\t\tif (iids.length > gitLabEtagFieldsMaxIids) {\n\t\t\tthrow new Error(`Cannot read more than ${gitLabEtagFieldsMaxIids} GitLab iids in one request`);\n\t\t}\n\n\t\tinterface QueryResult {\n\t\t\tdata: {\n\t\t\t\tproject: Partial<\n\t\t\t\t\tRecord<'mergeRequests' | 'issues', { pageInfo: { hasNextPage: boolean }; nodes: T[] } | null>\n\t\t\t\t> | null;\n\t\t\t} | null;\n\t\t}\n\n\t\tconst rsp = await this.graphql<QueryResult>(\n\t\t\tprovider,\n\t\t\ttoken,\n\t\t\tbaseUrl,\n\t\t\tquery,\n\t\t\t{ fullPath: fullPath, iids: iids.map(String), first: iids.length },\n\t\t\tcancellation,\n\t\t\tscope,\n\t\t\tdeferFailure,\n\t\t);\n\t\tif (rsp?.data == null) throw new Error(`GitLab returned no data for the ${connection} of ${fullPath}`);\n\n\t\tconst project = rsp.data.project;\n\t\tif (project == null) return iids.map(() => undefined);\n\n\t\tconst page = project[connection];\n\t\tif (page?.nodes == null) throw new Error(`GitLab returned no ${connection} for ${fullPath}`);\n\t\tif (page.pageInfo.hasNextPage) throw new Error(`GitLab returned a partial page of ${connection}`);\n\n\t\tconst byIid = new Map(page.nodes.map(node => [node.iid, node]));\n\t\treturn iids.map(iid => byIid.get(String(iid)));\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, 'text-search'));\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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"}
|