Add resolveEditUrl to integrations
Signed-off-by: Oliver Sand <oliver.sand@sda-se.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Add `resolveEditUrl` to integrations to resolve a URL that can be used to edit
|
||||
a file in the web interfaces of an SCM.
|
||||
@@ -88,4 +88,10 @@ describe('ScmIntegrations', () => {
|
||||
}),
|
||||
).toBe('https://absolute.com/path');
|
||||
});
|
||||
|
||||
it('can resolveEditUrl using fallback', () => {
|
||||
expect(i.resolveEditUrl('http://example.com/x/a.yaml')).toBe(
|
||||
'http://example.com/x/a.yaml',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,4 +91,13 @@ export class ScmIntegrations implements ScmIntegrationRegistry {
|
||||
|
||||
return integration.resolveUrl(options);
|
||||
}
|
||||
|
||||
resolveEditUrl(url: string): string {
|
||||
const integration = this.byUrl(url);
|
||||
if (!integration) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return integration.resolveEditUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,4 +99,18 @@ describe('AzureIntegration', () => {
|
||||
).toBe('https://dev.azure.com/organization/project/test');
|
||||
});
|
||||
});
|
||||
|
||||
it('resolve edit URL', () => {
|
||||
const integration = new AzureIntegration({ host: 'h.com' } as any);
|
||||
|
||||
// TODO: The Azure integration doesn't support resolving an edit URL yet,
|
||||
// instead we keep the input URL.
|
||||
expect(
|
||||
integration.resolveEditUrl(
|
||||
'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml',
|
||||
),
|
||||
).toBe(
|
||||
'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { basicIntegrations } from '../helpers';
|
||||
import { basicIntegrations, isValidUrl } from '../helpers';
|
||||
import { ScmIntegration, ScmIntegrationsFactory } from '../types';
|
||||
import { AzureIntegrationConfig, readAzureIntegrationConfigs } from './config';
|
||||
|
||||
@@ -53,12 +53,8 @@ export class AzureIntegration implements ScmIntegration {
|
||||
const { url, base } = options;
|
||||
|
||||
// If we can parse the url, it is absolute - then return it verbatim
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new URL(url);
|
||||
if (isValidUrl(url)) {
|
||||
return url;
|
||||
} catch {
|
||||
// Ignore intentionally - looks like a relative path
|
||||
}
|
||||
|
||||
const parsed = parseGitUrl(base);
|
||||
@@ -78,4 +74,10 @@ export class AzureIntegration implements ScmIntegration {
|
||||
|
||||
return newUrl.toString();
|
||||
}
|
||||
|
||||
resolveEditUrl(url: string): string {
|
||||
// TODO: Implement edit URL for Azure, fallback to view url as I don't know
|
||||
// how azure works.
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,16 @@ describe('BitbucketIntegration', () => {
|
||||
expect(integration.type).toBe('bitbucket');
|
||||
expect(integration.title).toBe('h.com');
|
||||
});
|
||||
|
||||
it('resolve edit URL', () => {
|
||||
const integration = new BitbucketIntegration({ host: 'h.com' } as any);
|
||||
|
||||
expect(
|
||||
integration.resolveEditUrl(
|
||||
'https://bitbucket.org/my-owner/my-project/src/master/README.md',
|
||||
),
|
||||
).toBe(
|
||||
'https://bitbucket.org/my-owner/my-project/src/master/README.md?mode=edit&spa=0&at=master',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { basicIntegrations, defaultScmResolveUrl } from '../helpers';
|
||||
import { ScmIntegration, ScmIntegrationsFactory } from '../types';
|
||||
import {
|
||||
@@ -51,4 +52,16 @@ export class BitbucketIntegration implements ScmIntegration {
|
||||
resolveUrl(options: { url: string; base: string }): string {
|
||||
return defaultScmResolveUrl(options);
|
||||
}
|
||||
|
||||
resolveEditUrl(url: string): string {
|
||||
const urlData = parseGitUrl(url);
|
||||
const editUrl = new URL(url);
|
||||
|
||||
editUrl.searchParams.set('mode', 'edit');
|
||||
// TODO: Not sure what spa=0 does, at least bitbucket.org doesn't support it
|
||||
// but this is taken over from the initial implementation.
|
||||
editUrl.searchParams.set('spa', '0');
|
||||
editUrl.searchParams.set('at', urlData.ref);
|
||||
return editUrl.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,4 +49,34 @@ describe('GitHubIntegration', () => {
|
||||
expect(integration.title).toBe('h.com');
|
||||
expect(integration.config.host).toBe('h.com');
|
||||
});
|
||||
|
||||
it('resolveUrl', () => {
|
||||
const integration = new GitHubIntegration({ host: 'h.com' });
|
||||
|
||||
expect(
|
||||
integration.resolveUrl({
|
||||
url: '../a.yaml',
|
||||
base:
|
||||
'https://github.com/backstage/backstage/blob/master/test/README.md',
|
||||
}),
|
||||
).toBe('https://github.com/backstage/backstage/tree/master/a.yaml');
|
||||
|
||||
expect(
|
||||
integration.resolveUrl({
|
||||
url: './',
|
||||
base:
|
||||
'https://github.com/backstage/backstage/blob/master/test/README.md',
|
||||
}),
|
||||
).toBe('https://github.com/backstage/backstage/tree/master/test/');
|
||||
});
|
||||
|
||||
it('resolve edit URL', () => {
|
||||
const integration = new GitHubIntegration({ host: 'h.com' });
|
||||
|
||||
expect(
|
||||
integration.resolveEditUrl(
|
||||
'https://github.com/backstage/backstage/blob/master/README.md',
|
||||
),
|
||||
).toBe('https://github.com/backstage/backstage/edit/master/README.md');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,6 +47,13 @@ export class GitHubIntegration implements ScmIntegration {
|
||||
}
|
||||
|
||||
resolveUrl(options: { url: string; base: string }): string {
|
||||
return defaultScmResolveUrl(options);
|
||||
// GitHub uses blob URLs for files and tree urls for directory listings. But
|
||||
// there is a redirect from tree to blob for files, so we can always return
|
||||
// tree urls here.
|
||||
return defaultScmResolveUrl(options).replace('/blob/', '/tree/');
|
||||
}
|
||||
|
||||
resolveEditUrl(url: string): string {
|
||||
return url.replace('/blob/', '/edit/');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,4 +43,14 @@ describe('GitLabIntegration', () => {
|
||||
expect(integration.type).toBe('gitlab');
|
||||
expect(integration.title).toBe('h.com');
|
||||
});
|
||||
|
||||
it('resolve edit URL', () => {
|
||||
const integration = new GitLabIntegration({ host: 'h.com' } as any);
|
||||
|
||||
expect(
|
||||
integration.resolveEditUrl(
|
||||
'https://gitlab.com/my-org/my-project/-/blob/develop/README.md',
|
||||
),
|
||||
).toBe('https://gitlab.com/my-org/my-project/-/edit/develop/README.md');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,4 +49,8 @@ export class GitLabIntegration implements ScmIntegration {
|
||||
resolveUrl(options: { url: string; base: string }): string {
|
||||
return defaultScmResolveUrl(options);
|
||||
}
|
||||
|
||||
resolveEditUrl(url: string): string {
|
||||
return url.replace('/blob/', '/edit/');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,19 @@ export interface ScmIntegration {
|
||||
* @param options.base The base URL onto which this resolution happens
|
||||
*/
|
||||
resolveUrl(options: { url: string; base: string }): string;
|
||||
|
||||
/**
|
||||
* Resolves the edit URL for a file within the SCM system.
|
||||
*
|
||||
* Most SCM systems have a web interface that allows viewing and editing files
|
||||
* in the repository. The returned URL directly jumps into the edit mode for
|
||||
* the file.
|
||||
* If this is not possible, the integration can fall back to a URL to view
|
||||
* the file in the web interface.
|
||||
*
|
||||
* @param url The absolute URL to the file that should be edited.
|
||||
*/
|
||||
resolveEditUrl(url: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,6 +116,19 @@ export interface ScmIntegrationRegistry
|
||||
* @param options.base The base URL onto which this resolution happens
|
||||
*/
|
||||
resolveUrl(options: { url: string; base: string }): string;
|
||||
|
||||
/**
|
||||
* Resolves the edit URL for a file within the SCM system.
|
||||
*
|
||||
* Most SCM systems have a web interface that allows viewing and editing files
|
||||
* in the repository. The returned URL directly jumps into the edit mode for
|
||||
* the file.
|
||||
* If this is not possible, the integration can fall back to a URL to view
|
||||
* the file in the web interface.
|
||||
*
|
||||
* @param url The absolute URL to the file that should be edited.
|
||||
*/
|
||||
resolveEditUrl(url: string): string;
|
||||
}
|
||||
|
||||
export type ScmIntegrationsFactory<T extends ScmIntegration> = (options: {
|
||||
|
||||
Reference in New Issue
Block a user