add new scaffolder action to ensure a gitlab group exists
Signed-off-by: Andreas Berger <andreas@berger-ecommerce.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': minor
|
||||
---
|
||||
|
||||
Add a new scaffolder action for gitlab to ensure a group exists
|
||||
@@ -45,6 +45,9 @@ const actions = [
|
||||
createGitlabProjectDeployTokenAction({
|
||||
integrations: integrations,
|
||||
}),
|
||||
createGitlabGroupEnsureExistsAction({
|
||||
integrations: integrations,
|
||||
}),
|
||||
];
|
||||
|
||||
// Create Scaffolder Router
|
||||
@@ -104,13 +107,22 @@ spec:
|
||||
url: https://github.com/TEMPLATE
|
||||
values:
|
||||
name: ${{ parameters.name }}
|
||||
- id: createGitlabGroup
|
||||
name: Ensure Gitlab group exists
|
||||
action: gitlab:group:ensureExists
|
||||
input:
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
path:
|
||||
- path
|
||||
- to
|
||||
- group
|
||||
|
||||
- id: publish
|
||||
name: Publish
|
||||
action: publish:gitlab
|
||||
input:
|
||||
description: This is ${{ parameters.name }}
|
||||
repoUrl: ${{ parameters.repoUrl }}
|
||||
repoUrl: ${{ parameters.repoUrl }}?owner=${{ steps.createGitlabGroup.output.groupId }}
|
||||
sourcePath: pimcore
|
||||
defaultBranch: main
|
||||
|
||||
|
||||
@@ -7,6 +7,18 @@ import { JsonObject } from '@backstage/types';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
// @public
|
||||
export const createGitlabGroupEnsureExistsAction: (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => TemplateAction<
|
||||
{
|
||||
repoUrl: string;
|
||||
token?: string | undefined;
|
||||
} & {
|
||||
path: string[];
|
||||
}
|
||||
>;
|
||||
|
||||
// @public
|
||||
export const createGitlabProjectAccessTokenAction: (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
@@ -43,16 +55,18 @@ export const createGitlabProjectVariableAction: (options: {
|
||||
}) => TemplateAction<
|
||||
{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
token?: string | undefined;
|
||||
} & {
|
||||
key: string;
|
||||
value: string;
|
||||
projectId: string | number;
|
||||
variableType: string;
|
||||
variableProtected: boolean;
|
||||
masked: boolean;
|
||||
raw: boolean;
|
||||
environmentScope: string;
|
||||
token?: string | undefined;
|
||||
},
|
||||
variableProtected?: boolean | undefined;
|
||||
masked?: boolean | undefined;
|
||||
raw?: boolean | undefined;
|
||||
environmentScope?: string | undefined;
|
||||
}
|
||||
,
|
||||
JsonObject
|
||||
>;
|
||||
```
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/integration": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-node": "workspace:^",
|
||||
"@gitbeaker/node": "^35.8.0"
|
||||
"@gitbeaker/node": "^35.8.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
|
||||
+140
@@ -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 { PassThrough } from 'stream';
|
||||
import { createGitlabGroupEnsureExistsAction } from './createGitlabGroupEnsureExistsAction';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
|
||||
const mockGitlabClient = {
|
||||
Groups: {
|
||||
search: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
};
|
||||
jest.mock('@gitbeaker/node', () => ({
|
||||
Gitlab: class {
|
||||
constructor() {
|
||||
return mockGitlabClient;
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
describe('gitlab:group:ensureExists', () => {
|
||||
const mockContext = {
|
||||
workspacePath: 'lol',
|
||||
logger: getVoidLogger(),
|
||||
logStream: new PassThrough(),
|
||||
output: jest.fn(),
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should create a new group if it does not exists', async () => {
|
||||
mockGitlabClient.Groups.search.mockResolvedValue([
|
||||
{
|
||||
id: 1,
|
||||
full_path: 'repos/bar',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
full_path: 'repos/foo',
|
||||
},
|
||||
]);
|
||||
|
||||
mockGitlabClient.Groups.create.mockResolvedValue({
|
||||
id: 3,
|
||||
full_path: 'repos/foo/bar',
|
||||
});
|
||||
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
const action = createGitlabGroupEnsureExistsAction({ integrations });
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
repoUrl: 'gitlab.com',
|
||||
path: ['foo', 'bar'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith('bar', 'bar', {
|
||||
parent_id: 2,
|
||||
});
|
||||
|
||||
expect(mockContext.output).toHaveBeenCalledWith('groupId', 3);
|
||||
});
|
||||
|
||||
it('should return existing group if it does exists', async () => {
|
||||
mockGitlabClient.Groups.search.mockResolvedValue([
|
||||
{
|
||||
id: 1,
|
||||
full_path: 'repos/bar',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
full_path: 'repos/foo',
|
||||
},
|
||||
{
|
||||
id: 42,
|
||||
full_path: 'repos/foo/bar',
|
||||
},
|
||||
]);
|
||||
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
const action = createGitlabGroupEnsureExistsAction({ integrations });
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
repoUrl: 'gitlab.com',
|
||||
path: ['foo', 'bar'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockGitlabClient.Groups.create).not.toHaveBeenCalled();
|
||||
|
||||
expect(mockContext.output).toHaveBeenCalledWith('groupId', 42);
|
||||
});
|
||||
});
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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-node';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import { GroupSchema } from '@gitbeaker/core/dist/types/resources/Groups';
|
||||
import commonGitlabConfig from '../commonGitlabConfig';
|
||||
import { getToken } from '../util';
|
||||
import { z } from 'zod';
|
||||
|
||||
const input = commonGitlabConfig.and(
|
||||
z.object({
|
||||
path: z
|
||||
.array(z.string(), {
|
||||
description: 'A path of group names that is ensured to exist',
|
||||
})
|
||||
.min(1),
|
||||
}),
|
||||
);
|
||||
|
||||
const output = z.object({
|
||||
groupId: z.string({ description: 'The id of the innermost sub-group' }),
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an `gitlab:group:ensureExists` Scaffolder action.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const createGitlabGroupEnsureExistsAction = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
|
||||
return createTemplateAction<z.infer<typeof input>>({
|
||||
id: 'gitlab:group:ensureExists',
|
||||
description: 'Ensures a Gitlab group exists',
|
||||
schema: { input, output },
|
||||
async handler(ctx) {
|
||||
const { path } = ctx.input;
|
||||
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
||||
|
||||
const api = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
token: token,
|
||||
});
|
||||
|
||||
let currentPath: string = 'repos';
|
||||
let parent: GroupSchema | null = null;
|
||||
for (const pathElement of path) {
|
||||
const fullPath = `${currentPath}/${pathElement}`;
|
||||
const result = (await api.Groups.search(
|
||||
fullPath,
|
||||
)) as any as Array<GroupSchema>;
|
||||
const subGroup = result.find(
|
||||
searchPathElem => searchPathElem.full_path === fullPath,
|
||||
);
|
||||
if (!subGroup) {
|
||||
ctx.logger.info(`creating missing group ${fullPath}`);
|
||||
parent = await api.Groups.create(
|
||||
pathElement,
|
||||
pathElement,
|
||||
parent
|
||||
? {
|
||||
parent_id: parent.id,
|
||||
}
|
||||
: {},
|
||||
);
|
||||
} else {
|
||||
parent = subGroup;
|
||||
}
|
||||
currentPath = fullPath;
|
||||
}
|
||||
if (parent !== null) {
|
||||
ctx.output('groupId', parent?.id);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
+22
-57
@@ -16,10 +16,27 @@
|
||||
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import commonGitlabConfig from '../commonGitlabConfig';
|
||||
import { getToken } from '../util';
|
||||
import { z } from 'zod';
|
||||
|
||||
const input = commonGitlabConfig.and(
|
||||
z.object({
|
||||
projectId: z.union([z.number(), z.string()], { description: 'Project ID' }),
|
||||
name: z.string({ description: 'Deploy Token Name' }).optional(),
|
||||
accessLevel: z
|
||||
.string({ description: 'Access Level of the Token' })
|
||||
.optional(),
|
||||
scopes: z.array(z.string(), { description: 'Scopes' }).optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
const output = z.object({
|
||||
access_token: z.string({ description: 'Access Token' }),
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a `gitlab:create-project-access-token` Scaffolder action.
|
||||
* Creates a `gitlab:projectAccessToken:create` Scaffolder action.
|
||||
*
|
||||
* @param options - Templating configuration.
|
||||
* @public
|
||||
@@ -28,65 +45,13 @@ export const createGitlabProjectAccessTokenAction = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
name: string;
|
||||
accessLevel: number;
|
||||
scopes: string[];
|
||||
token?: string;
|
||||
}>({
|
||||
return createTemplateAction<z.infer<typeof input>>({
|
||||
id: 'gitlab:projectAccessToken:create',
|
||||
schema: {
|
||||
input: {
|
||||
required: ['projectId', 'repoUrl'],
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
access_token: {
|
||||
title: 'Access Token',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: { input, output },
|
||||
async handler(ctx) {
|
||||
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
||||
const { repoUrl, projectId, name, accessLevel, scopes } = ctx.input;
|
||||
const { token, integrationConfig } = getToken(
|
||||
repoUrl,
|
||||
ctx.input.token,
|
||||
integrations,
|
||||
);
|
||||
const { projectId, name, accessLevel, scopes } = ctx.input;
|
||||
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
||||
|
||||
const response = await fetch(
|
||||
`${integrationConfig.config.baseUrl}/api/v4/projects/${projectId}/access_tokens`,
|
||||
|
||||
+21
-61
@@ -18,11 +18,27 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { DeployTokenScope } from '@gitbeaker/core/dist/types/templates/ResourceDeployTokens';
|
||||
import commonGitlabConfig from '../commonGitlabConfig';
|
||||
import { getToken } from '../util';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { z } from 'zod';
|
||||
|
||||
const input = commonGitlabConfig.and(
|
||||
z.object({
|
||||
projectId: z.union([z.number(), z.string()], { description: 'Project ID' }),
|
||||
name: z.string({ description: 'Deploy Token Name' }),
|
||||
username: z.string({ description: 'Deploy Token Username' }).optional(),
|
||||
scopes: z.array(z.string(), { description: 'Scopes' }).optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
const output = z.object({
|
||||
deploy_token: z.string({ description: 'Deploy Token' }),
|
||||
user: z.string({ description: 'User' }),
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a `gitlab:create-project-deploy-token` Scaffolder action.
|
||||
* Creates a `gitlab:projectDeployToken:create` Scaffolder action.
|
||||
*
|
||||
* @param options - Templating configuration.
|
||||
* @public
|
||||
@@ -31,69 +47,13 @@ export const createGitlabProjectDeployTokenAction = (options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
}) => {
|
||||
const { integrations } = options;
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
projectId: string | number;
|
||||
name: string;
|
||||
username: string;
|
||||
scopes: string[];
|
||||
token?: string;
|
||||
}>({
|
||||
return createTemplateAction<z.infer<typeof input>>({
|
||||
id: 'gitlab:projectDeployToken:create',
|
||||
schema: {
|
||||
input: {
|
||||
required: ['projectId', 'repoUrl'],
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
deploy_token: {
|
||||
title: 'Deploy Token',
|
||||
type: 'string',
|
||||
},
|
||||
user: {
|
||||
title: 'User',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: { input, output },
|
||||
async handler(ctx) {
|
||||
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
||||
const { repoUrl, projectId, name, username, scopes } = ctx.input;
|
||||
const { token, integrationConfig } = getToken(
|
||||
repoUrl,
|
||||
ctx.input.token,
|
||||
integrations,
|
||||
);
|
||||
const { projectId, name, username, scopes } = ctx.input;
|
||||
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
||||
|
||||
const api = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
|
||||
+41
-84
@@ -16,11 +16,43 @@
|
||||
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { getToken } from '../util';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import { getToken } from '../util';
|
||||
import commonGitlabConfig from '../commonGitlabConfig';
|
||||
import { z } from 'zod';
|
||||
|
||||
const input = commonGitlabConfig.and(
|
||||
z.object({
|
||||
projectId: z.union([z.number(), z.string()], { description: 'Project ID' }),
|
||||
key: z
|
||||
.string({
|
||||
description:
|
||||
'The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed',
|
||||
})
|
||||
.regex(/^[A-Za-z0-9_]{1,255}$/),
|
||||
value: z.string({ description: 'The value of a variable' }),
|
||||
variableType: z.string({ description: 'Variable Type (env_var or file)' }),
|
||||
variableProtected: z
|
||||
.boolean({ description: 'Whether the variable is protected' })
|
||||
.default(false)
|
||||
.optional(),
|
||||
masked: z
|
||||
.boolean({ description: 'Whether the variable is masked' })
|
||||
.default(false)
|
||||
.optional(),
|
||||
raw: z
|
||||
.boolean({ description: 'Whether the variable is expandable' })
|
||||
.default(false)
|
||||
.optional(),
|
||||
environmentScope: z
|
||||
.string({ description: 'The environment_scope of the variable' })
|
||||
.default('*')
|
||||
.optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a `gitlab:create-project-variable` Scaffolder action.
|
||||
* Creates a `gitlab:projectVariable:create` Scaffolder action.
|
||||
*
|
||||
* @param options - Templating configuration.
|
||||
* @public
|
||||
@@ -29,96 +61,21 @@ export const createGitlabProjectVariableAction = (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;
|
||||
}>({
|
||||
return createTemplateAction<z.infer<typeof input>>({
|
||||
id: 'gitlab:projectVariable:create',
|
||||
schema: {
|
||||
input: {
|
||||
required: [
|
||||
'repoUrl',
|
||||
'projectId',
|
||||
'key',
|
||||
'value',
|
||||
'variableType',
|
||||
'variableProtected',
|
||||
'masked',
|
||||
'raw',
|
||||
'environmentScope',
|
||||
],
|
||||
type: 'object',
|
||||
properties: {
|
||||
repoUrl: {
|
||||
title: 'Repository Location',
|
||||
type: 'string',
|
||||
},
|
||||
projectId: {
|
||||
title: 'Project ID',
|
||||
type: ['string', 'number'],
|
||||
},
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: { input },
|
||||
async handler(ctx) {
|
||||
const {
|
||||
repoUrl,
|
||||
projectId,
|
||||
key,
|
||||
value,
|
||||
variableType,
|
||||
variableProtected,
|
||||
masked,
|
||||
raw,
|
||||
environmentScope,
|
||||
variableProtected = false,
|
||||
masked = false,
|
||||
raw = false,
|
||||
environmentScope = '*',
|
||||
} = ctx.input;
|
||||
const { token, integrationConfig } = getToken(
|
||||
repoUrl,
|
||||
ctx.input.token,
|
||||
integrations,
|
||||
);
|
||||
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
||||
|
||||
const api = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { z } from 'zod';
|
||||
|
||||
const commonGitlabConfig = z.object({
|
||||
repoUrl: z.string({ description: 'Repository Location' }),
|
||||
token: z
|
||||
.string({ description: 'The token to use for authorization to GitLab' })
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export default commonGitlabConfig;
|
||||
@@ -13,12 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A module for the scaffolder backend that lets you create gitlab project access tokens or deploy tokens
|
||||
* A module for the scaffolder backend that lets you interact with gitlab
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './actions/createGitlabGroupEnsureExistsAction';
|
||||
export * from './actions/createGitlabProjectDeployTokenAction';
|
||||
export * from './actions/createGitlabProjectAccessTokenAction';
|
||||
export * from './actions/createGitlabProjectVariableAction';
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
GitLabIntegration,
|
||||
ScmIntegrationRegistry,
|
||||
} from '@backstage/integration';
|
||||
import { z } from 'zod';
|
||||
import commonGitlabConfig from './commonGitlabConfig';
|
||||
|
||||
export const parseRepoHost = (repoUrl: string): string => {
|
||||
let parsed;
|
||||
@@ -33,11 +35,10 @@ export const parseRepoHost = (repoUrl: string): string => {
|
||||
};
|
||||
|
||||
export const getToken = (
|
||||
repoUrl: string,
|
||||
inputToken: string | null | undefined,
|
||||
config: z.infer<typeof commonGitlabConfig>,
|
||||
integrations: ScmIntegrationRegistry,
|
||||
): { token: string; integrationConfig: GitLabIntegration } => {
|
||||
const host = parseRepoHost(repoUrl);
|
||||
const host = parseRepoHost(config.repoUrl);
|
||||
const integrationConfig = integrations.gitlab.byHost(host);
|
||||
|
||||
if (!integrationConfig) {
|
||||
@@ -46,8 +47,8 @@ export const getToken = (
|
||||
);
|
||||
}
|
||||
|
||||
const token = inputToken || integrationConfig.config.token!;
|
||||
const tokenType = inputToken ? 'oauthToken' : 'token';
|
||||
const token = config.token || integrationConfig.config.token!;
|
||||
const tokenType = config.token ? 'oauthToken' : 'token';
|
||||
|
||||
if (tokenType === 'oauthToken') {
|
||||
throw new InputError(`OAuth Token is currently not supported`);
|
||||
|
||||
@@ -7855,6 +7855,7 @@ __metadata:
|
||||
"@backstage/integration": "workspace:^"
|
||||
"@backstage/plugin-scaffolder-node": "workspace:^"
|
||||
"@gitbeaker/node": ^35.8.0
|
||||
zod: ^3.21.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -40593,6 +40594,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zod@npm:^3.21.4":
|
||||
version: 3.21.4
|
||||
resolution: "zod@npm:3.21.4"
|
||||
checksum: f185ba87342ff16f7a06686767c2b2a7af41110c7edf7c1974095d8db7a73792696bcb4a00853de0d2edeb34a5b2ea6a55871bc864227dace682a0a28de33e1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zod@npm:~3.18.0":
|
||||
version: 3.18.0
|
||||
resolution: "zod@npm:3.18.0"
|
||||
|
||||
Reference in New Issue
Block a user