Add Gitlab Backend Scaffolder Plugin
Signed-off-by: Dominik Pfaffenbauer <dominik@pfaffenbauer.at>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,118 @@
|
||||
# scaffolder-backend-module-gitlab
|
||||
|
||||
Welcome to the Gitlab Module for Scaffolder.
|
||||
|
||||
Here you can find all Gitlab related features to improve your scaffolder:
|
||||
|
||||
## Getting started
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
yarn add --cwd packages/backend @backstage/plugin-scaffolder-backend-module-gitlab
|
||||
```
|
||||
|
||||
Configure the action (you can check
|
||||
the [docs](https://backstage.io/docs/features/software-templates/writing-custom-actions#registering-custom-actions) to
|
||||
see all options):
|
||||
|
||||
After that you can use the action in your template:
|
||||
|
||||
```yaml
|
||||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
name: gitlab-demo
|
||||
title: Gitlab DEMO
|
||||
description: Scaffolder Gitlab Demo
|
||||
spec:
|
||||
owner: backstage/techdocs-core
|
||||
type: service
|
||||
|
||||
parameters:
|
||||
- title: Fill in some steps
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
ui:autofocus: true
|
||||
ui:options:
|
||||
rows: 5
|
||||
- title: Choose a location
|
||||
required:
|
||||
- repoUrl
|
||||
properties:
|
||||
repoUrl:
|
||||
title: Repository Location
|
||||
type: string
|
||||
ui:field: RepoUrlPicker
|
||||
ui:options:
|
||||
allowedHosts:
|
||||
- gitlab.com
|
||||
|
||||
steps:
|
||||
- id: fetch
|
||||
name: Fetch
|
||||
action: fetch:template
|
||||
input:
|
||||
url: https://github.com/TEMPLATE
|
||||
values:
|
||||
name: ${{ parameters.name }}
|
||||
|
||||
- id: publish
|
||||
name: Publish
|
||||
action: publish:gitlab
|
||||
input:
|
||||
description: This is ${{ parameters.name }}
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
sourcePath: pimcore
|
||||
defaultBranch: main
|
||||
|
||||
- id: gitlab-deploy-token
|
||||
name: Create Deploy Token
|
||||
action: gitlab:create-project-deploy-token
|
||||
input:
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
projectId: "${{ steps['publish'].output.projectId }}"
|
||||
name: ${{ parameters.name }}-secret
|
||||
username: ${{ parameters.name }}-secret
|
||||
scopes: ['read_registry']
|
||||
|
||||
- id: gitlab-access-token
|
||||
name: Gitlab Access Token
|
||||
action: gitlab:create-project-access-token
|
||||
input:
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
projectId: "${{ steps['publish-manifest'].output.projectId }}"
|
||||
name: ${{ parameters.name }}-access-token
|
||||
accessLevel: 40
|
||||
scopes: ['read_repository', 'write_repository']
|
||||
|
||||
- id: gitlab-project-variable
|
||||
name: Manifest CI/CD Variable
|
||||
action: gitlab:create-project-variable
|
||||
input:
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
projectId: "${{ steps['publish'].output.projectId }}"
|
||||
key: 'VARIABLE_NAME'
|
||||
value: "${{ steps['gitlab-access-token'].output.access_token }}"
|
||||
variableType: 'env_var'
|
||||
masked: true
|
||||
variableProtected: false
|
||||
raw: false
|
||||
environmentScope: '*'
|
||||
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
input:
|
||||
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
|
||||
catalogInfoPath: '/catalog-info.yaml'
|
||||
|
||||
output:
|
||||
links:
|
||||
- title: Repository
|
||||
url: ${{ steps['publish'].output.remoteUrl }}
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "@backstage/plugin-scaffolder-backend-module-gitlab",
|
||||
"version": "0.0.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend-plugin"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/integration": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend": "workspace:^",
|
||||
"@gitbeaker/node": "^35.8.0",
|
||||
"fs-extra": "10.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/dev-utils": "workspace:^",
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/node": "*",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"msw": "^0.49.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { parseRepoHost } from '../util';
|
||||
|
||||
export const createGitlabProjectAccessToken = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
name: string;
|
||||
accessLevel: number;
|
||||
scopes: string[];
|
||||
token?: string;
|
||||
}>({
|
||||
id: 'gitlab:create-project-access-token',
|
||||
schema: {
|
||||
input: {
|
||||
required: ['projectId'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
repoUrl: {
|
||||
title: 'Repository Location',
|
||||
type: 'string',
|
||||
},
|
||||
projectId: {
|
||||
title: 'Project ID',
|
||||
type: 'string | number',
|
||||
},
|
||||
name: {
|
||||
title: 'Deploy Token Name',
|
||||
type: 'string',
|
||||
},
|
||||
accessLevel: {
|
||||
title: 'Access Level of the Token',
|
||||
type: 'number',
|
||||
},
|
||||
scopes: {
|
||||
title: 'Scopes',
|
||||
type: 'array',
|
||||
},
|
||||
token: {
|
||||
title: 'Authentication Token',
|
||||
type: 'string',
|
||||
description: 'The token to use for authorization to GitLab',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
||||
const { repoUrl, projectId, name, accessLevel, scopes } = ctx.input;
|
||||
|
||||
const host = parseRepoHost(repoUrl);
|
||||
const integrationConfig = integrations.gitlab.byHost(host);
|
||||
|
||||
if (!integrationConfig) {
|
||||
throw new InputError(
|
||||
`No matching integration configuration for host ${host}, please check your integrations config`,
|
||||
);
|
||||
}
|
||||
|
||||
const token = ctx.input.token || integrationConfig.config.token!;
|
||||
const tokenType = ctx.input.token ? 'oauthToken' : 'token';
|
||||
|
||||
if (tokenType === 'oauthToken') {
|
||||
throw new InputError(`OAuth Token is currently not supported`);
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`${integrationConfig.config.baseUrl}/api/v4/projects/${projectId}/access_tokens`,
|
||||
{
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
headers: {
|
||||
'PRIVATE-TOKEN': token,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
scopes: scopes,
|
||||
access_level: accessLevel,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
ctx.output('access_token', result.token);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createGitlabProjectDeployToken } from './createProjectDeployToken';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { PassThrough } from 'stream';
|
||||
|
||||
const mockGitlabClient = {
|
||||
ProjectDeployTokens: {
|
||||
add: jest.fn(),
|
||||
},
|
||||
};
|
||||
jest.mock('@gitbeaker/node', () => ({
|
||||
Gitlab: class {
|
||||
constructor() {
|
||||
return mockGitlabClient;
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
describe('gitlab:create-deploy-token', () => {
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
{
|
||||
host: 'hosted.gitlab.com',
|
||||
apiBaseUrl: 'https://api.hosted.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const action = createGitlabProjectDeployToken({ integrations });
|
||||
const mockContext = {
|
||||
input: {
|
||||
repoUrl: 'gitlab.com?repo=repo&owner=owner',
|
||||
projectId: '123',
|
||||
name: 'tokenname',
|
||||
username: 'tokenuser',
|
||||
scopes: ['read_repository'],
|
||||
},
|
||||
workspacePath: 'lol',
|
||||
logger: getVoidLogger(),
|
||||
logStream: new PassThrough(),
|
||||
output: jest.fn(),
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should work when there is a token provided through ctx.input', async () => {
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
repoUrl: 'hosted.gitlab.com?repo=bob&owner=owner',
|
||||
projectId: '123',
|
||||
name: 'tokenname',
|
||||
username: 'tokenuser',
|
||||
scopes: ['read_repository'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith(
|
||||
'123',
|
||||
'tokenname',
|
||||
['read_repository'],
|
||||
{ username: 'tokenuser' },
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { DeployTokenScope } from '@gitbeaker/core/dist/types/templates/ResourceDeployTokens';
|
||||
import { parseRepoHost } from '../util';
|
||||
|
||||
export const createGitlabProjectDeployToken = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
name: string;
|
||||
username: string;
|
||||
scopes: string[];
|
||||
token?: string;
|
||||
}>({
|
||||
id: 'gitlab:create-project-deploy-token',
|
||||
schema: {
|
||||
input: {
|
||||
required: ['projectId'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
repoUrl: {
|
||||
title: 'Repository Location',
|
||||
type: 'string',
|
||||
},
|
||||
projectId: {
|
||||
title: 'Project ID',
|
||||
type: 'string | number',
|
||||
},
|
||||
name: {
|
||||
title: 'Deploy Token Name',
|
||||
type: 'string',
|
||||
},
|
||||
username: {
|
||||
title: 'Deploy Token Username',
|
||||
type: 'string',
|
||||
},
|
||||
scopes: {
|
||||
title: 'Scopes',
|
||||
type: 'array',
|
||||
},
|
||||
token: {
|
||||
title: 'Authentication Token',
|
||||
type: 'string',
|
||||
description: 'The token to use for authorization to GitLab',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
||||
const { repoUrl, projectId, name, username, scopes } = ctx.input;
|
||||
|
||||
const host = parseRepoHost(repoUrl);
|
||||
const integrationConfig = integrations.gitlab.byHost(host);
|
||||
|
||||
if (!integrationConfig) {
|
||||
throw new InputError(
|
||||
`No matching integration configuration for host ${host}, please check your integrations config`,
|
||||
);
|
||||
}
|
||||
|
||||
const token = ctx.input.token || integrationConfig.config.token!;
|
||||
const tokenType = ctx.input.token ? 'oauthToken' : 'token';
|
||||
|
||||
if (tokenType === 'oauthToken') {
|
||||
throw new InputError(`OAuth Token is currently not supported`);
|
||||
}
|
||||
|
||||
const api = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
token: token,
|
||||
});
|
||||
|
||||
const deployToken = await api.ProjectDeployTokens.add(
|
||||
projectId,
|
||||
name,
|
||||
scopes as DeployTokenScope[],
|
||||
{
|
||||
username: username,
|
||||
},
|
||||
);
|
||||
|
||||
const string = JSON.stringify(deployToken);
|
||||
const result = JSON.parse(string);
|
||||
|
||||
ctx.output('deploy_token', result.token);
|
||||
ctx.output('user', deployToken.username);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { parseRepoHost } from '../util';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
|
||||
export const createGitlabProjectVariable = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
key: string;
|
||||
value: string;
|
||||
variableType: string;
|
||||
variableProtected: boolean;
|
||||
masked: boolean;
|
||||
raw: boolean;
|
||||
environmentScope: string;
|
||||
token?: string;
|
||||
}>({
|
||||
id: 'gitlab:create-project-variable',
|
||||
schema: {
|
||||
input: {
|
||||
required: [
|
||||
'projectId',
|
||||
'key',
|
||||
'value',
|
||||
'variableType',
|
||||
'variableProtected',
|
||||
'masked',
|
||||
'raw',
|
||||
'environmentScope',
|
||||
],
|
||||
type: 'object',
|
||||
properties: {
|
||||
repoUrl: {
|
||||
title: 'Repository Location',
|
||||
type: 'string',
|
||||
},
|
||||
key: {
|
||||
title:
|
||||
'The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed',
|
||||
type: 'string',
|
||||
},
|
||||
value: {
|
||||
title: 'The value of a variable',
|
||||
type: 'string',
|
||||
},
|
||||
variableType: {
|
||||
title: 'Variable Type (env_var or file)',
|
||||
type: 'string',
|
||||
},
|
||||
variableProtected: {
|
||||
title: 'Whether the variable is protected. Default: false',
|
||||
type: 'boolean',
|
||||
},
|
||||
masked: {
|
||||
title: 'Whether the variable is masked. Default: false',
|
||||
type: 'boolean',
|
||||
},
|
||||
raw: {
|
||||
title: 'Whether the variable is expandable. Default: false',
|
||||
type: 'boolean',
|
||||
},
|
||||
environmentScope: {
|
||||
title: 'The environment_scope of the variable. Default: *',
|
||||
type: 'string',
|
||||
},
|
||||
token: {
|
||||
title: 'Authentication Token',
|
||||
type: 'string',
|
||||
description: 'The token to use for authorization to GitLab',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const {
|
||||
repoUrl,
|
||||
projectId,
|
||||
key,
|
||||
value,
|
||||
variableType,
|
||||
variableProtected,
|
||||
masked,
|
||||
raw,
|
||||
environmentScope,
|
||||
} = ctx.input;
|
||||
|
||||
const host = parseRepoHost(repoUrl);
|
||||
const integrationConfig = integrations.gitlab.byHost(host);
|
||||
|
||||
if (!integrationConfig) {
|
||||
throw new InputError(
|
||||
`No matching integration configuration for host ${host}, please check your integrations config`,
|
||||
);
|
||||
}
|
||||
|
||||
const token = ctx.input.token || integrationConfig.config.token!;
|
||||
const tokenType = ctx.input.token ? 'oauthToken' : 'token';
|
||||
|
||||
if (tokenType === 'oauthToken') {
|
||||
throw new InputError(`OAuth Token is currently not supported`);
|
||||
}
|
||||
|
||||
const api = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
token: token,
|
||||
});
|
||||
|
||||
await api.ProjectVariables.create(projectId, {
|
||||
key: key,
|
||||
value: value,
|
||||
variable_type: variableType,
|
||||
protected: variableProtected,
|
||||
masked: masked,
|
||||
raw: raw,
|
||||
environment_scope: environmentScope,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './actions/createProjectDeployToken';
|
||||
export * from './actions/createProjectAccessToken';
|
||||
export * from './actions/createProjectVariable';
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { InputError } from '@backstage/errors';
|
||||
|
||||
export const parseRepoHost = (repoUrl: string): string => {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(`https://${repoUrl}`);
|
||||
} catch (error) {
|
||||
throw new InputError(
|
||||
`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`,
|
||||
);
|
||||
}
|
||||
return parsed.host;
|
||||
};
|
||||
Reference in New Issue
Block a user