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
JavaScript
;
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;