feat(integration): add Gerrit option to activate the edit mode

Signed-off-by: Andy LADJADJ <andy.ladjadj@adevinta.com>
This commit is contained in:
Andy LADJADJ
2025-01-17 16:02:45 +01:00
parent d651ce7462
commit f134cea34c
9 changed files with 107 additions and 9 deletions
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/integration': minor
---
Add Gerrit option to activate the edit mode for version >= 3.9
```
enableEditUrl: true
```
The url pattern is `^\/admin\/repos\/edit\/repo\/(.+)\/branch\/(.+)\/file\/(.+)$`
+2
View File
@@ -22,6 +22,7 @@ integrations:
gitilesBaseUrl: https://gerrit.company.com/gitiles
baseUrl: https://gerrit.company.com/gerrit
cloneUrl: https://gerrit.company.com/clone
enableEditUrl: true
username: ${GERRIT_USERNAME}
password: ${GERRIT_PASSWORD}
```
@@ -37,6 +38,7 @@ a structure with up to six elements:
address here. This is the address that you would open in a browser.
- `cloneUrl` (optional): The base URL for HTTP clones. Will default to `baseUrl` if
not set. The address used to clone a repo is the `cloneUrl` plus the repo name.
- `enableEditUrl` (optional): Activate the edit mode for Gerrit >= 3.9
- `username` (optional): The Gerrit username to use in API requests. If
neither a username nor password are supplied, anonymous access will be used.
- `password` (optional): The password or http token for the Gerrit user.
+5
View File
@@ -161,6 +161,11 @@ export interface Config {
* @visibility frontend
*/
cloneUrl?: string;
/**
* Activate the edit url feature available since Gerrit 3.9
* @visibility frontend
*/
enableEditUrl?: boolean;
/**
* The username to use for authenticated requests.
* @visibility secret
+1
View File
@@ -392,6 +392,7 @@ export type GerritIntegrationConfig = {
host: string;
baseUrl?: string;
cloneUrl?: string;
enableEditUrl?: boolean;
gitilesBaseUrl: string;
username?: string;
password?: string;
@@ -47,6 +47,7 @@ describe('GerritIntegration', () => {
it('returns the basics', () => {
const integration = new GerritIntegration({
host: 'gerrit-review.example.com',
gitilesBaseUrl: 'https://gerrit-review.example.com/gitiles',
} as any);
expect(integration.type).toBe('gerrit');
expect(integration.title).toBe('gerrit-review.example.com');
@@ -70,6 +71,7 @@ describe('GerritIntegration', () => {
it('handles line numbers', () => {
const integration = new GerritIntegration({
host: 'gerrit-review.example.com',
gitilesBaseUrl: 'https://gerrit-review.example.com/gitiles',
} as any);
expect(
@@ -85,6 +87,7 @@ describe('GerritIntegration', () => {
describe('resolves with a relative url', () => {
const integration = new GerritIntegration({
host: 'gerrit-review.example.com',
gitilesBaseUrl: 'https://gerrit-review.example.com/gitiles',
} as any);
it('works for valid urls pointing to a branch', () => {
expect(
@@ -144,8 +147,27 @@ describe('GerritIntegration', () => {
// url as is.
expect(
integration.resolveEditUrl(
'https://gerrit-review.example.com/catalog-info.yaml',
'https://gerrit-review.example.com/gitiles/backstage/backstage/+/refs/heads/master/catalog-info.yaml',
),
).toBe('https://gerrit-review.example.com/catalog-info.yaml');
).toBe(
'https://gerrit-review.example.com/gitiles/backstage/backstage/+/refs/heads/master/catalog-info.yaml',
);
});
it('resolve edit URL with editUrl', () => {
const integration = new GerritIntegration({
host: 'gerrit-review.example.com',
baseUrl: 'https://gerrit-review.example.com',
enableEditUrl: true,
gitilesBaseUrl: 'https://gerrit-review.example.com/gitiles',
} as any);
expect(
integration.resolveEditUrl(
'https://gerrit-review.example.com/gitiles/backstage/backstage/+/refs/heads/master/catalog-info.yaml',
),
).toBe(
'https://gerrit-review.example.com/admin/repos/edit/repo/backstage/backstage/branch/refs/heads/master/file/catalog-info.yaml',
);
});
});
@@ -20,7 +20,7 @@ import {
GerritIntegrationConfig,
readGerritIntegrationConfigs,
} from './config';
import { parseGitilesUrlRef } from './core';
import { buildGerritEditUrl, parseGitilesUrlRef } from './core';
/**
* A Gerrit based integration.
@@ -75,7 +75,15 @@ export class GerritIntegration implements ScmIntegration {
}
resolveEditUrl(url: string): string {
// Not applicable for gerrit.
if (this.config.enableEditUrl) {
const parsed = parseGitilesUrlRef(this.config, url);
return buildGerritEditUrl(
this.config,
parsed.project,
parsed.ref,
parsed.path,
);
}
return url;
}
}
@@ -57,6 +57,7 @@ describe('readGerritIntegrationConfig', () => {
host: 'a.com',
baseUrl: 'https://a.com/api',
cloneUrl: 'https:a.com/clone',
enableEditUrl: false,
gitilesBaseUrl: 'https://a.com/git',
username: 'u',
password: ' p ',
@@ -66,12 +67,32 @@ describe('readGerritIntegrationConfig', () => {
host: 'a.com',
baseUrl: 'https://a.com/api',
cloneUrl: 'https:a.com/clone',
enableEditUrl: false,
gitilesBaseUrl: 'https://a.com/git',
username: 'u',
password: 'p',
});
});
it('activate Edit Url', () => {
const output = readGerritIntegrationConfig(
buildConfig({
host: 'a.com',
enableEditUrl: true,
gitilesBaseUrl: 'https://a.com/gerrit/plugins/gitiles',
}),
);
expect(output).toEqual({
host: 'a.com',
baseUrl: 'https://a.com',
cloneUrl: 'https://a.com',
enableEditUrl: true,
gitilesBaseUrl: 'https://a.com/gerrit/plugins/gitiles',
username: undefined,
password: undefined,
});
});
it('can create a default value if the API base URL is missing', () => {
const output = readGerritIntegrationConfig(
buildConfig({
@@ -156,6 +177,7 @@ describe('readGerritIntegrationConfigs', () => {
host: 'b.com',
baseUrl: 'https://b.com/api',
cloneUrl: 'https://b.com/api',
enableEditUrl: undefined,
gitilesBaseUrl: 'https://b.com/gerrit/plugins/gitiles',
username: undefined,
password: undefined,
+9 -5
View File
@@ -44,6 +44,11 @@ export type GerritIntegrationConfig = {
*/
cloneUrl?: string;
/**
* Activate the edit url feature available since Gerrit 3.9
*/
enableEditUrl?: boolean;
/**
* Base url for Gitiles. This is needed for creating a valid
* user-friendly url that can be used for browsing the content of the
@@ -75,6 +80,7 @@ export function readGerritIntegrationConfig(
const host = config.getString('host');
let baseUrl = config.getOptionalString('baseUrl');
let cloneUrl = config.getOptionalString('cloneUrl');
const enableEditUrl = config.getOptionalBoolean('enableEditUrl');
let gitilesBaseUrl = config.getString('gitilesBaseUrl');
const username = config.getOptionalString('username');
const password = config.getOptionalString('password')?.trim();
@@ -101,21 +107,19 @@ export function readGerritIntegrationConfig(
} else {
baseUrl = `https://${host}`;
}
if (gitilesBaseUrl) {
gitilesBaseUrl = trimEnd(gitilesBaseUrl, '/');
} else {
gitilesBaseUrl = `https://${host}`;
}
if (cloneUrl) {
cloneUrl = trimEnd(cloneUrl, '/');
} else {
cloneUrl = baseUrl;
}
gitilesBaseUrl = trimEnd(gitilesBaseUrl, '/');
return {
host,
baseUrl,
cloneUrl,
enableEditUrl,
gitilesBaseUrl,
username,
password,
+23
View File
@@ -208,6 +208,29 @@ export function buildGerritGitilesUrl(
}/${project}/+/refs/heads/${branch}/${trimStart(filePath, '/')}`;
}
/**
* Build a Gerrit Gitiles url that targets a specific path.
*
* @param config - A Gerrit provider config.
* @param project - The name of the git project
* @param branch - The branch we will target.
* @param filePath - The absolute file path.
* @public
*/
export function buildGerritEditUrl(
config: GerritIntegrationConfig,
project: string,
branch: string,
filePath: string,
): string {
return `${
config.baseUrl
}/admin/repos/edit/repo/${project}/branch/refs/heads/${branch}/file/${trimStart(
filePath,
'/',
)}`;
}
/**
* Build a Gerrit Gitiles archive url that targets a specific branch and path
*