integration: add the resolveUrl method

This commit is contained in:
Fredrik Adelöw
2021-02-02 11:03:02 +01:00
parent 2132233fc8
commit 3149bfe639
12 changed files with 222 additions and 15 deletions
@@ -73,4 +73,19 @@ describe('ScmIntegrations', () => {
expect(i.byHost('github.local')).toBe(github);
expect(i.byHost('gitlab.local')).toBe(gitlab);
});
it('can resolveUrl using fallback', () => {
expect(
i.resolveUrl({
url: '../b.yaml',
base: 'https://no-matching-integration.com/x/a.yaml',
}),
).toBe('https://no-matching-integration.com/b.yaml');
expect(
i.resolveUrl({
url: 'https://absolute.com/path',
base: 'https://no-matching-integration.com/x/a.yaml',
}),
).toBe('https://absolute.com/path');
});
});
@@ -81,4 +81,13 @@ export class ScmIntegrations implements ScmIntegrationRegistry {
.map(i => i.byHost(host))
.find(Boolean);
}
resolveUrl(options: { url: string; base: string }): string {
const resolve = this.byUrl(options.base)?.resolveUrl;
if (!resolve) {
return new URL(options.url, options.base).toString();
}
return resolve(options);
}
}
@@ -41,4 +41,52 @@ describe('AzureIntegration', () => {
expect(integration.type).toBe('azure');
expect(integration.title).toBe('h.com');
});
describe('resolveUrl', () => {
it('works for valid urls', () => {
const integration = new AzureIntegration({
host: 'dev.azure.com',
} as any);
expect(
integration.resolveUrl({
url: '../a.yaml',
base:
'https://dev.azure.com/organization/project/_git/repository?path=%2Ffolder%2Fcatalog-info.yaml',
}),
).toBe(
'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml',
);
expect(
integration.resolveUrl({
url: './a.yaml',
base: 'https://dev.azure.com/organization/project/_git/repository',
}),
).toBe(
'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml',
);
expect(
integration.resolveUrl({
url: 'https://absolute.com/path',
base:
'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml',
}),
).toBe('https://absolute.com/path');
});
it('falls back to regular URL resolution if not in a repo', () => {
const integration = new AzureIntegration({
host: 'dev.azure.com',
} as any);
expect(
integration.resolveUrl({
url: './test',
base: 'https://dev.azure.com/organization/project/_git',
}),
).toBe('https://dev.azure.com/organization/project/test');
});
});
});
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import parseGitUrl from 'git-url-parse';
import { basicIntegrations } from '../helpers';
import { ScmIntegration, ScmIntegrationsFactory } from '../types';
import { AzureIntegrationConfig, readAzureIntegrationConfigs } from './config';
@@ -42,4 +43,39 @@ export class AzureIntegration implements ScmIntegration {
get config(): AzureIntegrationConfig {
return this.integrationConfig;
}
/*
* Azure repo URLs on the form with a `path` query param are treated specially.
*
* Example base URL: https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml
*/
resolveUrl(options: { url: string; base: string }): string {
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);
return url;
} catch {
// Ignore intentionally - looks like a relative path
}
const parsed = parseGitUrl(base);
const { organization, owner, name, filepath } = parsed;
// If not an actual file path within a repo, treat the URL as raw
if (!organization || !owner || !name) {
return new URL(url, base).toString();
}
const path = filepath?.replace(/^\//, '') || '';
const mockBaseUrl = new URL(`https://a.com/${path}`);
const updatedPath = new URL(url, mockBaseUrl).pathname;
const newUrl = new URL(base);
newUrl.searchParams.set('path', updatedPath);
return newUrl.toString();
}
}
+21
View File
@@ -34,6 +34,18 @@ export interface ScmIntegration {
* differentiate between different integrations.
*/
title: string;
/**
* Works like the two-argument form of the URL constructor, resolving an
* absolute or relative URL in relation to a base URL.
*
* If this method is not implemented, the URL constructor is used instead for
* URLs that match this integration.
*
* @param options.url The (absolute or relative) URL or path to resolve
* @param options.base The base URL onto which this resolution happens
*/
resolveUrl?(options: { url: string; base: string }): string;
}
/**
@@ -69,6 +81,15 @@ export interface ScmIntegrationRegistry
bitbucket: ScmIntegrationsGroup<BitbucketIntegration>;
github: ScmIntegrationsGroup<GitHubIntegration>;
gitlab: ScmIntegrationsGroup<GitLabIntegration>;
/**
* Works like the two-argument form of the URL constructor, resolving an
* absolute or relative URL in relation to a base URL.
*
* @param options.url The (absolute or relative) URL or path to resolve
* @param options.base The base URL onto which this resolution happens
*/
resolveUrl(options: { url: string; base: string }): string;
}
export type ScmIntegrationsFactory<T extends ScmIntegration> = (options: {