consider hosted gitlab with relative path

Signed-off-by: ahmed <ahmed@planet.com>
This commit is contained in:
ahmed
2022-07-04 11:08:19 +02:00
parent 3a6f3536f3
commit 419559d0e7
6 changed files with 74 additions and 17 deletions
@@ -37,7 +37,7 @@ import {
ReadUrlResponse,
ReadUrlOptions,
} from './types';
import { trimEnd } from 'lodash';
import { trimEnd, trimStart } from 'lodash';
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
@@ -117,13 +117,19 @@ export class GitlabUrlReader implements UrlReader {
const { etag, signal } = options ?? {};
const { ref, full_name, filepath } = parseGitUrl(url);
// Considering self hosted gitlab with relative
const repo_full_name = trimStart(
full_name,
this.integration.config.relativePath ?? '',
);
// Use GitLab API to get the default branch
// encodeURIComponent is required for GitLab API
// https://docs.gitlab.com/ee/api/README.html#namespaced-path-encoding
const projectGitlabResponse = await fetch(
new URL(
`${this.integration.config.apiBaseUrl}/projects/${encodeURIComponent(
full_name,
repo_full_name,
)}`,
).toString(),
getGitLabRequestOptions(this.integration.config),
@@ -150,7 +156,7 @@ export class GitlabUrlReader implements UrlReader {
const commitsGitlabResponse = await fetch(
new URL(
`${this.integration.config.apiBaseUrl}/projects/${encodeURIComponent(
full_name,
repo_full_name,
)}/repository/commits?${commitsReqParams.toString()}`,
).toString(),
{
@@ -181,7 +187,7 @@ export class GitlabUrlReader implements UrlReader {
// https://docs.gitlab.com/ee/api/repositories.html#get-file-archive
const archiveGitLabResponse = await fetch(
`${this.integration.config.apiBaseUrl}/projects/${encodeURIComponent(
full_name,
repo_full_name,
)}/repository/archive?sha=${branch}`,
{
...getGitLabRequestOptions(this.integration.config),
@@ -28,6 +28,7 @@ describe('GitLabIntegration', () => {
token: 't',
apiBaseUrl: 'https://h.com/api/v4',
baseUrl: 'https://h.com',
relativePath: '',
},
],
},
@@ -66,6 +66,7 @@ describe('readGitLabIntegrationConfig', () => {
token: 't',
apiBaseUrl: 'https://a.com',
baseUrl: 'https://baseurl.for.me/gitlab',
relativePath: '/gitlab',
});
});
@@ -77,6 +78,7 @@ describe('readGitLabIntegrationConfig', () => {
host: 'gitlab.com',
apiBaseUrl: 'https://gitlab.com/api/v4',
baseUrl: 'https://gitlab.com',
relativePath: '',
});
});
@@ -89,6 +91,7 @@ describe('readGitLabIntegrationConfig', () => {
host: 'gitlab.com',
baseUrl: 'https://gitlab.com',
apiBaseUrl: 'https://gitlab.com/api/v4',
relativePath: '',
});
});
@@ -119,6 +122,7 @@ describe('readGitLabIntegrationConfig', () => {
host: 'a.com',
apiBaseUrl: 'https://a.com/api',
baseUrl: 'https://a.com',
relativePath: '/',
});
});
});
@@ -144,6 +148,7 @@ describe('readGitLabIntegrationConfigs', () => {
token: 't',
apiBaseUrl: 'https://a.com/api/v4',
baseUrl: 'https://a.com',
relativePath: '/',
});
});
+14 -2
View File
@@ -54,6 +54,14 @@ export type GitLabIntegrationConfig = {
* If no baseUrl is provided, it will default to `https://${host}`
*/
baseUrl: string;
/**
* The relative path for gitlab self hosted installations
* described here https://docs.gitlab.com/ee/install/relative_url.html
*
* If no baseUrl is provided, it will default to `/`
*/
relativePath?: string;
};
/**
@@ -69,7 +77,7 @@ export function readGitLabIntegrationConfig(
let apiBaseUrl = config.getOptionalString('apiBaseUrl');
const token = config.getOptionalString('token');
let baseUrl = config.getOptionalString('baseUrl');
let relativePath = '';
if (apiBaseUrl) {
apiBaseUrl = trimEnd(apiBaseUrl, '/');
} else if (host === GITLAB_HOST) {
@@ -96,7 +104,11 @@ export function readGitLabIntegrationConfig(
);
}
return { host, token, apiBaseUrl, baseUrl };
if (host !== GITLAB_HOST) {
relativePath = new URL(baseUrl).pathname;
}
return { host, token, apiBaseUrl, baseUrl, relativePath };
}
/**
@@ -39,12 +39,22 @@ describe('gitlab core', () => {
token: '0123456789',
apiBaseUrl: '<ignored>',
baseUrl: '<ignored>',
relativePath: '',
};
const configWithNoToken: GitLabIntegrationConfig = {
host: 'g.com',
apiBaseUrl: '<ignored>',
baseUrl: '<ignored>',
relativePath: '',
};
const configWithSelfHosted: GitLabIntegrationConfig = {
host: 'g.com',
token: '0123456789',
apiBaseUrl: '<ignored>',
baseUrl: '<ignored>',
relativePath: '/gitlab',
};
describe('getGitLabFileFetchUrl with .yaml extension', () => {
@@ -121,6 +131,12 @@ describe('gitlab core', () => {
result:
'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch',
},
{
config: configWithSelfHosted,
url: 'https://gitlab.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml',
result:
'https://gitlab.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch',
},
{
config: configWithNoToken,
// Works with non URI encoded link
+28 -11
View File
@@ -17,6 +17,9 @@
import { GitLabIntegrationConfig } from './config';
import fetch from 'cross-fetch';
import { InputError } from '@backstage/errors';
import { relative } from 'path';
import { trimStart } from 'lodash';
// import { config } from 'process';
/**
* Given a URL pointing to a file on a provider, returns a URL that is suitable
@@ -44,7 +47,7 @@ export async function getGitLabFileFetchUrl(
// makes sense and it might require some more work.
if (url.includes('/-/blob/')) {
const projectID = await getProjectId(url, config);
return buildProjectUrl(url, projectID).toString();
return buildProjectUrl(url, projectID, config).toString();
}
return buildRawUrl(url).toString();
}
@@ -101,20 +104,26 @@ export function buildRawUrl(target: string): URL {
// Converts
// from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath
// to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch
export function buildProjectUrl(target: string, projectID: Number): URL {
export function buildProjectUrl(
target: string,
projectID: Number,
config: GitLabIntegrationConfig,
): URL {
try {
const url = new URL(target);
const branchAndFilePath = url.pathname.split('/-/blob/')[1];
const [branch, ...filePath] = branchAndFilePath.split('/');
url.pathname = [
'/api/v4/projects',
projectID,
'repository/files',
encodeURIComponent(decodeURIComponent(filePath.join('/'))),
'raw',
].join('/');
url.pathname =
[config.relativePath] +
[
'/api/v4/projects',
projectID,
'repository/files',
encodeURIComponent(decodeURIComponent(filePath.join('/'))),
'raw',
].join('/');
url.search = `?ref=${branch}`;
return url;
@@ -137,19 +146,27 @@ export async function getProjectId(
}
try {
const repo = url.pathname.split('/-/blob/')[0];
let repo = url.pathname.split('/-/blob/')[0];
// Ignore relative path if it's not set
const relativePath = config.relativePath ?? '';
// Should replace first match only
repo = repo.replace(relativePath, '');
// Convert
// to: https://gitlab.com/api/v4/projects/groupA%2Fteams%2FsubgroupA%2FteamA%2Frepo
const repoIDLookup = new URL(
`${url.origin}/api/v4/projects/${encodeURIComponent(
`${url.origin}${relativePath}/api/v4/projects/${encodeURIComponent(
repo.replace(/^\//, ''),
)}`,
);
const response = await fetch(
repoIDLookup.toString(),
getGitLabRequestOptions(config),
);
const data = await response.json();
if (!response.ok) {