Skip to content

Commit ffce252

Browse files
committed
Makes by URL or ID searched GitLab PRs checkoutable
(#3788, #3795)
1 parent 3cbe734 commit ffce252

File tree

3 files changed

+146
-11
lines changed

3 files changed

+146
-11
lines changed

src/plus/integrations/integration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ export abstract class IntegrationBase<
556556
const connected = this.maybeConnected ?? (await this.isConnected());
557557
if (!connected) return undefined;
558558

559-
const pr = this.container.cache.getPullRequest(id, resource, this, () => ({
559+
const pr = await this.container.cache.getPullRequest(id, resource, this, () => ({
560560
value: (async () => {
561561
try {
562562
const result = await this.getProviderPullRequest?.(this._session!, resource, id);

src/plus/integrations/providers/gitlab/gitlab.ts

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ import type {
3535
GitLabCommit,
3636
GitLabIssue,
3737
GitLabMergeRequest,
38+
GitLabMergeRequestFull,
3839
GitLabMergeRequestREST,
3940
GitLabMergeRequestState,
4041
GitLabProjectREST,
4142
GitLabUser,
4243
} from './models';
43-
import { fromGitLabMergeRequestREST, fromGitLabMergeRequestState } from './models';
44+
import { fromGitLabMergeRequest, fromGitLabMergeRequestREST, fromGitLabMergeRequestState } from './models';
4445

4546
// drop it as soon as we switch to @gitkraken/providers-api
4647
const gitlabUserIdPrefix = 'gid://gitlab/User/';
@@ -585,24 +586,73 @@ export class GitLabApi implements Disposable {
585586
): Promise<PullRequest | undefined> {
586587
const scope = getLogScope();
587588

588-
const projectId = await this.getProjectId(provider, token, owner, repo, options?.baseUrl, cancellation);
589-
if (!projectId) return undefined;
589+
interface QueryResult {
590+
data: {
591+
project: {
592+
mergeRequest: GitLabMergeRequestFull | null;
593+
} | null;
594+
};
595+
}
590596

591597
try {
592-
const mr = await this.request<GitLabMergeRequestREST>(
598+
const query = `query getMergeRequest(
599+
$fullPath: ID!
600+
$iid: String!
601+
) {
602+
project(fullPath: $fullPath) {
603+
mergeRequest(iid: $iid) {
604+
id,
605+
iid
606+
state,
607+
author {
608+
id
609+
name
610+
avatarUrl
611+
webUrl
612+
}
613+
diffRefs {
614+
baseSha
615+
headSha
616+
}
617+
title
618+
description
619+
webUrl
620+
createdAt
621+
updatedAt
622+
mergedAt
623+
targetBranch
624+
sourceBranch
625+
project {
626+
id
627+
fullPath
628+
webUrl
629+
}
630+
sourceProject {
631+
id
632+
fullPath
633+
webUrl
634+
}
635+
}
636+
}
637+
}`;
638+
639+
const rsp = await this.graphql<QueryResult>(
593640
provider,
594641
token,
595642
options?.baseUrl,
596-
`v4/projects/${projectId}/merge_requests/${id}`,
643+
query,
597644
{
598-
method: 'GET',
645+
fullPath: `${owner}/${repo}`,
646+
iid: String(id),
599647
},
600648
cancellation,
601649
scope,
602650
);
603-
if (mr == null) return undefined;
604651

605-
return fromGitLabMergeRequestREST(mr, provider, { owner: owner, repo: repo });
652+
if (rsp?.data?.project?.mergeRequest == null) return undefined;
653+
654+
const pr = rsp.data.project.mergeRequest;
655+
return fromGitLabMergeRequest(pr, provider);
606656
} catch (ex) {
607657
if (ex instanceof RequestNotFoundError) return undefined;
608658

src/plus/integrations/providers/gitlab/models.ts

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { HostingIntegrationId } from '../../../../constants.integrations';
2-
import type { PullRequestState } from '../../../../git/models/pullRequest';
3-
import { PullRequest } from '../../../../git/models/pullRequest';
2+
import type { PullRequestRefs, PullRequestState } from '../../../../git/models/pullRequest';
3+
import { PullRequest, PullRequestMergeableState } from '../../../../git/models/pullRequest';
44
import type { PullRequestUrlIdentity } from '../../../../git/models/pullRequest.utils';
55
import type { Provider } from '../../../../git/models/remoteProvider';
66
import type { Integration } from '../../integration';
@@ -67,6 +67,24 @@ export interface GitLabMergeRequest {
6767
webUrl: string;
6868
}
6969

70+
export interface GitLabRepositoryStub {
71+
id: string;
72+
fullPath: string;
73+
webUrl: string;
74+
}
75+
76+
export interface GitLabMergeRequestFull extends GitLabMergeRequest {
77+
id: string;
78+
targetBranch: string;
79+
sourceBranch: string;
80+
diffRefs: {
81+
baseSha: string | null;
82+
headSha: string;
83+
};
84+
project: GitLabRepositoryStub;
85+
sourceProject: GitLabRepositoryStub;
86+
}
87+
7088
export type GitLabMergeRequestState = 'opened' | 'closed' | 'locked' | 'merged';
7189

7290
export function fromGitLabMergeRequestState(state: GitLabMergeRequestState): PullRequestState {
@@ -93,6 +111,15 @@ export interface GitLabMergeRequestREST {
93111
updated_at: string;
94112
closed_at: string | null;
95113
merged_at: string | null;
114+
diff_refs: {
115+
base_sha: string;
116+
head_sha: string;
117+
start_sha: string;
118+
};
119+
source_branch: string;
120+
source_project_id: number;
121+
target_branch: string;
122+
target_project_id: number;
96123
web_url: string;
97124
}
98125

@@ -167,3 +194,61 @@ export function getGitLabPullRequestIdentityFromMaybeUrl(url: string): RequireSo
167194

168195
return { prNumber: match[2], ownerAndRepo: match[1], provider: HostingIntegrationId.GitLab };
169196
}
197+
198+
export function fromGitLabMergeRequest(pr: GitLabMergeRequestFull, provider: Provider): PullRequest {
199+
return new PullRequest(
200+
provider,
201+
{
202+
// author
203+
id: pr.author?.id ?? '',
204+
name: pr.author?.name ?? 'Unknown',
205+
avatarUrl: pr.author?.avatarUrl ?? '',
206+
url: pr.author?.webUrl ?? '',
207+
},
208+
pr.iid, // id
209+
pr.id, // nodeId
210+
pr.title,
211+
pr.webUrl || '',
212+
{
213+
// IssueRepository
214+
owner: '',
215+
repo: '',
216+
url: '',
217+
},
218+
fromGitLabMergeRequestState(pr.state), // PullRequestState
219+
new Date(pr.createdAt),
220+
new Date(pr.updatedAt),
221+
// TODO@eamodio this isn't right, but GitLab doesn't seem to provide a closedAt on merge requests in GraphQL
222+
pr.state !== 'closed' ? undefined : new Date(pr.updatedAt),
223+
pr.mergedAt == null ? undefined : new Date(pr.mergedAt),
224+
PullRequestMergeableState.Unknown,
225+
undefined, // viewerCanUpdate
226+
fromGitLabMergeRequestRefs(pr), // PullRequestRefs
227+
);
228+
}
229+
230+
function fromGitLabMergeRequestRefs(pr: GitLabMergeRequestFull): PullRequestRefs | undefined {
231+
return {
232+
base: {
233+
owner: getRepoNamespace(pr.sourceProject.fullPath),
234+
branch: pr.sourceBranch,
235+
exists: true,
236+
url: pr.sourceProject.webUrl,
237+
repo: pr.sourceProject.fullPath,
238+
sha: pr.diffRefs.baseSha || '',
239+
},
240+
head: {
241+
owner: getRepoNamespace(pr.project.fullPath),
242+
branch: pr.targetBranch,
243+
exists: true,
244+
url: pr.project.webUrl,
245+
repo: pr.project.fullPath,
246+
sha: pr.diffRefs.headSha,
247+
},
248+
isCrossRepository: pr.sourceProject.id !== pr.project.id,
249+
};
250+
}
251+
252+
function getRepoNamespace(projectFullPath: string) {
253+
return projectFullPath.split('/').slice(0, -1).join('/');
254+
}

0 commit comments

Comments
 (0)