Skip to content

Commit 258675d

Browse files
committed
Generates create GitLab PR URLs and retrieves repoId for cross-forks
(#4142, #4143)
1 parent a266877 commit 258675d

File tree

4 files changed

+78
-15
lines changed

4 files changed

+78
-15
lines changed

src/git/remotes/gitlab.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import type {
66
MaybeEnrichedAutolink,
77
} from '../../autolinks/models/autolinks';
88
import { GlyphChars } from '../../constants';
9+
import type { Container } from '../../container';
10+
import { HostingIntegration } from '../../plus/integrations/integration';
11+
import { remoteProviderIdToIntegrationId } from '../../plus/integrations/integrationService';
912
import type { GitLabRepositoryDescriptor } from '../../plus/integrations/providers/gitlab';
1013
import type { Brand, Unbrand } from '../../system/brand';
1114
import { fromNow } from '../../system/date';
@@ -30,7 +33,14 @@ function isGitLabDotCom(domain: string): boolean {
3033
}
3134

3235
export class GitLabRemote extends RemoteProvider<GitLabRepositoryDescriptor> {
33-
constructor(domain: string, path: string, protocol?: string, name?: string, custom: boolean = false) {
36+
constructor(
37+
private readonly container: Container,
38+
domain: string,
39+
path: string,
40+
protocol?: string,
41+
name?: string,
42+
custom: boolean = false,
43+
) {
3444
super(domain, path, protocol, name, custom);
3545
}
3646

@@ -372,8 +382,51 @@ export class GitLabRemote extends RemoteProvider<GitLabRepositoryDescriptor> {
372382
return this.encodeUrl(`${this.baseUrl}/-/commit/${sha}`);
373383
}
374384

375-
protected override getUrlForComparison(base: string, compare: string, notation: '..' | '...'): string {
376-
return this.encodeUrl(`${this.baseUrl}/-/compare/${base}${notation}${compare}`);
385+
protected override getUrlForComparison(base: string, head: string, notation: '..' | '...'): string {
386+
return this.encodeUrl(`${this.baseUrl}/-/compare/${base}${notation}${head}`);
387+
}
388+
389+
override async isReadyForForCrossForkPullRequestUrls(): Promise<boolean> {
390+
const integrationId = remoteProviderIdToIntegrationId(this.id);
391+
const integration = integrationId && (await this.container.integrations.get(integrationId));
392+
return integration?.maybeConnected ?? integration?.isConnected() ?? false;
393+
}
394+
395+
protected override async getUrlForCreatePullRequest(
396+
base: { branch?: string; remote: { path: string; url: string } },
397+
head: { branch: string; remote: { path: string; url: string } },
398+
options?: { title?: string; description?: string },
399+
): Promise<string | undefined> {
400+
const query = new URLSearchParams({
401+
utf8: '✓',
402+
'merge_request[source_branch]': head.branch,
403+
'merge_request[target_branch]': base.branch ?? '',
404+
});
405+
if (base.remote.url !== head.remote.url) {
406+
const targetDesc = {
407+
owner: base.remote.path.split('/')[0],
408+
name: base.remote.path.split('/')[1],
409+
};
410+
const integrationId = remoteProviderIdToIntegrationId(this.id);
411+
const integration = integrationId && (await this.container.integrations.get(integrationId));
412+
let targetRepoId = undefined;
413+
if (integration?.isConnected && integration instanceof HostingIntegration) {
414+
targetRepoId = (await integration.getRepoInfo?.(targetDesc))?.id;
415+
}
416+
if (!targetRepoId) {
417+
return undefined;
418+
}
419+
query.set('merge_request[target_project_id]', targetRepoId);
420+
// 'merge_request["source_project_id"]': this.path, // ?? seems we don't need it
421+
}
422+
if (options?.title) {
423+
query.set('merge_request[title]', options.title);
424+
}
425+
if (options?.description) {
426+
query.set('merge_request[description]', options.description);
427+
}
428+
429+
return `${this.encodeUrl(`${this.getRepoBaseUrl(head.remote.path)}/-/merge_requests/new`)}?${query.toString()}`;
377430
}
378431

379432
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {

src/git/remotes/remoteProviders.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const builtInProviders: RemoteProviders = [
3737
{
3838
custom: false,
3939
matcher: 'gitlab.com',
40-
creator: (_container: Container, domain: string, path: string) => new GitLabRemote(domain, path),
40+
creator: (container: Container, domain: string, path: string) => new GitLabRemote(container, domain, path),
4141
},
4242
{
4343
custom: false,
@@ -52,7 +52,7 @@ const builtInProviders: RemoteProviders = [
5252
{
5353
custom: false,
5454
matcher: /\bgitlab\b/i,
55-
creator: (_container: Container, domain: string, path: string) => new GitLabRemote(domain, path),
55+
creator: (container: Container, domain: string, path: string) => new GitLabRemote(container, domain, path),
5656
},
5757
{
5858
custom: false,
@@ -77,13 +77,16 @@ const builtInProviders: RemoteProviders = [
7777
},
7878
];
7979

80-
const cloudRemotesMap: Record<
80+
const cloudProviderCreatorsMap: Record<
8181
CloudSelfHostedIntegrationId,
82-
typeof GitHubRemote | typeof GitLabRemote | typeof BitbucketServerRemote
82+
(container: Container, domain: string, path: string) => RemoteProvider
8383
> = {
84-
[SelfHostedIntegrationId.CloudGitHubEnterprise]: GitHubRemote,
85-
[SelfHostedIntegrationId.CloudGitLabSelfHosted]: GitLabRemote,
86-
[SelfHostedIntegrationId.BitbucketServer]: BitbucketServerRemote,
84+
[SelfHostedIntegrationId.CloudGitHubEnterprise]: (_container: Container, domain: string, path: string) =>
85+
new GitHubRemote(domain, path),
86+
[SelfHostedIntegrationId.CloudGitLabSelfHosted]: (container: Container, domain: string, path: string) =>
87+
new GitLabRemote(container, domain, path),
88+
[SelfHostedIntegrationId.BitbucketServer]: (_container: Container, domain: string, path: string) =>
89+
new BitbucketServerRemote(domain, path),
8790
};
8891

8992
export function loadRemoteProviders(
@@ -118,12 +121,10 @@ export function loadRemoteProviders(
118121
const integrationId = ci.integrationId;
119122
if (isCloudSelfHostedIntegrationId(integrationId) && ci.domain) {
120123
const matcher = ci.domain.toLocaleLowerCase();
121-
const providerCreator = (_container: Container, domain: string, path: string): RemoteProvider =>
122-
new cloudRemotesMap[integrationId](domain, path);
123124
const provider = {
124125
custom: false,
125126
matcher: matcher,
126-
creator: providerCreator,
127+
creator: cloudProviderCreatorsMap[integrationId],
127128
};
128129

129130
const indexOfCustomDuplication: number = providers.findIndex(p => p.matcher === matcher);
@@ -169,8 +170,8 @@ function getCustomProviderCreator(cfg: RemotesConfig) {
169170
return (_container: Container, domain: string, path: string) =>
170171
new GitHubRemote(domain, path, cfg.protocol, cfg.name, true);
171172
case 'GitLab':
172-
return (_container: Container, domain: string, path: string) =>
173-
new GitLabRemote(domain, path, cfg.protocol, cfg.name, true);
173+
return (container: Container, domain: string, path: string) =>
174+
new GitLabRemote(container, domain, path, cfg.protocol, cfg.name, true);
174175
default:
175176
return undefined;
176177
}

src/plus/integrations/providers/gitlab.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type { RepositoryDescriptor } from '../integration';
1919
import { HostingIntegration } from '../integration';
2020
import { getGitLabPullRequestIdentityFromMaybeUrl } from './gitlab/gitlab.utils';
2121
import { fromGitLabMergeRequestProvidersApi } from './gitlab/models';
22+
import type { ProviderRepository } from './models';
2223
import { ProviderPullRequestReviewState, providersMetadata, toIssueShape } from './models';
2324
import type { ProvidersApi } from './providersApi';
2425

@@ -190,6 +191,13 @@ abstract class GitLabIntegrationBase<
190191
);
191192
}
192193

194+
public override async getRepoInfo(repo: { owner: string; name: string }): Promise<ProviderRepository | undefined> {
195+
const api = await this.getProvidersApi();
196+
return api.getRepo(this.id, repo.owner, repo.name, undefined, {
197+
accessToken: this._session?.accessToken,
198+
});
199+
}
200+
193201
protected override async getProviderRepositoryMetadata(
194202
{ accessToken }: AuthenticationSession,
195203
repo: GitLabRepositoryDescriptor,

src/plus/integrations/providers/providersApi.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export class ProvidersApi {
133133
[HostingIntegrationId.GitLab]: {
134134
...providersMetadata[HostingIntegrationId.GitLab],
135135
provider: providerApis.gitlab,
136+
getRepoFn: providerApis.gitlab.getRepo.bind(providerApis.gitlab),
136137
getCurrentUserFn: providerApis.gitlab.getCurrentUser.bind(providerApis.gitlab) as GetCurrentUserFn,
137138
getPullRequestsForReposFn: providerApis.gitlab.getPullRequestsForRepos.bind(
138139
providerApis.gitlab,

0 commit comments

Comments
 (0)