feat: add scaffolder action to trigger gitlab pipelines

Signed-off-by: ElaineDeMattosSilvaB <elaine.de-mattos-silva-bezerra@deutschebahn.com>
This commit is contained in:
ElaineDeMattosSilvaB
2024-05-24 17:05:49 +02:00
parent 024b530575
commit eff06359a8
4 changed files with 150 additions and 4 deletions
@@ -0,0 +1,41 @@
/*
* Copyright 2023 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 { TemplateExample } from '@backstage/plugin-scaffolder-node';
import yaml from 'yaml';
import { commonGitlabConfigExample } from '../commonGitlabConfig';
export const examples: TemplateExample[] = [
{
description: 'Trigger a GitLab Project Pipeline',
example: yaml.stringify({
steps: [
{
id: 'triggerPipeline',
name: 'Trigger Project Pipeline',
action: 'gitlab:pipeline:trigger',
input: {
...commonGitlabConfigExample,
projectId: 12,
tokenDescription:
'This is the text that will appear in the pipeline token',
token: 'glpt-xxxxxxxxxxxx',
branch: 'main',
},
},
],
}),
},
];
@@ -0,0 +1,102 @@
/*
* Copyright 2023 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';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
ExpandedPipelineSchema,
PipelineTriggerTokenSchema,
} from '@gitbeaker/rest';
import { z } from 'zod';
import commonGitlabConfig from '../commonGitlabConfig';
import { getClient, parseRepoUrl } from '../util';
import { examples } from './gitlabPipelineTrigger.examples';
const pipelineInputProperties = z.object({
projectId: z.number().describe('Project Id'),
tokenDescription: z.string().describe('Pipeline token description'),
branch: z.string().describe('Project branch'),
});
const pipelineOutputProperties = z.object({
pipelineUrl: z.string({ description: 'Pipeline Url' }),
});
/**
* Creates a `gitlab:pipeline:trigger` Scaffolder action.
*
* @param options - Templating configuration.
* @public
*/
export const createTriggerGitlabPipelineAction = (options: {
integrations: ScmIntegrationRegistry;
}) => {
const { integrations } = options;
return createTemplateAction({
id: 'gitlab:pipeline:trigger',
description: 'Triggers a GitLab Pipeline.',
examples,
schema: {
input: commonGitlabConfig.merge(pipelineInputProperties),
output: pipelineOutputProperties,
},
async handler(ctx) {
try {
const { repoUrl, projectId, tokenDescription, token, branch } =
commonGitlabConfig.merge(pipelineInputProperties).parse(ctx.input);
const { host } = parseRepoUrl(repoUrl, integrations);
const api = getClient({ host, integrations, token });
// Get a pipeline token
const createdPipelineTokenResponse =
(await api.PipelineTriggerTokens.create(
projectId,
tokenDescription,
)) as PipelineTriggerTokenSchema;
if (!createdPipelineTokenResponse.token) {
return;
}
// Use the pipeline token to trigger the pipeline in the project
const pipelineTriggerResponse =
(await api.PipelineTriggerTokens.trigger(
projectId,
branch,
createdPipelineTokenResponse.token,
)) as ExpandedPipelineSchema;
// Delete the pipeline token
await api.PipelineTriggerTokens.remove(
projectId,
createdPipelineTokenResponse.id,
);
ctx.output('pipelineUrl', pipelineTriggerResponse.web_url);
} catch (error: any) {
if (error instanceof z.ZodError) {
// Handling Zod validation errors
throw new InputError(`Validation error: ${error.message}`, {
validationErrors: error.errors,
});
}
// Handling other errors
throw new InputError(`Failed to trigger Pipeline: ${error.message}`);
}
},
});
};
@@ -14,10 +14,11 @@
* limitations under the License.
*/
export * from './createGitlabGroupEnsureExistsAction';
export * from './createGitlabProjectDeployTokenAction';
export * from './createGitlabProjectAccessTokenAction';
export * from './createGitlabProjectVariableAction';
export * from './createGitlabIssueAction';
export * from './createGitlabProjectAccessTokenAction';
export * from './createGitlabProjectDeployTokenAction';
export * from './createGitlabProjectVariableAction';
export * from './gitlab';
export * from './gitlabMergeRequest';
export * from './gitlabRepoPush';
export * from './gitlabPipelineTrigger';
@@ -17,6 +17,7 @@ import {
coreServices,
createBackendModule,
} from '@backstage/backend-plugin-api';
import { ScmIntegrations } from '@backstage/integration';
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';
import {
createGitlabGroupEnsureExistsAction,
@@ -27,8 +28,8 @@ import {
createGitlabRepoPushAction,
createPublishGitlabAction,
createPublishGitlabMergeRequestAction,
createTriggerGitlabPipelineAction,
} from './actions';
import { ScmIntegrations } from '@backstage/integration';
/**
* @public
@@ -55,6 +56,7 @@ export const gitlabModule = createBackendModule({
createGitlabRepoPushAction({ integrations }),
createPublishGitlabAction({ config, integrations }),
createPublishGitlabMergeRequestAction({ integrations }),
createTriggerGitlabPipelineAction({ integrations }),
);
},
});