@gitkraken/core-gitlens 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/README.md +13 -10
- package/dist/git/context.d.ts +4 -3
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/providers/operations.d.ts +1 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/worktrees.d.ts +2 -0
- package/dist/git/providers/worktrees.d.ts.map +1 -1
- package/dist/git/utils/conflictResolution.utils.d.ts +32 -0
- package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -1
- package/dist/git/utils/conflictResolution.utils.js +95 -0
- package/dist/git/utils/conflictResolution.utils.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +1 -0
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +22 -1
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +2 -0
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +3 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +5 -5
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +6 -13
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +5 -10
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +11 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js +90 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +67 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +295 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +92 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +185 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +62 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js +122 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts +15 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js +49 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/models.d.ts +87 -0
- package/dist/plus/integrations/authentication/models.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/models.js +64 -0
- package/dist/plus/integrations/authentication/models.js.map +1 -0
- package/dist/plus/integrations/constants.d.ts +47 -0
- package/dist/plus/integrations/constants.d.ts.map +1 -0
- package/dist/plus/integrations/constants.js +128 -0
- package/dist/plus/integrations/constants.js.map +1 -0
- package/dist/plus/integrations/context.d.ts +354 -0
- package/dist/plus/integrations/context.d.ts.map +1 -0
- package/dist/plus/integrations/context.js +2 -0
- package/dist/plus/integrations/context.js.map +1 -0
- package/dist/plus/integrations/errors.d.ts +14 -0
- package/dist/plus/integrations/errors.d.ts.map +1 -0
- package/dist/plus/integrations/errors.js +19 -0
- package/dist/plus/integrations/errors.js.map +1 -0
- package/dist/plus/integrations/index.d.ts +32 -0
- package/dist/plus/integrations/index.d.ts.map +1 -0
- package/dist/plus/integrations/index.js +62 -0
- package/dist/plus/integrations/index.js.map +1 -0
- package/dist/plus/integrations/integrationService.d.ts +98 -0
- package/dist/plus/integrations/integrationService.d.ts.map +1 -0
- package/dist/plus/integrations/integrationService.js +627 -0
- package/dist/plus/integrations/integrationService.js.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +82 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.js +522 -0
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -0
- package/dist/plus/integrations/models/integration.d.ts +127 -0
- package/dist/plus/integrations/models/integration.d.ts.map +1 -0
- package/dist/plus/integrations/models/integration.js +456 -0
- package/dist/plus/integrations/models/integration.js.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts +28 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.js +101 -0
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -0
- package/dist/plus/integrations/providers/apiClients.d.ts +25 -0
- package/dist/plus/integrations/providers/apiClients.d.ts.map +1 -0
- package/dist/plus/integrations/providers/apiClients.js +39 -0
- package/dist/plus/integrations/providers/apiClients.js.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts +47 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.js +444 -0
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -0
- package/dist/plus/integrations/providers/azure/models.d.ts +286 -0
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/models.js +203 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts +95 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.js +432 -0
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +42 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +513 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +222 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js +158 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +120 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js +111 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +60 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.js +138 -0
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts +50 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.js +181 -0
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.d.ts +5 -0
- package/dist/plus/integrations/providers/github/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.js +47 -0
- package/dist/plus/integrations/providers/github/github.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts +11 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.js +6 -0
- package/dist/plus/integrations/providers/github/github.utils.js.map +1 -0
- package/dist/plus/integrations/providers/github/models.d.ts +3 -0
- package/dist/plus/integrations/providers/github/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/models.js +2 -0
- package/dist/plus/integrations/providers/github/models.js.map +1 -0
- package/dist/plus/integrations/providers/github.d.ts +73 -0
- package/dist/plus/integrations/providers/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github.js +160 -0
- package/dist/plus/integrations/providers/github.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +63 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +828 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts +21 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js +45 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts +128 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +96 -0
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab.d.ts +79 -0
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab.js +253 -0
- package/dist/plus/integrations/providers/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/jira.d.ts +46 -0
- package/dist/plus/integrations/providers/jira.d.ts.map +1 -0
- package/dist/plus/integrations/providers/jira.js +255 -0
- package/dist/plus/integrations/providers/jira.js.map +1 -0
- package/dist/plus/integrations/providers/linear.d.ts +47 -0
- package/dist/plus/integrations/providers/linear.d.ts.map +1 -0
- package/dist/plus/integrations/providers/linear.js +198 -0
- package/dist/plus/integrations/providers/linear.js.map +1 -0
- package/dist/plus/integrations/providers/models.d.ts +433 -0
- package/dist/plus/integrations/providers/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/models.js +602 -0
- package/dist/plus/integrations/providers/models.js.map +1 -0
- package/dist/plus/integrations/providers/providersApi.d.ts +129 -0
- package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -0
- package/dist/plus/integrations/providers/providersApi.js +602 -0
- package/dist/plus/integrations/providers/providersApi.js.map +1 -0
- package/dist/plus/integrations/providers/utils.d.ts +54 -0
- package/dist/plus/integrations/providers/utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/utils.js +262 -0
- package/dist/plus/integrations/providers/utils.js.map +1 -0
- package/dist/plus/integrations/telemetry.d.ts +26 -0
- package/dist/plus/integrations/telemetry.d.ts.map +1 -0
- package/dist/plus/integrations/telemetry.js +11 -0
- package/dist/plus/integrations/telemetry.js.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts +14 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.js +111 -0
- package/dist/plus/integrations/utils/integration.utils.js.map +1 -0
- package/dist/utils/disposable.d.ts +15 -2
- package/dist/utils/disposable.d.ts.map +1 -1
- package/dist/utils/disposable.js.map +1 -1
- package/package.json +43 -2
- package/src/git/context.ts +4 -3
- package/src/git/providers/operations.ts +1 -1
- package/src/git/providers/worktrees.ts +14 -2
- package/src/git/utils/conflictResolution.utils.ts +126 -0
- package/src/git-cli/providers/operations.ts +22 -2
- package/src/git-cli/providers/worktrees.ts +17 -2
- package/src/plus/ai/utils/ai.utils.ts +5 -5
- package/src/plus/git-github/api/github.ts +13 -25
- package/src/plus/integrations/authentication/cloudIntegrationService.ts +120 -0
- package/src/plus/integrations/authentication/configuredIntegrationService.ts +414 -0
- package/src/plus/integrations/authentication/integrationAuthenticationProvider.ts +289 -0
- package/src/plus/integrations/authentication/integrationAuthenticationService.ts +144 -0
- package/src/plus/integrations/authentication/manualTokenProvider.ts +72 -0
- package/src/plus/integrations/authentication/models.ts +168 -0
- package/src/plus/integrations/constants.ts +169 -0
- package/src/plus/integrations/context.ts +383 -0
- package/src/plus/integrations/errors.ts +35 -0
- package/src/plus/integrations/index.ts +119 -0
- package/src/plus/integrations/integrationService.ts +924 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +738 -0
- package/src/plus/integrations/models/integration.ts +657 -0
- package/src/plus/integrations/models/issuesIntegration.ts +124 -0
- package/src/plus/integrations/providers/apiClients.ts +72 -0
- package/src/plus/integrations/providers/azure/azure.ts +691 -0
- package/src/plus/integrations/providers/azure/models.ts +605 -0
- package/src/plus/integrations/providers/azureDevOps.ts +677 -0
- package/src/plus/integrations/providers/bitbucket/bitbucket.ts +774 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +445 -0
- package/src/plus/integrations/providers/bitbucket-server/models.ts +252 -0
- package/src/plus/integrations/providers/bitbucket-server.ts +282 -0
- package/src/plus/integrations/providers/bitbucket.ts +350 -0
- package/src/plus/integrations/providers/github/github.ts +64 -0
- package/src/plus/integrations/providers/github/github.utils.ts +23 -0
- package/src/plus/integrations/providers/github/models.ts +29 -0
- package/src/plus/integrations/providers/github.ts +366 -0
- package/src/plus/integrations/providers/gitlab/gitlab.ts +1210 -0
- package/src/plus/integrations/providers/gitlab/gitlab.utils.ts +71 -0
- package/src/plus/integrations/providers/gitlab/models.ts +257 -0
- package/src/plus/integrations/providers/gitlab.ts +473 -0
- package/src/plus/integrations/providers/jira.ts +359 -0
- package/src/plus/integrations/providers/linear.ts +275 -0
- package/src/plus/integrations/providers/models.ts +1114 -0
- package/src/plus/integrations/providers/providersApi.ts +1126 -0
- package/src/plus/integrations/providers/utils.ts +359 -0
- package/src/plus/integrations/telemetry.ts +29 -0
- package/src/plus/integrations/utils/integration.utils.ts +138 -0
- package/src/utils/disposable.ts +15 -2
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { PullRequest } from '../../../../git/models/pullRequest.js';
|
|
8
|
+
import { CancellationError } from '../../../../utils/cancellation.js';
|
|
9
|
+
import { trace } from '../../../../utils/decorators/log.js';
|
|
10
|
+
import { Logger } from '../../../../utils/logger.js';
|
|
11
|
+
import { getScopedLogger } from '../../../../utils/logger.scoped.js';
|
|
12
|
+
import { maybeStopWatch } from '../../../../utils/stopwatch.js';
|
|
13
|
+
import { equalsIgnoreCase } from '../../../../utils/string.js';
|
|
14
|
+
import { joinUriPath, parseUri } from '../../../../utils/uri.js';
|
|
15
|
+
import { AuthenticationError, AuthenticationErrorReason, ProviderFetchError, RequestClientError, RequestNotFoundError, RequestRateLimitError, } from '../../errors.js';
|
|
16
|
+
import { selectGitLabUserForCommit } from './gitlab.utils.js';
|
|
17
|
+
import { fromGitLabMergeRequest, fromGitLabMergeRequestREST, fromGitLabMergeRequestState } from './models.js';
|
|
18
|
+
// drop it as soon as we switch to @gitkraken/providers-api
|
|
19
|
+
const gitlabUserIdPrefix = 'gid://gitlab/User/';
|
|
20
|
+
const gitlabMergeRequestIdPrefix = 'gid://gitlab/MergeRequest/';
|
|
21
|
+
function buildGitLabUserId(id) {
|
|
22
|
+
return typeof id === 'string' && id?.startsWith(gitlabUserIdPrefix)
|
|
23
|
+
? id.substring(gitlabUserIdPrefix.length)
|
|
24
|
+
: String(id);
|
|
25
|
+
}
|
|
26
|
+
export class GitLabApi {
|
|
27
|
+
ctx;
|
|
28
|
+
_disposable;
|
|
29
|
+
_projectIds = new Map();
|
|
30
|
+
constructor(ctx) {
|
|
31
|
+
this.ctx = ctx;
|
|
32
|
+
this._disposable = ctx.config.onDidChange(e => {
|
|
33
|
+
if (e.httpProxy || e.remotes) {
|
|
34
|
+
this.resetCaches();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
dispose() {
|
|
39
|
+
this._disposable.dispose();
|
|
40
|
+
}
|
|
41
|
+
resetCaches() {
|
|
42
|
+
this._projectIds.clear();
|
|
43
|
+
}
|
|
44
|
+
async getAccountForCommit(provider, token, owner, repo, rev, options, cancellation) {
|
|
45
|
+
const scope = getScopedLogger();
|
|
46
|
+
const projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);
|
|
47
|
+
if (!projectId)
|
|
48
|
+
return undefined;
|
|
49
|
+
try {
|
|
50
|
+
const commit = await this.request(provider, token, options?.baseUrl, `v4/projects/${projectId}/repository/commits/${rev}?stats=false`, {
|
|
51
|
+
method: 'GET',
|
|
52
|
+
// ...options,
|
|
53
|
+
}, cancellation, scope);
|
|
54
|
+
let users = await this.findUser(provider, token, commit.author_name, options, cancellation);
|
|
55
|
+
let user = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);
|
|
56
|
+
// If the name search was ambiguous (multiple users share the name), try an email-scoped search to
|
|
57
|
+
// disambiguate before giving up — otherwise we'd show a stranger's avatar (see #2205)
|
|
58
|
+
if (user == null && commit.author_email) {
|
|
59
|
+
const exactNameMatches = users.filter(u => equalsIgnoreCase(u.name, commit.author_name)).length;
|
|
60
|
+
if (exactNameMatches > 1) {
|
|
61
|
+
users = await this.findUser(provider, token, commit.author_email, options, cancellation);
|
|
62
|
+
user = selectGitLabUserForCommit(users, commit.author_name, commit.author_email);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (user == null)
|
|
66
|
+
return undefined;
|
|
67
|
+
// 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)
|
|
68
|
+
if (user.avatarUrl && !/^([a-zA-Z][\w+.-]+):/.test(user.avatarUrl)) {
|
|
69
|
+
user.avatarUrl = joinUriPath(parseUri(user.webUrl), '..', user.avatarUrl).toString();
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
provider: provider,
|
|
73
|
+
id: String(user.id),
|
|
74
|
+
name: user.name || undefined,
|
|
75
|
+
email: commit.author_email || undefined,
|
|
76
|
+
avatarUrl: user.avatarUrl || undefined,
|
|
77
|
+
username: user.username || undefined,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (ex) {
|
|
81
|
+
if (ex instanceof RequestNotFoundError)
|
|
82
|
+
return undefined;
|
|
83
|
+
throw this.handleException(ex, provider, scope);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async getAccountForEmail(provider, token, _owner, _repo, email, options) {
|
|
87
|
+
const scope = getScopedLogger();
|
|
88
|
+
try {
|
|
89
|
+
const [user] = await this.findUser(provider, token, email, options);
|
|
90
|
+
if (user == null)
|
|
91
|
+
return undefined;
|
|
92
|
+
return {
|
|
93
|
+
provider: provider,
|
|
94
|
+
id: String(user.id),
|
|
95
|
+
name: user.name || undefined,
|
|
96
|
+
email: user.publicEmail || undefined,
|
|
97
|
+
avatarUrl: user.avatarUrl || undefined,
|
|
98
|
+
username: user.username || undefined,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (ex) {
|
|
102
|
+
if (ex instanceof RequestNotFoundError)
|
|
103
|
+
return undefined;
|
|
104
|
+
throw this.handleException(ex, provider, scope);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async getDefaultBranch(provider, token, owner, repo, options, cancellation) {
|
|
108
|
+
const scope = getScopedLogger();
|
|
109
|
+
try {
|
|
110
|
+
const query = `query getDefaultBranch(
|
|
111
|
+
$fullPath: ID!
|
|
112
|
+
) {
|
|
113
|
+
project(fullPath: $fullPath) {
|
|
114
|
+
repository {
|
|
115
|
+
rootRef
|
|
116
|
+
}
|
|
117
|
+
}`;
|
|
118
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, {
|
|
119
|
+
fullPath: `${owner}/${repo}`,
|
|
120
|
+
}, cancellation, scope);
|
|
121
|
+
const defaultBranch = rsp?.data?.project?.repository?.rootRef ?? undefined;
|
|
122
|
+
if (defaultBranch == null)
|
|
123
|
+
return undefined;
|
|
124
|
+
return {
|
|
125
|
+
provider: provider,
|
|
126
|
+
name: defaultBranch,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (ex) {
|
|
130
|
+
if (ex instanceof RequestNotFoundError)
|
|
131
|
+
return undefined;
|
|
132
|
+
throw this.handleException(ex, provider, scope);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async getIssueOrPullRequest(provider, token, owner, repo, number, options, cancellation) {
|
|
136
|
+
const scope = getScopedLogger();
|
|
137
|
+
try {
|
|
138
|
+
const query = `query getIssueOrMergeRequest(
|
|
139
|
+
$fullPath: ID!
|
|
140
|
+
$iid: String!
|
|
141
|
+
) {
|
|
142
|
+
project(fullPath: $fullPath) {
|
|
143
|
+
mergeRequest(iid: $iid) {
|
|
144
|
+
author {
|
|
145
|
+
id
|
|
146
|
+
name
|
|
147
|
+
avatarUrl
|
|
148
|
+
webUrl
|
|
149
|
+
}
|
|
150
|
+
iid
|
|
151
|
+
title
|
|
152
|
+
description
|
|
153
|
+
state
|
|
154
|
+
createdAt
|
|
155
|
+
updatedAt
|
|
156
|
+
mergedAt
|
|
157
|
+
webUrl
|
|
158
|
+
}
|
|
159
|
+
issue(iid: $iid) {
|
|
160
|
+
author {
|
|
161
|
+
id
|
|
162
|
+
name
|
|
163
|
+
avatarUrl
|
|
164
|
+
webUrl
|
|
165
|
+
}
|
|
166
|
+
iid
|
|
167
|
+
title
|
|
168
|
+
description
|
|
169
|
+
state
|
|
170
|
+
createdAt
|
|
171
|
+
updatedAt
|
|
172
|
+
closedAt
|
|
173
|
+
webUrl
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}`;
|
|
177
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, {
|
|
178
|
+
fullPath: `${owner}/${repo}`,
|
|
179
|
+
iid: String(number),
|
|
180
|
+
}, cancellation, scope);
|
|
181
|
+
if (rsp?.data?.project?.issue != null) {
|
|
182
|
+
const issue = rsp.data.project.issue;
|
|
183
|
+
return {
|
|
184
|
+
provider: provider,
|
|
185
|
+
type: 'issue',
|
|
186
|
+
id: issue.iid,
|
|
187
|
+
nodeId: undefined,
|
|
188
|
+
createdDate: new Date(issue.createdAt),
|
|
189
|
+
updatedDate: new Date(issue.updatedAt),
|
|
190
|
+
title: issue.title,
|
|
191
|
+
closed: issue.state === 'closed',
|
|
192
|
+
closedDate: issue.closedAt == null ? undefined : new Date(issue.closedAt),
|
|
193
|
+
url: issue.webUrl,
|
|
194
|
+
state: issue.state === 'locked' ? 'closed' : issue.state,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (rsp?.data?.project?.mergeRequest != null) {
|
|
198
|
+
const mergeRequest = rsp.data.project.mergeRequest;
|
|
199
|
+
return {
|
|
200
|
+
provider: provider,
|
|
201
|
+
type: 'pullrequest',
|
|
202
|
+
id: mergeRequest.iid,
|
|
203
|
+
nodeId: undefined,
|
|
204
|
+
createdDate: new Date(mergeRequest.createdAt),
|
|
205
|
+
updatedDate: new Date(mergeRequest.updatedAt),
|
|
206
|
+
title: mergeRequest.title,
|
|
207
|
+
closed: mergeRequest.state === 'closed',
|
|
208
|
+
// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL
|
|
209
|
+
closedDate: mergeRequest.state === 'closed' ? new Date(mergeRequest.updatedAt) : undefined,
|
|
210
|
+
url: mergeRequest.webUrl,
|
|
211
|
+
state: mergeRequest.state === 'locked' ? 'closed' : mergeRequest.state,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
catch (ex) {
|
|
217
|
+
if (ex instanceof RequestNotFoundError)
|
|
218
|
+
return undefined;
|
|
219
|
+
throw this.handleException(ex, provider, scope);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async getPullRequestForBranch(provider, token, owner, repo, branch, options, cancellation) {
|
|
223
|
+
const scope = getScopedLogger();
|
|
224
|
+
try {
|
|
225
|
+
const fragment = `
|
|
226
|
+
nodes {
|
|
227
|
+
iid
|
|
228
|
+
author {
|
|
229
|
+
id
|
|
230
|
+
name
|
|
231
|
+
avatarUrl
|
|
232
|
+
webUrl
|
|
233
|
+
}
|
|
234
|
+
title
|
|
235
|
+
description
|
|
236
|
+
state
|
|
237
|
+
createdAt
|
|
238
|
+
updatedAt
|
|
239
|
+
mergedAt
|
|
240
|
+
webUrl
|
|
241
|
+
}`;
|
|
242
|
+
const query = `query getMergeRequestForBranch(
|
|
243
|
+
$fullPath: ID!
|
|
244
|
+
$branches: [String!]
|
|
245
|
+
) {
|
|
246
|
+
project(fullPath: $fullPath) {
|
|
247
|
+
${options?.include == null
|
|
248
|
+
? `mergeRequests(sourceBranches: $branches sort: UPDATED_DESC first: 1) {
|
|
249
|
+
${fragment}
|
|
250
|
+
}`
|
|
251
|
+
: ''}
|
|
252
|
+
${options?.include?.includes('opened')
|
|
253
|
+
? `opened: mergeRequests(sourceBranches: $branches state: opened sort: UPDATED_DESC first: 1) {
|
|
254
|
+
${fragment}
|
|
255
|
+
}`
|
|
256
|
+
: ''}
|
|
257
|
+
${options?.include?.includes('merged')
|
|
258
|
+
? `merged: mergeRequests(sourceBranches: $branches state: merged sort: UPDATED_DESC first: 1) {
|
|
259
|
+
${fragment}
|
|
260
|
+
}`
|
|
261
|
+
: ''}
|
|
262
|
+
${options?.include?.includes('closed')
|
|
263
|
+
? `closed: mergeRequests(sourceBranches: $branches state: closed sort: UPDATED_DESC first: 1) {
|
|
264
|
+
${fragment}
|
|
265
|
+
}`
|
|
266
|
+
: ''}
|
|
267
|
+
}
|
|
268
|
+
}`;
|
|
269
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, {
|
|
270
|
+
fullPath: `${owner}/${repo}`,
|
|
271
|
+
branches: [branch],
|
|
272
|
+
state: options?.include,
|
|
273
|
+
}, cancellation, scope);
|
|
274
|
+
let pr;
|
|
275
|
+
if (options?.include == null) {
|
|
276
|
+
pr = rsp?.data?.project?.mergeRequests?.nodes?.[0];
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
for (const state of options.include) {
|
|
280
|
+
let mr;
|
|
281
|
+
if (state === 'opened') {
|
|
282
|
+
mr = rsp?.data?.project?.opened?.nodes?.[0];
|
|
283
|
+
}
|
|
284
|
+
else if (state === 'merged') {
|
|
285
|
+
mr = rsp?.data?.project?.merged?.nodes?.[0];
|
|
286
|
+
}
|
|
287
|
+
else if (state === 'closed') {
|
|
288
|
+
mr = rsp?.data?.project?.closed?.nodes?.[0];
|
|
289
|
+
}
|
|
290
|
+
if (mr != null && (pr == null || new Date(mr.updatedAt) > new Date(pr.updatedAt))) {
|
|
291
|
+
pr = mr;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (pr == null)
|
|
296
|
+
return undefined;
|
|
297
|
+
return new PullRequest(provider, {
|
|
298
|
+
id: buildGitLabUserId(pr.author?.id) ?? '',
|
|
299
|
+
name: pr.author?.name ?? 'Unknown',
|
|
300
|
+
avatarUrl: pr.author?.avatarUrl ?? '',
|
|
301
|
+
url: pr.author?.webUrl ?? '',
|
|
302
|
+
},
|
|
303
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
|
|
304
|
+
String(pr.iid), undefined, pr.title, pr.webUrl, { owner: owner, repo: repo }, fromGitLabMergeRequestState(pr.state), new Date(pr.createdAt), new Date(pr.updatedAt),
|
|
305
|
+
// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL
|
|
306
|
+
pr.state !== 'closed' ? undefined : new Date(pr.updatedAt), pr.mergedAt == null ? undefined : new Date(pr.mergedAt));
|
|
307
|
+
}
|
|
308
|
+
catch (ex) {
|
|
309
|
+
if (ex instanceof RequestNotFoundError)
|
|
310
|
+
return undefined;
|
|
311
|
+
throw this.handleException(ex, provider, scope);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async getPullRequestForCommit(provider, token, owner, repo, rev, options, cancellation) {
|
|
315
|
+
const scope = getScopedLogger();
|
|
316
|
+
const projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);
|
|
317
|
+
if (!projectId)
|
|
318
|
+
return undefined;
|
|
319
|
+
try {
|
|
320
|
+
const mrs = await this.request(provider, token, options?.baseUrl, `v4/projects/${projectId}/repository/commits/${rev}/merge_requests`, {
|
|
321
|
+
method: 'GET',
|
|
322
|
+
// ...options,
|
|
323
|
+
}, cancellation, scope);
|
|
324
|
+
if (mrs == null || mrs.length === 0)
|
|
325
|
+
return undefined;
|
|
326
|
+
if (mrs.length > 1) {
|
|
327
|
+
mrs.sort((a, b) => (a.state === 'opened' ? -1 : 1) - (b.state === 'opened' ? -1 : 1) ||
|
|
328
|
+
new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime());
|
|
329
|
+
}
|
|
330
|
+
return fromGitLabMergeRequestREST(mrs[0], provider, { owner: owner, repo: repo });
|
|
331
|
+
}
|
|
332
|
+
catch (ex) {
|
|
333
|
+
if (ex instanceof RequestNotFoundError)
|
|
334
|
+
return undefined;
|
|
335
|
+
throw this.handleException(ex, provider, scope);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async getPullRequest(provider, token, owner, repo, id, options, cancellation) {
|
|
339
|
+
const scope = getScopedLogger();
|
|
340
|
+
try {
|
|
341
|
+
const query = `query getMergeRequest(
|
|
342
|
+
$fullPath: ID!
|
|
343
|
+
$iid: String!
|
|
344
|
+
) {
|
|
345
|
+
project(fullPath: $fullPath) {
|
|
346
|
+
mergeRequest(iid: $iid) {
|
|
347
|
+
id,
|
|
348
|
+
iid
|
|
349
|
+
state,
|
|
350
|
+
author {
|
|
351
|
+
id
|
|
352
|
+
name
|
|
353
|
+
avatarUrl
|
|
354
|
+
webUrl
|
|
355
|
+
}
|
|
356
|
+
diffRefs {
|
|
357
|
+
baseSha
|
|
358
|
+
headSha
|
|
359
|
+
}
|
|
360
|
+
title
|
|
361
|
+
description
|
|
362
|
+
webUrl
|
|
363
|
+
createdAt
|
|
364
|
+
updatedAt
|
|
365
|
+
mergedAt
|
|
366
|
+
targetBranch
|
|
367
|
+
sourceBranch
|
|
368
|
+
project {
|
|
369
|
+
id
|
|
370
|
+
fullPath
|
|
371
|
+
webUrl
|
|
372
|
+
}
|
|
373
|
+
sourceProject {
|
|
374
|
+
id
|
|
375
|
+
fullPath
|
|
376
|
+
webUrl
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}`;
|
|
381
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, {
|
|
382
|
+
fullPath: `${owner}/${repo}`,
|
|
383
|
+
iid: String(id),
|
|
384
|
+
}, cancellation, scope);
|
|
385
|
+
if (rsp?.data?.project?.mergeRequest == null)
|
|
386
|
+
return undefined;
|
|
387
|
+
const pr = rsp.data.project.mergeRequest;
|
|
388
|
+
return fromGitLabMergeRequest(pr, provider);
|
|
389
|
+
}
|
|
390
|
+
catch (ex) {
|
|
391
|
+
if (ex instanceof RequestNotFoundError)
|
|
392
|
+
return undefined;
|
|
393
|
+
throw this.handleException(ex, provider, scope);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async getRepositoryMetadata(provider, token, owner, repo, options, cancellation) {
|
|
397
|
+
const scope = getScopedLogger();
|
|
398
|
+
const projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);
|
|
399
|
+
if (!projectId)
|
|
400
|
+
return undefined;
|
|
401
|
+
try {
|
|
402
|
+
const proj = await this.request(provider, token, options?.baseUrl, `v4/projects/${projectId}`, {
|
|
403
|
+
method: 'GET',
|
|
404
|
+
// ...options,
|
|
405
|
+
}, cancellation, scope);
|
|
406
|
+
if (proj == null)
|
|
407
|
+
return undefined;
|
|
408
|
+
return {
|
|
409
|
+
provider: provider,
|
|
410
|
+
owner: proj.namespace.full_path,
|
|
411
|
+
name: proj.path,
|
|
412
|
+
isFork: proj.forked_from_project != null,
|
|
413
|
+
parent: proj.forked_from_project != null
|
|
414
|
+
? {
|
|
415
|
+
owner: proj.forked_from_project.namespace.full_path,
|
|
416
|
+
name: proj.forked_from_project.path,
|
|
417
|
+
}
|
|
418
|
+
: undefined,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
catch (ex) {
|
|
422
|
+
if (ex instanceof RequestNotFoundError)
|
|
423
|
+
return undefined;
|
|
424
|
+
throw this.handleException(ex, provider, scope);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async searchPullRequests(provider, token, options, cancellation) {
|
|
428
|
+
const scope = getScopedLogger();
|
|
429
|
+
const search = options?.search;
|
|
430
|
+
if (!search) {
|
|
431
|
+
return [];
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
const perPageLimit = 20; // with bigger amount we exceed the max GraphQL complexity in the next query
|
|
435
|
+
const restPRs = await this.request(provider, token, options?.baseUrl, `v4/search/?scope=merge_requests&search=${search}&per_page=${perPageLimit}`, {
|
|
436
|
+
method: 'GET',
|
|
437
|
+
}, cancellation, scope);
|
|
438
|
+
if (restPRs.length === 0) {
|
|
439
|
+
return [];
|
|
440
|
+
}
|
|
441
|
+
const queryArgs = restPRs.map((_, i) => `$id_${i}: MergeRequestID!`).join('\n');
|
|
442
|
+
const queryFields = restPRs
|
|
443
|
+
.map((_, i) => `mergeRequest_${i}: mergeRequest(id: $id_${i}) { ...mergeRequestFields }`)
|
|
444
|
+
.join('\n');
|
|
445
|
+
// Set of fields includes only additional fields that are not included in GitLabMergeRequestREST.
|
|
446
|
+
// It's limited as much as possible to reduce complexity of the query.
|
|
447
|
+
const queryMrFields = `fragment mergeRequestFields on MergeRequest {
|
|
448
|
+
diffRefs {
|
|
449
|
+
baseSha
|
|
450
|
+
headSha
|
|
451
|
+
}
|
|
452
|
+
project {
|
|
453
|
+
id
|
|
454
|
+
fullPath
|
|
455
|
+
webUrl
|
|
456
|
+
}
|
|
457
|
+
sourceProject {
|
|
458
|
+
id
|
|
459
|
+
fullPath
|
|
460
|
+
webUrl
|
|
461
|
+
}
|
|
462
|
+
}`;
|
|
463
|
+
const query = `query getMergeRequests (${queryArgs}) {${queryFields}} ${queryMrFields}`;
|
|
464
|
+
const params = restPRs.reduce((ids, gitlabRestPr, i) => {
|
|
465
|
+
ids[`id_${i}`] = `${gitlabMergeRequestIdPrefix}${gitlabRestPr.id}`;
|
|
466
|
+
return ids;
|
|
467
|
+
}, {});
|
|
468
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, params, cancellation, scope);
|
|
469
|
+
if (rsp?.data != null) {
|
|
470
|
+
const resultPRs = restPRs.reduce((accum, restPR, i) => {
|
|
471
|
+
const graphQlPR = rsp.data[`mergeRequest_${i}`];
|
|
472
|
+
if (graphQlPR == null) {
|
|
473
|
+
return accum;
|
|
474
|
+
}
|
|
475
|
+
const fullPr = {
|
|
476
|
+
...graphQlPR,
|
|
477
|
+
iid: String(restPR.iid),
|
|
478
|
+
id: String(restPR.id),
|
|
479
|
+
state: restPR.state,
|
|
480
|
+
author: {
|
|
481
|
+
id: buildGitLabUserId(restPR.author?.id) ?? '',
|
|
482
|
+
name: restPR.author?.name ?? 'Unknown',
|
|
483
|
+
avatarUrl: restPR.author?.avatar_url ?? '',
|
|
484
|
+
webUrl: restPR.author?.web_url ?? '',
|
|
485
|
+
},
|
|
486
|
+
title: restPR.title,
|
|
487
|
+
description: restPR.description,
|
|
488
|
+
webUrl: restPR.web_url,
|
|
489
|
+
createdAt: restPR.created_at,
|
|
490
|
+
updatedAt: restPR.updated_at,
|
|
491
|
+
mergedAt: restPR.merged_at,
|
|
492
|
+
sourceBranch: restPR.source_branch,
|
|
493
|
+
targetBranch: restPR.target_branch,
|
|
494
|
+
};
|
|
495
|
+
accum.push(fromGitLabMergeRequest(fullPr, provider));
|
|
496
|
+
return accum;
|
|
497
|
+
}, []);
|
|
498
|
+
return resultPRs;
|
|
499
|
+
}
|
|
500
|
+
return [];
|
|
501
|
+
}
|
|
502
|
+
catch (ex) {
|
|
503
|
+
if (ex instanceof RequestNotFoundError)
|
|
504
|
+
return [];
|
|
505
|
+
throw this.handleException(ex, provider, scope);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
async findUser(provider, token, search, options, cancellation) {
|
|
509
|
+
const scope = getScopedLogger();
|
|
510
|
+
try {
|
|
511
|
+
const query = `query findUser(
|
|
512
|
+
$search: String!
|
|
513
|
+
) {
|
|
514
|
+
users(search: $search) {
|
|
515
|
+
nodes {
|
|
516
|
+
id
|
|
517
|
+
name
|
|
518
|
+
username,
|
|
519
|
+
publicEmail,
|
|
520
|
+
state
|
|
521
|
+
avatarUrl
|
|
522
|
+
webUrl
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}`;
|
|
526
|
+
const rsp = await this.graphql(provider, token, options?.baseUrl, query, {
|
|
527
|
+
search: search,
|
|
528
|
+
}, cancellation, scope);
|
|
529
|
+
const matches = rsp?.data?.users?.nodes;
|
|
530
|
+
if (matches == null || matches.length === 0)
|
|
531
|
+
return [];
|
|
532
|
+
const users = [];
|
|
533
|
+
for (const user of matches) {
|
|
534
|
+
const match = /gid:\/\/gitlab\/User\/([0-9]+)\b/.exec(user.id);
|
|
535
|
+
if (match == null)
|
|
536
|
+
continue;
|
|
537
|
+
users.push({
|
|
538
|
+
id: parseInt(match[1], 10),
|
|
539
|
+
name: user.name,
|
|
540
|
+
username: user.username,
|
|
541
|
+
publicEmail: user.publicEmail || undefined,
|
|
542
|
+
state: user.state,
|
|
543
|
+
avatarUrl: user.avatarUrl,
|
|
544
|
+
webUrl: user.webUrl,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
return users;
|
|
548
|
+
}
|
|
549
|
+
catch (ex) {
|
|
550
|
+
if (ex instanceof RequestNotFoundError)
|
|
551
|
+
return [];
|
|
552
|
+
this.handleException(ex, provider, scope);
|
|
553
|
+
return [];
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
getProjectId(provider, token, group, repo, baseUrl, cancellation) {
|
|
557
|
+
const { accessToken } = token;
|
|
558
|
+
const key = `${accessToken}|${group}/${repo}`;
|
|
559
|
+
let projectId = this._projectIds.get(key);
|
|
560
|
+
if (projectId == null) {
|
|
561
|
+
projectId = this.getProjectIdCore(provider, token, group, repo, baseUrl, cancellation);
|
|
562
|
+
this._projectIds.set(key, projectId);
|
|
563
|
+
}
|
|
564
|
+
return projectId;
|
|
565
|
+
}
|
|
566
|
+
async getProjectIdCore(provider, token, group, repo, baseUrl, cancellation) {
|
|
567
|
+
const scope = getScopedLogger();
|
|
568
|
+
try {
|
|
569
|
+
const query = `query getProjectId(
|
|
570
|
+
$fullPath: ID!
|
|
571
|
+
) {
|
|
572
|
+
project(fullPath: $fullPath) {
|
|
573
|
+
id
|
|
574
|
+
}
|
|
575
|
+
}`;
|
|
576
|
+
const rsp = await this.graphql(provider, token, baseUrl, query, {
|
|
577
|
+
fullPath: `${group}/${repo}`,
|
|
578
|
+
}, cancellation, scope);
|
|
579
|
+
const gid = rsp?.data?.project?.id;
|
|
580
|
+
if (gid == null)
|
|
581
|
+
return undefined;
|
|
582
|
+
const match = /gid:\/\/gitlab\/Project\/([0-9]+)\b/.exec(gid);
|
|
583
|
+
if (match == null)
|
|
584
|
+
return undefined;
|
|
585
|
+
const projectId = match[1];
|
|
586
|
+
scope?.addExitInfo(`projectId=${projectId}`);
|
|
587
|
+
return projectId;
|
|
588
|
+
}
|
|
589
|
+
catch (ex) {
|
|
590
|
+
if (ex instanceof RequestNotFoundError)
|
|
591
|
+
return undefined;
|
|
592
|
+
this.handleException(ex, provider, scope);
|
|
593
|
+
return undefined;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async graphql(provider, token, baseUrl, query, variables, cancellation, scope) {
|
|
597
|
+
const { accessToken } = token;
|
|
598
|
+
let rsp;
|
|
599
|
+
try {
|
|
600
|
+
const sw = maybeStopWatch(`[GITLAB] POST ${baseUrl}`, { log: { onlyExit: true } });
|
|
601
|
+
try {
|
|
602
|
+
if (cancellation?.aborted)
|
|
603
|
+
throw new CancellationError();
|
|
604
|
+
rsp = await this.ctx.http.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () => this.ctx.http.fetch(`${baseUrl ?? 'https://gitlab.com/api'}/graphql`, {
|
|
605
|
+
method: 'POST',
|
|
606
|
+
headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
|
|
607
|
+
signal: cancellation,
|
|
608
|
+
body: JSON.stringify({ query: query, variables: variables }),
|
|
609
|
+
}));
|
|
610
|
+
if (rsp.ok) {
|
|
611
|
+
const data = (await rsp.json());
|
|
612
|
+
if ('errors' in data)
|
|
613
|
+
throw new ProviderFetchError('GitLab', rsp, data.errors);
|
|
614
|
+
return data;
|
|
615
|
+
}
|
|
616
|
+
throw new ProviderFetchError('GitLab', rsp);
|
|
617
|
+
}
|
|
618
|
+
finally {
|
|
619
|
+
const match = /(^[^({\n]+)/.exec(query);
|
|
620
|
+
const message = ` ${match?.[1].trim() ?? query}`;
|
|
621
|
+
sw?.stop({ message: message });
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
catch (ex) {
|
|
625
|
+
if (ex instanceof ProviderFetchError || ex.name === 'AbortError') {
|
|
626
|
+
this.handleRequestError(provider, token, ex, scope);
|
|
627
|
+
}
|
|
628
|
+
else if (Logger.isDebugging) {
|
|
629
|
+
this.ctx.hooks?.ui?.onError?.(`GitLab request failed: ${ex.message}`);
|
|
630
|
+
}
|
|
631
|
+
throw ex;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
async request(provider, token, baseUrl, route, options, cancellation, scope) {
|
|
635
|
+
const { accessToken } = token;
|
|
636
|
+
const url = `${baseUrl ?? 'https://gitlab.com/api'}/${route}`;
|
|
637
|
+
let rsp;
|
|
638
|
+
try {
|
|
639
|
+
const sw = maybeStopWatch(`[GITLAB] ${options?.method ?? 'GET'} ${url}`, { log: { onlyExit: true } });
|
|
640
|
+
try {
|
|
641
|
+
if (cancellation?.aborted)
|
|
642
|
+
throw new CancellationError();
|
|
643
|
+
rsp = await this.ctx.http.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () => this.ctx.http.fetch(url, {
|
|
644
|
+
headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
|
|
645
|
+
signal: cancellation,
|
|
646
|
+
...options,
|
|
647
|
+
}));
|
|
648
|
+
if (rsp.ok) {
|
|
649
|
+
return (await rsp.json());
|
|
650
|
+
}
|
|
651
|
+
throw new ProviderFetchError('GitLab', rsp);
|
|
652
|
+
}
|
|
653
|
+
finally {
|
|
654
|
+
sw?.stop();
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
catch (ex) {
|
|
658
|
+
if (ex instanceof ProviderFetchError || ex.name === 'AbortError') {
|
|
659
|
+
this.handleRequestError(provider, token, ex, scope);
|
|
660
|
+
}
|
|
661
|
+
else if (Logger.isDebugging) {
|
|
662
|
+
this.ctx.hooks?.ui?.onError?.(`GitLab request failed: ${ex.message}`);
|
|
663
|
+
}
|
|
664
|
+
throw ex;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
handleRequestError(provider, token, ex, scope) {
|
|
668
|
+
if (ex.name === 'AbortError' || !(ex instanceof ProviderFetchError))
|
|
669
|
+
throw new CancellationError(ex);
|
|
670
|
+
const { accessToken, ...tokenInfo } = token;
|
|
671
|
+
switch (ex.status) {
|
|
672
|
+
case 404: // Not found
|
|
673
|
+
case 410: // Gone
|
|
674
|
+
case 422: // Unprocessable Entity
|
|
675
|
+
throw new RequestNotFoundError(ex);
|
|
676
|
+
// case 429: //Too Many Requests
|
|
677
|
+
case 401: // Unauthorized
|
|
678
|
+
throw new AuthenticationError(tokenInfo, AuthenticationErrorReason.Unauthorized, ex);
|
|
679
|
+
case 403: // Forbidden
|
|
680
|
+
if (ex.message.includes('rate limit exceeded')) {
|
|
681
|
+
let resetAt;
|
|
682
|
+
const reset = ex.response?.headers?.get('x-ratelimit-reset');
|
|
683
|
+
if (reset != null) {
|
|
684
|
+
resetAt = parseInt(reset, 10);
|
|
685
|
+
if (Number.isNaN(resetAt)) {
|
|
686
|
+
resetAt = undefined;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
throw new RequestRateLimitError(ex, accessToken, resetAt);
|
|
690
|
+
}
|
|
691
|
+
throw new AuthenticationError(tokenInfo, AuthenticationErrorReason.Forbidden, ex);
|
|
692
|
+
case 500: // Internal Server Error
|
|
693
|
+
scope?.error(ex);
|
|
694
|
+
if (ex.response != null) {
|
|
695
|
+
provider?.trackRequestException();
|
|
696
|
+
this.ctx.hooks?.ui?.onRequestFailed?.(`${provider?.name ?? 'GitLab'} failed to respond and might be experiencing issues.${provider == null || provider.id === 'gitlab'
|
|
697
|
+
? ' Please visit the [GitLab status page](https://status.gitlab.com) for more information.'
|
|
698
|
+
: ''}`);
|
|
699
|
+
}
|
|
700
|
+
return;
|
|
701
|
+
case 502: // Bad Gateway
|
|
702
|
+
scope?.error(ex);
|
|
703
|
+
// GitHub seems to return this status code for timeouts
|
|
704
|
+
if (ex.message.includes('timeout')) {
|
|
705
|
+
provider?.trackRequestException();
|
|
706
|
+
this.ctx.hooks?.ui?.onRequestTimedOut?.(provider?.name ?? 'GitLab');
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
break;
|
|
710
|
+
default:
|
|
711
|
+
if (ex.status >= 400 && ex.status < 500)
|
|
712
|
+
throw new RequestClientError(ex);
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
scope?.error(ex);
|
|
716
|
+
if (Logger.isDebugging) {
|
|
717
|
+
this.ctx.hooks?.ui?.onError?.(`GitLab request failed: ${ex.response?.errors?.[0]?.message ?? ex.message}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
handleException(ex, provider, scope) {
|
|
721
|
+
scope?.error(ex);
|
|
722
|
+
// debugger;
|
|
723
|
+
if (ex instanceof AuthenticationError) {
|
|
724
|
+
void this.showAuthenticationErrorMessage(ex, provider);
|
|
725
|
+
}
|
|
726
|
+
return ex;
|
|
727
|
+
}
|
|
728
|
+
async showAuthenticationErrorMessage(ex, provider) {
|
|
729
|
+
if (ex.reason === AuthenticationErrorReason.Unauthorized || ex.reason === AuthenticationErrorReason.Forbidden) {
|
|
730
|
+
const reauthenticate = await this.ctx.hooks?.onReauthenticationRequired?.(`${ex.message}. Would you like to try reauthenticating${ex.reason === AuthenticationErrorReason.Forbidden ? ' to provide additional access' : ''}?`);
|
|
731
|
+
if (reauthenticate) {
|
|
732
|
+
await provider.reauthenticate();
|
|
733
|
+
this.resetCaches();
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
this.ctx.hooks?.ui?.onError?.(ex.message);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
__decorate([
|
|
742
|
+
trace({
|
|
743
|
+
args: (provider, token, owner, repo, rev) => ({
|
|
744
|
+
provider: provider.name,
|
|
745
|
+
token: `<token:${token.microHash}>`,
|
|
746
|
+
owner: owner,
|
|
747
|
+
repo: repo,
|
|
748
|
+
rev: rev,
|
|
749
|
+
}),
|
|
750
|
+
})
|
|
751
|
+
], GitLabApi.prototype, "getAccountForCommit", null);
|
|
752
|
+
__decorate([
|
|
753
|
+
trace({
|
|
754
|
+
args: (provider, token, _owner, _repo, email) => ({
|
|
755
|
+
provider: provider.name,
|
|
756
|
+
token: `<token:${token.microHash}>`,
|
|
757
|
+
email: email,
|
|
758
|
+
}),
|
|
759
|
+
})
|
|
760
|
+
], GitLabApi.prototype, "getAccountForEmail", null);
|
|
761
|
+
__decorate([
|
|
762
|
+
trace({
|
|
763
|
+
args: (provider, token, owner, repo) => ({
|
|
764
|
+
provider: provider.name,
|
|
765
|
+
token: `<token:${token.microHash}>`,
|
|
766
|
+
owner: owner,
|
|
767
|
+
repo: repo,
|
|
768
|
+
}),
|
|
769
|
+
})
|
|
770
|
+
], GitLabApi.prototype, "getDefaultBranch", null);
|
|
771
|
+
__decorate([
|
|
772
|
+
trace({
|
|
773
|
+
args: (provider, token, owner, repo, number) => ({
|
|
774
|
+
provider: provider.name,
|
|
775
|
+
token: `<token:${token.microHash}>`,
|
|
776
|
+
owner: owner,
|
|
777
|
+
repo: repo,
|
|
778
|
+
number: number,
|
|
779
|
+
}),
|
|
780
|
+
})
|
|
781
|
+
], GitLabApi.prototype, "getIssueOrPullRequest", null);
|
|
782
|
+
__decorate([
|
|
783
|
+
trace({
|
|
784
|
+
args: (provider, token, owner, repo, branch) => ({
|
|
785
|
+
provider: provider.name,
|
|
786
|
+
token: `<token:${token.microHash}>`,
|
|
787
|
+
owner: owner,
|
|
788
|
+
repo: repo,
|
|
789
|
+
branch: branch,
|
|
790
|
+
}),
|
|
791
|
+
})
|
|
792
|
+
], GitLabApi.prototype, "getPullRequestForBranch", null);
|
|
793
|
+
__decorate([
|
|
794
|
+
trace({
|
|
795
|
+
args: (provider, token, owner, repo, rev) => ({
|
|
796
|
+
provider: provider.name,
|
|
797
|
+
token: `<token:${token.microHash}>`,
|
|
798
|
+
owner: owner,
|
|
799
|
+
repo: repo,
|
|
800
|
+
rev: rev,
|
|
801
|
+
}),
|
|
802
|
+
})
|
|
803
|
+
], GitLabApi.prototype, "getPullRequestForCommit", null);
|
|
804
|
+
__decorate([
|
|
805
|
+
trace({
|
|
806
|
+
args: (provider, token, owner, repo, id) => ({
|
|
807
|
+
provider: provider.name,
|
|
808
|
+
token: `<token:${token.microHash}>`,
|
|
809
|
+
owner: owner,
|
|
810
|
+
repo: repo,
|
|
811
|
+
id: id,
|
|
812
|
+
}),
|
|
813
|
+
})
|
|
814
|
+
], GitLabApi.prototype, "getPullRequest", null);
|
|
815
|
+
__decorate([
|
|
816
|
+
trace({
|
|
817
|
+
args: (provider, token, owner, repo) => ({
|
|
818
|
+
provider: provider.name,
|
|
819
|
+
token: `<token:${token.microHash}>`,
|
|
820
|
+
owner: owner,
|
|
821
|
+
repo: repo,
|
|
822
|
+
}),
|
|
823
|
+
})
|
|
824
|
+
], GitLabApi.prototype, "getRepositoryMetadata", null);
|
|
825
|
+
__decorate([
|
|
826
|
+
trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })
|
|
827
|
+
], GitLabApi.prototype, "searchPullRequests", null);
|
|
828
|
+
//# sourceMappingURL=gitlab.js.map
|