Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 35 additions & 12 deletions server/src/repo/git/gitlab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export class GitlabApi extends Repo {
},
} as Options;

// Helper method to properly encode project path for nested groups
private encodeProjectPath(owner: string, repo: string): string {
const fullPath = `${owner}/${repo}`;
return fullPath.split('/').map(encodeURIComponent).join('%2F');
}

constructor(baseURL: string, token: string) {
super('gitlab');
const host = baseURL || 'https://gitlab.com';
Expand Down Expand Up @@ -52,11 +58,18 @@ export class GitlabApi extends Repo {
};

const parsed = gitUrlParse(gitrepo);
const repo = parsed.name;
const owner = parsed.owner;

// Extract full project path to support nested groups/subgroups
// For gitlab.com/owner/subgroup/repo.git -> owner/subgroup/repo
const projectPath = parsed.pathname
.replace(/^\//, '') // Remove leading slash
.replace(/\.git$/, ''); // Remove .git suffix

// URL-encode each path segment separately, then join with %2F
const encodedPath = projectPath.split('/').map(encodeURIComponent).join('%2F');

const res: any = await this.gitlab
.get(`projects/${owner}%2F${repo}`)
.get(`projects/${encodedPath}`)
.catch((error: any) => {
console.log(error);
return ret;
Expand All @@ -72,15 +85,21 @@ export class GitlabApi extends Repo {
res.permissions.admin = true;
res.permissions.push = true;

// Extract owner path (everything except the last segment)
// For owner/subgroup/repo -> owner/subgroup
const pathSegments = res.path_with_namespace.split('/');
const repoName = pathSegments.pop(); // Remove and get last segment
const ownerPath = pathSegments.join('/'); // Join remaining segments

ret = {
status: 200,
statusText: 'found',
data: {
id: res.id,
node_id: res.path_with_namespace,
name: res.path,
name: repoName || res.path,
description: res.description,
owner: res.namespace.path,
owner: ownerPath || res.namespace.path,
private: res.private,
ssh_url: res.ssh_url_to_repo,
language: res.language,
Expand Down Expand Up @@ -114,8 +133,9 @@ export class GitlabApi extends Repo {
},
};

const encodedPath = this.encodeProjectPath(owner, repo);
const webhooksList: any = await this.gitlab
.get(`projects/${owner}%2F${repo}/hooks`)
.get(`projects/${encodedPath}/hooks`)
.catch((error: any) => {
console.log(error);
return ret;
Expand All @@ -142,7 +162,7 @@ export class GitlabApi extends Repo {
// create the webhook since it does not exist
try {
const res: any = await this.gitlab.post(
`projects/${owner}%2F${repo}/hooks`,
`projects/${encodedPath}/hooks`,
JSON.stringify({
url: url,
token: secret,
Expand Down Expand Up @@ -193,8 +213,9 @@ export class GitlabApi extends Repo {
};
try {
// https://docs.gitlab.com/ee/api/deploy_keys.html#add-deploy-key
const encodedPath = this.encodeProjectPath(owner, repo);
const res: any = await this.gitlab.post(
`projects/${owner}%2F${repo}/deploy_keys`,
`projects/${encodedPath}/deploy_keys`,
JSON.stringify({
title: title,
key: keyPair.pubKey,
Expand Down Expand Up @@ -315,10 +336,11 @@ export class GitlabApi extends Repo {
const ret: string[] = [];

const { repo, owner } = this.parseRepo(gitrepo);
const encodedPath = this.encodeProjectPath(owner, repo);

try {
const branches: any = await this.gitlab
.get(`projects/${owner}%2F${repo}/repository/branches`)
.get(`projects/${encodedPath}/repository/branches`)
.catch((error: any) => {
console.log(error);
return ret;
Expand All @@ -338,10 +360,11 @@ export class GitlabApi extends Repo {
const ret: string[] = [];

const { repo, owner } = this.parseRepo(gitrepo);
const encodedPath = this.encodeProjectPath(owner, repo);

try {
const branches: any = await this.gitlab
.get(`projects/${owner}%2F${repo}/repository/branches`)
.get(`projects/${encodedPath}/repository/branches`)
.catch((error: any) => {
console.log(error);
return ret;
Expand All @@ -356,7 +379,7 @@ export class GitlabApi extends Repo {

try {
const tags: any = await this.gitlab
.get(`projects/${owner}%2F${repo}/repository/tags`)
.get(`projects/${encodedPath}/repository/tags`)
.catch((error: any) => {
console.log(error);
return ret;
Expand All @@ -371,7 +394,7 @@ export class GitlabApi extends Repo {

try {
const commits: any = await this.gitlab
.get(`projects/${owner}%2F${repo}/repository/commits`)
.get(`projects/${encodedPath}/repository/commits`)
.catch((error: any) => {
console.log(error);
return ret;
Expand Down