UNPKG

azdev-automation

Version:

Azure DevOps automation framework enables access control automation of projects, pipelines and repositories configuration in Azure DevOps Services

213 lines (212 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReleaseHelper = void 0; class ReleaseHelper { constructor(releaseApi, logger) { this.debugLogger = logger.extend(this.constructor.name); this.releaseApi = releaseApi; } async getDefinitions(projectName) { const debug = this.debugLogger.extend(this.getDefinitions.name); const result = await this.releaseApi.getReleaseDefinitions(projectName); debug(`Found <${projectName}> project <${result.length}> definition(s)`); return result; } async findDefinitionsWithArtifact(projectName, artifactName, artifactType) { const debug = this.debugLogger.extend(this.findDefinitionsWithArtifact.name); const result = []; const projectDefinitions = await this.releaseApi.getReleaseDefinitions(projectName); debug(`Found <${projectName}> project <${projectDefinitions.length}> definition(s)`); for (const definitioin of projectDefinitions) { const targetDefinition = await this.releaseApi.getReleaseDefinition(projectName, definitioin.id); const exists = targetDefinition.artifacts.some((a) => a.alias === artifactName && a.type === artifactType); if (exists) { debug(`Artifact ${artifactName} found`); result.push(targetDefinition); } } debug(`Found <${result.length}> filtered definition(s)`); return result; } async findDefinitionsWithTasks(name, projectName, tasks) { const debug = this.debugLogger.extend(this.findDefinitionsWithTasks.name); const result = []; const projectDefinitions = await this.releaseApi.getReleaseDefinitions(projectName, name); const taskIDs = tasks.map((t) => t.id); debug(`Found <${projectName}> project <${projectDefinitions.length}> definition(s)`); await Promise.all(projectDefinitions.map(async (definition) => { const targetDefinition = await this.releaseApi.getReleaseDefinition(projectName, definition.id); const taskExists = targetDefinition.environments.some((e) => e.deployPhases.some((p) => p.workflowTasks.some((t) => taskIDs.some((i) => i === t.taskId)))); if (taskExists) { debug("Task(s) mathing ID found"); result.push(targetDefinition); } })); debug(`Found <${result.length}> filtered definition(s)`); return result; } async findDefinitionReleasesWithTasks(definitionId, projectName, tasks) { const debug = this.debugLogger.extend(this.findDefinitionReleasesWithTasks.name); const result = []; const definitionReleases = await this.releaseApi.getReleases(projectName, definitionId); const taskIDs = tasks.map((t) => t.id); debug(`Found <${definitionId}> definition <${definitionReleases.length}> release(s)`); await Promise.all(definitionReleases.map(async (release) => { const targetRelease = await this.releaseApi.getRelease(projectName, release.id); const exists = targetRelease.environments.some((e) => e.deployPhasesSnapshot.some((p) => p.workflowTasks.some((t) => taskIDs.some((i) => i === t.taskId)))); if (exists) { debug("Target task(s) found"); result.push(targetRelease); } })); debug(`Found <${result.length}> filtered release(s)`); return result; } async removeDefinitionTasks(definition, tasks) { const debug = this.debugLogger.extend(this.removeDefinitionTasks.name); const taskIDs = tasks.map((t) => t.id); const removedTasks = []; for (const stage of definition.environments) { for (const phase of stage.deployPhases) { const updatedTasks = []; for (const task of phase.workflowTasks) { if (taskIDs.some((t) => t === task.taskId)) { debug(`Removing <${stage.name}> stage <${task.name}> task`); if (!removedTasks.includes(task.name)) { removedTasks.push(task.name); } continue; } updatedTasks.push(task); } phase.workflowTasks = updatedTasks; } } if (removedTasks.length > 0) { definition.comment = `Remove ${removedTasks.join(", ")} task(s)`; } return definition; } async updateDefinitionTasks(definition, tasks, taskParameters, parametersFilter) { const debug = this.debugLogger.extend(this.updateDefinitionTasks.name); const updatedStages = []; for (const stage of definition.environments) { for (const phase of stage.deployPhases) { const stageTasks = []; for (let task of phase.workflowTasks) { debug(`Processing <${stage.name}> stage <${task.name}> task`); const match = this.isTaskMatch(task, tasks, parametersFilter); if (match) { debug(`Updating <${stage.name}> stage <${task.name}> (${task.taskId}) task`); task = this.updateTaskParameters(task, taskParameters); if (!updatedStages.includes(stage.name)) { updatedStages.push(stage.name); } } stageTasks.push(task); } phase.workflowTasks = stageTasks; } } if (updatedStages.length > 0) { definition.comment = `Update <${updatedStages.join("|")}> stage(s) task parameters`; } return definition; } async updateReleaseTasks(release, tasks, taskParameters, parametersFilter) { const debug = this.debugLogger.extend(this.updateReleaseTasks.name); const updatedStages = []; for (const stage of release.environments) { for (const phase of stage.deployPhasesSnapshot) { const stageTasks = []; for (let task of phase.workflowTasks) { debug(`Processing <${stage.name}> stage <${task.name}> task`); const match = this.isTaskMatch(task, tasks, parametersFilter); if (match) { debug(`Updating <${stage.name}> stage <${task.name}> (${task.taskId}) task`); task = this.updateTaskParameters(task, taskParameters); if (!updatedStages.includes(stage.name)) { updatedStages.push(stage.name); } } stageTasks.push(task); } phase.workflowTasks = stageTasks; } } if (updatedStages.length > 0) { release.comment = `Update <${updatedStages.join("|")}> stage(s) task parameters`; } return release; } async removeDefinitionArtifact(definition, artifactName, artifactType) { const debug = this.debugLogger.extend(this.removeDefinitionArtifact.name); const updatedArtifacts = []; for (const artifact of definition.artifacts) { if (artifact.alias === artifactName && artifact.type === artifactType) { debug(`Removing <${artifact.alias}> type <${artifact.type}> artifact`); continue; } updatedArtifacts.push(artifact); } definition.artifacts = updatedArtifacts; definition.comment = `Remove <${artifactName}> artifact`; return definition; } async updateDefinition(definition, projectName) { const debug = this.debugLogger.extend(this.updateDefinition.name); debug(`Updating <${projectName}> project <${definition.name}> definition`); await this.releaseApi.updateReleaseDefinition(definition, projectName); } async updateRelease(release, projectName) { const debug = this.debugLogger.extend(this.updateRelease.name); debug(`Updating <${release.releaseDefinition.id}> definition <${release.name}> definition`); await this.releaseApi.updateRelease(release, projectName, release.id); } updateTaskParameters(task, parameters) { const debug = this.debugLogger.extend(this.updateTaskParameters.name); for (const parameter of Object.keys(parameters)) { const value = parameters[parameter]; if (Object.prototype.hasOwnProperty.call(task.inputs, parameter)) { debug(`Updating existing <${parameter}:${value}> parameter`); } else { debug(`Adding new <${parameter}:${value}> parameter`); } task.inputs[parameter] = value; } return task; } isTaskMatch(task, tasks, filter) { const debug = this.debugLogger.extend(this.isTaskMatch.name); const taskIDs = tasks.map((t) => t.id); let taskMatch = false; if (Object.keys(filter).length > 0) { let totalMatches = 0; // Apply task parameter maching filter // When at least one parameter value maches for (const parameter of Object.keys(filter)) { const taskValue = task.inputs[parameter]; const filterValue = filter[parameter]; const matchExpression = new RegExp(`^${filterValue}$`); const parameterMatch = matchExpression.test(taskValue); if (parameterMatch) { totalMatches++; // Must match all task parameters if (totalMatches === Object.keys(filter).length) { debug(`Found maching <${matchExpression}> parameter(s) filter <${task.name}> task`); taskMatch = true; } } } } else { taskMatch = taskIDs.some((t) => t === task.taskId); if (taskMatch) { debug(`Found maching ID filter <${task.name}> task`); } } return taskMatch; } } exports.ReleaseHelper = ReleaseHelper;