UNPKG

@antoniobergas/scaffolder-backend-module-azure-pipelines

Version:
472 lines (463 loc) 16.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var errors = require('@backstage/errors'); var integration = require('@backstage/integration'); var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node'); var fetch = require('node-fetch'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); const createAzurePipelineAction = (options) => { const { integrations } = options; return pluginScaffolderNode.createTemplateAction({ id: "azure:pipeline:create", schema: { input: { required: [ "organization", "project", "folder", "name", "repositoryId", "repositoryName" ], type: "object", properties: { createApiVersion: { type: "string", title: "Create API version", description: "The Azure Create Pipeline API version to use. Defaults to 6.1-preview.1" }, server: { type: "string", title: "Server hostname", description: "The hostname of the Azure DevOps service. Defaults to dev.azure.com" }, organization: { type: "string", title: "Organization", description: "The name of the Azure DevOps organization." }, project: { type: "string", title: "Project", description: "The name of the Azure project." }, folder: { type: "string", title: "Folder", description: "The name of the folder of the pipeline." }, name: { type: "string", title: "Name", description: "The name of the pipeline." }, repositoryId: { type: "string", title: "Repository ID", description: "The ID of the repository." }, repositoryName: { type: "string", title: "Repository Name", description: "The name of the repository." }, yamlPath: { type: "string", title: "Azure DevOps Pipelines Definition", description: "The location of the Azure DevOps Pipeline definition file. Defaults to /azure-pipelines.yaml" }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization." } } } }, async handler(ctx) { var _a, _b; const { createApiVersion, server, organization, project, folder, name, repositoryId, yamlPath, repositoryName } = ctx.input; const host = server != null ? server : "dev.azure.com"; const apiVersion = createApiVersion != null ? createApiVersion : "6.1-preview.1"; const type = (_a = integrations.byHost(host)) == null ? void 0 : _a.type; if (!type) { throw new errors.InputError( `No matching integration configuration for host ${host}, please check your integrations config` ); } const url = `https://${host}/${organization}`; const credentialProvider = integration.DefaultAzureDevOpsCredentialsProvider.fromIntegrations(integrations); const credentials = await credentialProvider.getCredentials({ url }); if (credentials === void 0 && ctx.input.token === void 0) { throw new errors.InputError( `No credentials provided ${url}, please check your integrations config` ); } const token = (_b = ctx.input.token) != null ? _b : credentials.token; ctx.logger.info( `Creating an Azure pipeline for the repository ${repositoryName} with the ID ${repositoryId}.` ); await fetch__default["default"]( `https://${host}/${organization}/${project}/_apis/pipelines?api-version=${apiVersion}`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Basic ${Buffer.from(`PAT:${token}`).toString( "base64" )}`, "X-TFS-FedAuthRedirect": "Suppress" }, body: JSON.stringify({ folder, name, configuration: { type: "yaml", path: yamlPath || "/azure-pipelines.yaml", repository: { id: repositoryId, name: repositoryName, type: "azureReposGit" } } }) } ).then((response) => { if (response.ok) { ctx.logger.info( `Successfully created ${name} Azure pipeline in ${folder}.` ); } else { ctx.logger.error( `Failed to create Azure pipeline. Status code ${response.status}.` ); } return response.json(); }).then((data) => { ctx.logger.info(`The Azure pipeline ID is ${data.id}.`); ctx.output("pipelineId", data.id.toString()); ctx.output("pipelineUrl", data._links.web.href); }); } }); }; const permitAzurePipelineAction = (options) => { const { integrations } = options; return pluginScaffolderNode.createTemplateAction({ id: "azure:pipeline:permit", schema: { input: { required: [ "organization", "project", "resourceId", "resourceType", "authorized", "pipelineId" ], type: "object", properties: { permitsApiVersion: { type: "string", title: "Permits API version", description: "The Azure Permits Pipeline API version to use. Defaults to 7.1-preview.1" }, server: { type: "string", title: "Server hostname", description: "The hostname of the Azure DevOps service. Defaults to dev.azure.com" }, organization: { type: "string", title: "Organization", description: "The name of the Azure DevOps organization." }, project: { type: "string", title: "Project", description: "The name of the Azure project." }, resourceId: { type: "string", title: "Resource ID", description: "The resource ID." }, resourceType: { type: "string", title: "Resource Type", description: "The type of the resource (e.g. endpoint)." }, authorized: { type: "boolean", title: "Authorized", description: "A true or false authorization indicator." }, pipelineId: { type: "string", title: "Pipeline ID", description: "The pipeline ID." }, token: { title: "Authenticatino Token", type: "string", description: "The token to use for authorization." } } } }, async handler(ctx) { var _a, _b; const { permitsApiVersion, server, organization, project, resourceId, resourceType, authorized, pipelineId } = ctx.input; const host = server != null ? server : "dev.azure.com"; const apiVersion = permitsApiVersion != null ? permitsApiVersion : "7.1-preview.1"; const type = (_a = integrations.byHost(host)) == null ? void 0 : _a.type; if (!type) { throw new errors.InputError( `No matching integration configuration for host ${host}, please check your integrations config` ); } const url = `https://${host}/${organization}`; const credentialProvider = integration.DefaultAzureDevOpsCredentialsProvider.fromIntegrations(integrations); const credentials = await credentialProvider.getCredentials({ url }); if (credentials === void 0 && ctx.input.token === void 0) { throw new errors.InputError( `No credentials provided ${url}, please check your integrations config` ); } const token = (_b = ctx.input.token) != null ? _b : credentials.token; if (ctx.input.authorized === true) { ctx.logger.info( `Authorizing Azure pipeline with ID ${pipelineId} for ${resourceType} with ID ${resourceId}.` ); } else { ctx.logger.info( `Unauthorizing Azure pipeline with ID ${pipelineId} for ${resourceType} with ID ${resourceId}.` ); } await fetch__default["default"]( `https://${host}/${organization}/${project}/_apis/pipelines/pipelinepermissions/${resourceType}/${resourceId}?api-version=${apiVersion}`, { method: "PATCH", headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Basic ${Buffer.from(`PAT:${token}`).toString( "base64" )}`, "X-TFS-FedAuthRedirect": "Suppress" }, body: JSON.stringify({ pipelines: [ { authorized, id: parseInt(pipelineId, 10) } ] }) } ).then((response) => { if (response.ok) { ctx.logger.info( `Successfully changed the Azure pipeline permissions.` ); } else { ctx.logger.error( `Failed to change the Azure pipeline permissions. Status code ${response.status}.` ); } }); } }); }; const runAzurePipelineAction = (options) => { const { integrations } = options; async function checkPipelineStatus(host, organization, project, runId, token, buildApiVersion) { const response = await fetch__default["default"]( `https://${host}/${organization}/${project}/_apis/build/builds/${runId}?api-version=${buildApiVersion}`, { headers: { Authorization: `Basic ${Buffer.from(`PAT:${token}`).toString("base64")}`, "X-TFS-FedAuthRedirect": "Suppress" } } ); if (!response.ok) { throw new Error(`Failed to retrieve pipeline run status. Status code ${response.status}.`); } const json = await response.json(); const status = json.status; if (status === "completed") { return json.result === "succeeded"; } else if (status === "inProgress" || status === "notStarted") { await new Promise((resolve) => setTimeout(resolve, 1e4)); return checkPipelineStatus(host, organization, project, runId, token, buildApiVersion); } else { throw new Error(`Azure pipeline failed with status: ${status}.`); } } return pluginScaffolderNode.createTemplateAction({ id: "azure:pipeline:run", schema: { input: { required: [ "organization", "pipelineId", "project" ], type: "object", properties: { runApiVersion: { type: "string", title: "Run API version", description: "The Azure Run Pipeline API version to use. Defaults to 7.0" }, buildApiVersion: { type: "string", title: "Build API version", description: "The Builds API version to use. Defaults to 6.1-preview.6" }, server: { type: "string", title: "Server hostname", description: "The hostname of the Azure DevOps service. Defaults to dev.azure.com" }, organization: { type: "string", title: "Organization", description: "The name of the Azure DevOps organization." }, pipelineId: { type: "string", title: "Pipeline ID", description: "The pipeline ID." }, project: { type: "string", title: "Project", description: "The name of the Azure project." }, branch: { title: "Repository Branch", type: "string", description: "The branch of the pipeline's repository." }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization." }, pipelineParameters: { title: "Pipeline Parameters", type: "object", description: "The values you need as parameters on the request to start a build." } } } }, async handler(ctx) { var _a, _b; const { runApiVersion, buildApiVersion, server, organization, pipelineId, project, branch, pipelineParameters } = ctx.input; const host = server != null ? server : "dev.azure.com"; const apiVersions = { runApiVersion: runApiVersion != null ? runApiVersion : "7.0", buildApiVersion: buildApiVersion != null ? buildApiVersion : "6.1-preview.6" }; const type = (_a = integrations.byHost(host)) == null ? void 0 : _a.type; if (!type) { throw new errors.InputError( `No matching integration configuration for host ${host}, please check your integrations config` ); } const url = `https://${host}/${organization}`; const credentialProvider = integration.DefaultAzureDevOpsCredentialsProvider.fromIntegrations(integrations); const credentials = await credentialProvider.getCredentials({ url }); if (credentials === void 0 && ctx.input.token === void 0) { throw new errors.InputError( `No credentials provided ${url}, please check your integrations config` ); } const token = (_b = ctx.input.token) != null ? _b : credentials.token; ctx.logger.info(`Running Azure pipeline with the ID ${pipelineId}.`); const request = { resources: { repositories: { self: { refName: `refs/heads/${branch != null ? branch : "main"}` } } }, templateParameters: pipelineParameters, yamlOverrides: "" }; const body = JSON.stringify(request); await fetch__default["default"]( `https://${host}/${organization}/${project}/_apis/pipelines/${pipelineId}/runs?api-version=${apiVersions.runApiVersion}`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: `Basic ${Buffer.from(`PAT:${token}`).toString( "base64" )}`, "X-TFS-FedAuthRedirect": "Suppress" }, body } ).then((response) => { if (response.ok) { return response.json(); } else { throw new Error(`Failed to run Azure pipeline. Status code ${response.status}.`); } }).then((json) => { const pipelineUrl = json._links.web.href; ctx.logger.info(`Successfully started Azure pipeline run: ${pipelineUrl}`); const pipelineRunId = json.id; return checkPipelineStatus(host, organization, project, pipelineRunId, token, apiVersions.buildApiVersion); }).then((success) => { if (success) { ctx.logger.info(`Azure pipeline completed successfully.`); } else { ctx.logger.error(`Azure pipeline failed.`); } }).catch((error) => { ctx.logger.error(error.message); }); } }); }; exports.createAzurePipelineAction = createAzurePipelineAction; exports.permitAzurePipelineAction = permitAzurePipelineAction; exports.runAzurePipelineAction = runAzurePipelineAction; //# sourceMappingURL=index.cjs.js.map