/// <summary> /// Create notification groups for failures in scheduled builds /// </summary> /// <param name="organization">Azure DevOps Organization</param> /// <param name="project">Name of the DevOps project</param> /// <param name="pathPrefix">Path prefix to include pipelines (e.g. "\net")</param> /// <param name="tokenVariableName">Environment variable token name (e.g. "SYSTEM_ACCESSTOKEN")</param> /// <param name="selectionStrategy">Pipeline selection strategy</param> /// <param name="dryRun">Prints changes but does not alter any objects</param> /// <returns></returns> static async Task Main( string organization, string project, string pathPrefix, string tokenVariableName, PipelineSelectionStrategy selectionStrategy = PipelineSelectionStrategy.Scheduled, bool dryRun = false) { var devOpsToken = Environment.GetEnvironmentVariable(tokenVariableName); var devOpsCreds = new VssBasicCredential("nobody", devOpsToken); var devOpsConnection = new VssConnection(new Uri($"https://dev.azure.com/{organization}/"), devOpsCreds); #pragma warning disable CS0618 // Type or member is obsolete var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(config => { config.IncludeScopes = true; }); }); #pragma warning restore CS0618 // Type or member is obsolete var devOpsServiceLogger = loggerFactory.CreateLogger <AzureDevOpsService>(); var notificationConfiguratorLogger = loggerFactory.CreateLogger <NotificationConfigurator>(); var devOpsService = new AzureDevOpsService(devOpsConnection, devOpsServiceLogger); var configurator = new NotificationConfigurator(devOpsService, notificationConfiguratorLogger); await configurator.ConfigureNotifications( project, pathPrefix, persistChanges : !dryRun, strategy : selectionStrategy); }
public async Task ConfigureNotifications( string projectName, string projectPath, bool persistChanges = true, PipelineSelectionStrategy strategy = PipelineSelectionStrategy.Scheduled) { var pipelines = await GetPipelinesAsync(projectName, projectPath, strategy); var teams = await service.GetTeamsAsync(projectName); foreach (var pipeline in pipelines) { using (logger.BeginScope("Evaluate Pipeline Name = {0}, Path = {1}, Id = {2}", pipeline.Name, pipeline.Path, pipeline.Id)) { var parentTeam = await EnsureTeamExists(pipeline, "Notifications", TeamPurpose.ParentNotificationTeam, teams, persistChanges); var childTeam = await EnsureTeamExists(pipeline, "Sync Notifications", TeamPurpose.SynchronizedNotificationTeam, teams, persistChanges); if (!persistChanges && (parentTeam == default || childTeam == default)) { // Skip team nesting and notification work if logger.LogInformation("Skipping Teams and Notifications because parent or child team does not exist"); continue; } await EnsureSynchronizedNotificationTeamIsChild(parentTeam, childTeam, persistChanges); await EnsureScheduledBuildFailSubscriptionExists(pipeline, parentTeam, persistChanges); // Associate } } }
public async Task ConfigureNotifications( string projectName, string projectPath, bool persistChanges = true, PipelineSelectionStrategy strategy = PipelineSelectionStrategy.Scheduled) { var pipelines = await GetPipelinesAsync(projectName, projectPath, strategy); var teams = await service.GetAllTeamsAsync(projectName); foreach (var pipeline in pipelines) { // If the pipeline name length is max or greater there is no // room to add differentiators like "-- Sync Notifications" // and this will result in team name collisions. if (pipeline.Name.Length >= MaxTeamNameLength) { throw new Exception($"Pipeline Name outside of character limit: Max = {MaxTeamNameLength}, Actual = {pipeline.Name.Length}, Name = {pipeline.Name}"); } using (logger.BeginScope("Evaluate Pipeline Name = {0}, Path = {1}, Id = {2}", pipeline.Name, pipeline.Path, pipeline.Id)) { var parentTeam = await EnsureTeamExists(pipeline, "Notifications", TeamPurpose.ParentNotificationTeam, teams, persistChanges); var childTeam = await EnsureTeamExists(pipeline, "Sync Notifications", TeamPurpose.SynchronizedNotificationTeam, teams, persistChanges); if (!persistChanges && (parentTeam == default || childTeam == default)) { // Skip team nesting and notification work if logger.LogInformation("Skipping Teams and Notifications because parent or child team does not exist"); continue; } await EnsureSynchronizedNotificationTeamIsChild(parentTeam, childTeam, persistChanges); await EnsureScheduledBuildFailSubscriptionExists(pipeline, parentTeam, persistChanges); // Associate } } }
private async Task <IEnumerable <BuildDefinition> > GetPipelinesAsync(string projectName, string projectPath, PipelineSelectionStrategy strategy) { var definitions = await service.GetPipelinesAsync(projectName, projectPath); switch (strategy) { case PipelineSelectionStrategy.All: return(definitions); case PipelineSelectionStrategy.Scheduled: default: return(definitions.Where( def => def.Triggers.Any( trigger => trigger.TriggerType == DefinitionTriggerType.Schedule))); } }