diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts new file mode 100644 index 0000000000..4948db908b --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts @@ -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', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts new file mode 100644 index 0000000000..2edb529ea7 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts @@ -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}`); + } + }, + }); +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts index 4a5ca06c98..fb80a43ff4 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts @@ -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'; diff --git a/plugins/scaffolder-backend-module-gitlab/src/module.ts b/plugins/scaffolder-backend-module-gitlab/src/module.ts index 3571575827..17052b987f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/module.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/module.ts @@ -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 }), ); }, });