public string GetDefinitionName(SdkComponent component) { var baseName = component.Variant == null ? $"{Context.Prefix} - {component.Name}" : $"{Context.Prefix} - {component.Name} - {component.Variant}"; return(baseName + PipelineNameSuffix); }
protected override string GetDefinitionName(SdkComponent component) { var definitionName = $"{Context.Prefix} - {component.Name} - tests-weekly"; if (component.Variant != null) { definitionName += $".{component.Variant}"; } return(definitionName); }
protected bool EnsureManagedVariables(BuildDefinition definition, SdkComponent component) { var hasChanges = false; var managedVariables = new Dictionary <string, string> { { "meta.platform", this.Context.Prefix }, { "meta.component", component.Name }, { "meta.variant", component.Variant }, { "meta.category", this.PipelineCategory }, { "meta.autoGenerated", "true" }, }; foreach (var(key, value) in managedVariables) { if (string.IsNullOrEmpty(value)) { if (definition.Variables.ContainsKey(key)) { Logger.LogInformation("Removing managed variable {Name}", key); definition.Variables.Remove(key); hasChanges = true; } // else: Nothing to do if an empty variable doesn't already exist. continue; } if (definition.Variables.TryGetValue(key, out var existingVariable)) { if (existingVariable.Value == value && !existingVariable.AllowOverride && !existingVariable.IsSecret) { // nothing to do if an existing variable matches the new value and options continue; } Logger.LogInformation("Overwriting managed variable {Name} from '{OriginalValue}' to '{NewValue}', not secret, not overridable", key, existingVariable.Value, value); } definition.Variables[key] = new BuildDefinitionVariable { Value = value, IsSecret = false, AllowOverride = false }; hasChanges = true; } return(hasChanges); }
public async Task <BuildDefinition> CreateOrUpdateDefinitionAsync(SdkComponent component, CancellationToken cancellationToken) { var definitionName = GetDefinitionName(component); Logger.LogDebug("Checking to see if definition '{0}' exists prior to create/update.", definitionName); var definition = await GetExistingDefinitionAsync(definitionName, cancellationToken); if (definition == null) { Logger.LogDebug("Definition '{0}' was not found.", definitionName); definition = await CreateDefinitionAsync(definitionName, component, cancellationToken); } Logger.LogDebug("Applying convention to '{0}' definition.", definitionName); var hasChanges = await ApplyConventionAsync(definition, component); if (hasChanges) { if (!Context.WhatIf) { Logger.LogInformation("Convention had changes, updating '{0}' definition.", definitionName); var buildClient = await Context.GetBuildHttpClientAsync(cancellationToken); definition.Comment = "Updated by pipeline generation tool"; definition = await buildClient.UpdateDefinitionAsync( definition : definition, cancellationToken : cancellationToken ); } else { Logger.LogWarning("Skipping update to definition '{0}' (--whatif).", definitionName); } } else { Logger.LogDebug("No changes for definition '{0}'.", definitionName); } return(definition); }
public async Task <BuildDefinition> DeleteDefinitionAsync(SdkComponent component, CancellationToken cancellationToken) { var definitionName = GetDefinitionName(component); Logger.LogDebug("Checking to see if definition '{0}' exists prior to deleting.", definitionName); var definition = await GetExistingDefinitionAsync(definitionName, cancellationToken); if (definition != null) { Logger.LogDebug("Found definition called '{0}' at '{1}'.", definitionName, definition.GetWebUrl()); if (!Context.WhatIf) { Logger.LogWarning("Deleting definition '{0}'.", definitionName); var projectReference = await Context.GetProjectReferenceAsync(cancellationToken); var buildClient = await Context.GetBuildHttpClientAsync(cancellationToken); await buildClient.DeleteDefinitionAsync( project : projectReference.Id, definitionId : definition.Id, cancellationToken : cancellationToken ); } else { Logger.LogWarning("Skipping deleting definition '{0}' (--whatif).", definitionName); } return(definition); } else { Logger.LogDebug("No definition called '{0}' existed.", definitionName); return(null); } }
protected virtual Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { bool hasChanges = false; if (EnsureVariableGroups(definition)) { hasChanges = true; } if (EnsureReportBuildStatus(definition)) { hasChanges = true; } if (IsScheduled) { var scheduleTriggers = definition.Triggers.OfType <ScheduleTrigger>(); var computedSchedule = CreateScheduleFromDefinition(definition); // Here we are basically say that if you don't have any triggers, or the triggers are empty or if it doesn't // match what we computed, then recreate it. This will force consistency but only require an update IF it // doesn't match what we want it to be. if (scheduleTriggers == default || !scheduleTriggers.Any() || (scheduleTriggers.First().Schedules[0].StartHours != computedSchedule.StartHours || scheduleTriggers.First().Schedules[0].StartMinutes != computedSchedule.StartMinutes)) { definition.Triggers.Add(new ScheduleTrigger { Schedules = new List <Schedule> { computedSchedule } }); hasChanges = true; } } if (definition.Path != this.Context.DevOpsPath) { definition.Path = this.Context.DevOpsPath; hasChanges = true; } if (definition.Repository.Properties.TryGetValue(ReportBuildStatusKey, out var reportBuildStatusString)) { if (!bool.TryParse(reportBuildStatusString, out var reportBuildStatusValue) || !reportBuildStatusValue) { definition.Repository.Properties[ReportBuildStatusKey] = "true"; hasChanges = true; } } else { definition.Repository.Properties.Add(ReportBuildStatusKey, "true"); hasChanges = true; } return(Task.FromResult(hasChanges)); }
protected virtual Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { bool hasChanges = false; if (EnsureVariableGroups(definition)) { hasChanges = true; } if (EnsureReportBuildStatus(definition)) { hasChanges = true; } if (definition.Path != this.Context.DevOpsPath) { definition.Path = this.Context.DevOpsPath; hasChanges = true; } if (definition.Repository.Properties.TryGetValue(ReportBuildStatusKey, out var reportBuildStatusString)) { if (!bool.TryParse(reportBuildStatusString, out var reportBuildStatusValue) || !reportBuildStatusValue) { definition.Repository.Properties[ReportBuildStatusKey] = "true"; hasChanges = true; } } else { definition.Repository.Properties.Add(ReportBuildStatusKey, "true"); hasChanges = true; } return(Task.FromResult(hasChanges)); }
protected abstract string GetDefinitionName(SdkComponent component);
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { // NOTE: Not happy with this code at all, I'm going to look for a reasonable // API that can do equality comparisons (without having to do all the checks myself). var hasChanges = await base.ApplyConventionAsync(definition, component); var prTrigger = definition.Triggers.OfType <PullRequestTrigger>().SingleOrDefault(); if (prTrigger == null) { definition.Triggers.Add(new PullRequestTrigger() { SettingsSourceType = 1, IsCommentRequiredForPullRequest = true, BranchFilters = new List <string>() { $"+{Context.Branch}" }, Forks = new Forks() { AllowSecrets = true, Enabled = true } }); hasChanges = true; } else { if (prTrigger.SettingsSourceType != 1 || prTrigger.IsCommentRequiredForPullRequest != true || !prTrigger.BranchFilters.All(bf => bf == $"+{Context.Branch}") || prTrigger.Forks.AllowSecrets != true || prTrigger.Forks.Enabled != true) { prTrigger.SettingsSourceType = 1; prTrigger.IsCommentRequiredForPullRequest = true; prTrigger.BranchFilters = new List <string>() { $"+{Context.Branch}" }; prTrigger.Forks.AllowSecrets = true; prTrigger.Forks.Enabled = true; hasChanges = true; } } return(hasChanges); }
private async Task <BuildDefinition> CreateDefinitionAsync(string definitionName, SdkComponent component, CancellationToken cancellationToken) { var sourceRepository = await Context.GetSourceRepositoryAsync(cancellationToken); var buildRepository = new BuildRepository() { DefaultBranch = Context.Branch, Id = sourceRepository.Id, Name = sourceRepository.FullName, Type = "GitHub", Url = new Uri(sourceRepository.Properties["cloneUrl"]), }; buildRepository.Properties.AddRangeIfRangeNotNull(sourceRepository.Properties); var projectReference = await Context.GetProjectReferenceAsync(cancellationToken); var agentPoolQueue = await Context.GetAgentPoolQueue(cancellationToken); var normalizedRelativeYamlPath = component.RelativeYamlPath.Replace("\\", "/"); var definition = new BuildDefinition() { Name = definitionName, Project = projectReference, Path = Context.DevOpsPath, Repository = buildRepository, Process = new YamlProcess() { YamlFilename = normalizedRelativeYamlPath }, Queue = agentPoolQueue }; if (!Context.WhatIf) { Logger.LogDebug("Creating definition named '{0}'.", definitionName); var buildClient = await Context.GetBuildHttpClientAsync(cancellationToken); definition = await buildClient.CreateDefinitionAsync( definition : definition, cancellationToken : cancellationToken ); Logger.LogInformation("Created definition '{0}' at: {1}", definitionName, definition.GetWebUrl()); } else { Logger.LogWarning("Skipping creating definition '{0}' (--whatif).", definitionName); } return(definition); }
protected override Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { // NOTE: Not happy with this code at all, I'm going to look for a reasonable // API that can do equality comparisons (without having to do all the checks myself). var hasChanges = false; if (definition.Path != $"\\{this.Context.Prefix}") { definition.Path = $"\\{this.Context.Prefix}"; hasChanges = true; } var ciTrigger = definition.Triggers.OfType <ContinuousIntegrationTrigger>().SingleOrDefault(); if (ciTrigger == null) { definition.Triggers.Add(new ContinuousIntegrationTrigger() { SettingsSourceType = 2 // HACK: This is editor invisible, but this is required to inherit branch filters from YAML file. }); hasChanges = true; } else { if (ciTrigger.SettingsSourceType != 2) { ciTrigger.SettingsSourceType = 2; hasChanges = true; } } var prTrigger = definition.Triggers.OfType <PullRequestTrigger>().SingleOrDefault(); if (prTrigger == null) { // TODO: We should probably be more complete here. definition.Triggers.Add(new PullRequestTrigger() { SettingsSourceType = 2, // HACK: See above. Forks = new Forks() { AllowSecrets = false, Enabled = true } }); hasChanges = true; } else { // TODO: We should probably be more complete here. if (prTrigger.SettingsSourceType != 2 || prTrigger.Forks.AllowSecrets != false || prTrigger.Forks.Enabled != true) { prTrigger.SettingsSourceType = 2; prTrigger.Forks.AllowSecrets = false; prTrigger.Forks.Enabled = true; hasChanges = true; } } if (definition.Repository.Properties.TryGetValue(ReportBuildStatusKey, out var reportBuildStatusString)) { if (!bool.TryParse(reportBuildStatusString, out var reportBuildStatusValue) || !reportBuildStatusValue) { definition.Repository.Properties[ReportBuildStatusKey] = "true"; hasChanges = true; } } else { definition.Repository.Properties.Add(ReportBuildStatusKey, "true"); hasChanges = true; } return(Task.FromResult(hasChanges)); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { // NOTE: Not happy with this code at all, I'm going to look for a reasonable // API that can do equality comparisons (without having to do all the checks myself). var hasChanges = await base.ApplyConventionAsync(definition, component); // Ensure Schedule Trigger var scheduleTriggers = definition.Triggers.OfType <ScheduleTrigger>(); if (scheduleTriggers == default || !scheduleTriggers.Any()) { var schedule = new Schedule { DaysToBuild = ScheduleDays.All, ScheduleOnlyWithChanges = false, StartHours = StartHourOffset + HashBucket(definition.Name), StartMinutes = 0, TimeZoneId = "Pacific Standard Time", }; schedule.BranchFilters.Add("+master"); definition.Triggers.Add(new ScheduleTrigger { Schedules = new List <Schedule> { schedule } }); hasChanges = true; } var ciTrigger = definition.Triggers.OfType <ContinuousIntegrationTrigger>().SingleOrDefault(); if (ciTrigger == null) { definition.Triggers.Add(new ContinuousIntegrationTrigger() { SettingsSourceType = 2 // HACK: This is editor invisible, but this is required to inherit branch filters from YAML file. }); hasChanges = true; } else { if (ciTrigger.SettingsSourceType != 2) { ciTrigger.SettingsSourceType = 2; hasChanges = true; } } var prTrigger = definition.Triggers.OfType <PullRequestTrigger>().SingleOrDefault(); if (prTrigger == null) { definition.Triggers.Add(new PullRequestTrigger() { SettingsSourceType = 1, // HACK: See above. IsCommentRequiredForPullRequest = true, BranchFilters = new List <string>() { $"+{Context.Branch}" }, Forks = new Forks() { AllowSecrets = true, Enabled = true } }); hasChanges = true; } else { if (prTrigger.SettingsSourceType != 2 || prTrigger.IsCommentRequiredForPullRequest != true || !prTrigger.BranchFilters.All(bf => bf == $"+{Context.Branch}") || prTrigger.Forks.AllowSecrets != true || prTrigger.Forks.Enabled != true) { prTrigger.SettingsSourceType = 2; prTrigger.IsCommentRequiredForPullRequest = true; prTrigger.BranchFilters = new List <string>() { $"+{Context.Branch}" }; prTrigger.Forks.AllowSecrets = true; prTrigger.Forks.Enabled = true; hasChanges = true; } } return(hasChanges); }
public override string GetDefinitionName(SdkComponent component) { return(component.Variant == null ? $"{Context.Prefix} - {component.Name} - ci" : $"{Context.Prefix} - {component.Name} - ci.{component.Variant}"); }
protected override string GetDefinitionName(SdkComponent component) { return($"{Context.Prefix} - {component.Name} - tests"); }
public abstract string GetDefinitionName(SdkComponent component);
protected override string GetDefinitionName(SdkComponent component) { return(component.Variant == null ? $"{Context.Prefix} - {component.Name} - tests" : $"{Context.Prefix} - {component.Name} - tests.{component.Variant}"); }
protected override Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { var hasChanges = false; // Ensure Path if (definition.Path != this.Context.DevOpsPath) { definition.Path = this.Context.DevOpsPath; hasChanges = true; } // Ensure Schedule Trigger var scheduleTriggers = definition.Triggers.OfType <ScheduleTrigger>(); if (scheduleTriggers == default || !scheduleTriggers.Any()) { var schedule = new Schedule { DaysToBuild = ScheduleDays.All, ScheduleOnlyWithChanges = false, StartHours = StartHourOffset + HashBucket(definition.Name), StartMinutes = 0, TimeZoneId = "Pacific Standard Time", }; schedule.BranchFilters.Add("+master"); definition.Triggers.Add(new ScheduleTrigger { Schedules = new List <Schedule> { schedule } }); hasChanges = true; } // Ensure PR trigger var prTriggers = definition.Triggers.OfType <PullRequestTrigger>(); if (prTriggers == default || !prTriggers.Any()) { var newTrigger = GetDefaultPrTrigger(); definition.Triggers.Add(newTrigger); hasChanges = true; } else { foreach (var trigger in prTriggers) { if (EnsurePrTriggerDefaults(trigger)) { hasChanges = true; } } } // Ensure Variable Group if (EnsureVariableGroups(definition)) { hasChanges = true; } // Ensure "Report Build Status" is set if (EnsureReportBuildStatus(definition)) { hasChanges = true; } return(Task.FromResult(hasChanges)); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { // NOTE: Not happy with this code at all, I'm going to look for a reasonable // API that can do equality comparisons (without having to do all the checks myself). var hasChanges = await base.ApplyConventionAsync(definition, component); var ciTrigger = definition.Triggers.OfType <ContinuousIntegrationTrigger>().SingleOrDefault(); if (ciTrigger == null) { definition.Triggers.Add(new ContinuousIntegrationTrigger() { SettingsSourceType = 2 // HACK: This is editor invisible, but this is required to inherit branch filters from YAML file. }); hasChanges = true; } else { if (ciTrigger.SettingsSourceType != 2) { ciTrigger.SettingsSourceType = 2; hasChanges = true; } } var prTrigger = definition.Triggers.OfType <PullRequestTrigger>().SingleOrDefault(); if (prTrigger == null) { // TODO: We should probably be more complete here. definition.Triggers.Add(new PullRequestTrigger() { SettingsSourceType = 2, // HACK: See above. Forks = new Forks() { AllowSecrets = false, Enabled = true } }); hasChanges = true; } else { // TODO: We should probably be more complete here. if (prTrigger.SettingsSourceType != 2 || prTrigger.Forks.AllowSecrets != false || prTrigger.Forks.Enabled != true) { prTrigger.SettingsSourceType = 2; prTrigger.Forks.AllowSecrets = false; prTrigger.Forks.Enabled = true; hasChanges = true; } } return(hasChanges); }
private async Task <BuildDefinition> CreateDefinitionAsync(string definitionName, SdkComponent component, CancellationToken cancellationToken) { var serviceEndpoint = await Context.GetServiceEndpointAsync(cancellationToken); var repository = Context.Repository; var buildRepository = new BuildRepository { DefaultBranch = Context.Branch, Id = repository, Name = repository, Type = "GitHub", Url = new Uri($"https://github.com/{repository}.git"), Properties = { ["connectedServiceId"] = serviceEndpoint.Id.ToString() } }; var projectReference = await Context.GetProjectReferenceAsync(cancellationToken); var agentPoolQueue = await Context.GetAgentPoolQueue(cancellationToken); var normalizedRelativeYamlPath = component.RelativeYamlPath.Replace("\\", "/"); var definition = new BuildDefinition() { Name = definitionName, Project = projectReference, Path = Context.DevOpsPath, Repository = buildRepository, Process = new YamlProcess() { YamlFilename = normalizedRelativeYamlPath }, Queue = agentPoolQueue }; if (!Context.WhatIf) { Logger.LogDebug("Creating definition named '{0}'.", definitionName); var buildClient = await Context.GetBuildHttpClientAsync(cancellationToken); definition = await buildClient.CreateDefinitionAsync( definition : definition, cancellationToken : cancellationToken ); Logger.LogInformation("Created definition '{0}' at: {1}", definitionName, definition.GetWebUrl()); } else { Logger.LogWarning("Skipping creating definition '{0}' (--whatif).", definitionName); } return(definition); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { // NOTE: Not happy with this code at all, I'm going to look for a reasonable // API that can do equality comparisons (without having to do all the checks myself). var hasChanges = await base.ApplyConventionAsync(definition, component); for (int i = definition.Triggers.Count - 1; i >= 0; i--) { if (definition.Triggers[i] is ContinuousIntegrationTrigger) { definition.Triggers.RemoveAt(i); hasChanges = true; } } var prTrigger = definition.Triggers.OfType <PullRequestTrigger>().SingleOrDefault(); if (prTrigger == null) { // TODO: We should probably be more complete here. definition.Triggers.Add(new PullRequestTrigger() { SettingsSourceType = 2, // HACK: See above. Forks = new Forks() { AllowSecrets = false, Enabled = true } }); hasChanges = true; } else { // TODO: We should probably be more complete here. if (prTrigger.SettingsSourceType != 2 || prTrigger.Forks.AllowSecrets != false || prTrigger.Forks.Enabled != true) { prTrigger.SettingsSourceType = 2; prTrigger.Forks.AllowSecrets = false; prTrigger.Forks.Enabled = true; hasChanges = true; } } return(hasChanges); }
protected virtual Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { bool hasChanges = false; if (EnsureVariableGroups(definition)) { hasChanges = true; } if (EnsureReportBuildStatus(definition)) { hasChanges = true; } if (IsScheduled) { var scheduleTriggers = definition.Triggers.OfType <ScheduleTrigger>(); // Only add the schedule trigger if one doesn't exist. if (scheduleTriggers == default || !scheduleTriggers.Any()) { var computedSchedule = CreateScheduleFromDefinition(definition); definition.Triggers.Add(new ScheduleTrigger { Schedules = new List <Schedule> { computedSchedule } }); hasChanges = true; } } if (RemoveCITriggers) { for (int i = definition.Triggers.Count - 1; i >= 0; i--) { if (definition.Triggers[i] is ContinuousIntegrationTrigger) { definition.Triggers.RemoveAt(i); hasChanges = true; } } } if (definition.Path != this.Context.DevOpsPath) { definition.Path = this.Context.DevOpsPath; hasChanges = true; } if (definition.Repository.Properties.TryGetValue(ReportBuildStatusKey, out var reportBuildStatusString)) { if (!bool.TryParse(reportBuildStatusString, out var reportBuildStatusValue) || !reportBuildStatusValue) { definition.Repository.Properties[ReportBuildStatusKey] = "true"; hasChanges = true; } } else { definition.Repository.Properties.Add(ReportBuildStatusKey, "true"); hasChanges = true; } return(Task.FromResult(hasChanges)); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { var hasChanges = await base.ApplyConventionAsync(definition, component); if (EnsureDefaultPullRequestTrigger(definition, overrideYaml: false, securePipeline: false)) { hasChanges = true; } if (EnsureDefaultCITrigger(definition)) { hasChanges = true; } return(hasChanges); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { var hasChanges = await base.ApplyConventionAsync(definition, component); // Ensure Schedule Trigger var scheduleTriggers = definition.Triggers.OfType <ScheduleTrigger>(); if (scheduleTriggers == default || !scheduleTriggers.Any()) { var schedule = new Schedule { DaysToBuild = ScheduleDays.All, ScheduleOnlyWithChanges = false, StartHours = StartHourOffset + HashBucket(definition.Name), StartMinutes = 0, TimeZoneId = "Pacific Standard Time", }; schedule.BranchFilters.Add("+master"); definition.Triggers.Add(new ScheduleTrigger { Schedules = new List <Schedule> { schedule } }); hasChanges = true; } // Ensure PR trigger var prTriggers = definition.Triggers.OfType <PullRequestTrigger>(); if (prTriggers == default || !prTriggers.Any()) { var newTrigger = GetDefaultPrTrigger(); definition.Triggers.Add(newTrigger); hasChanges = true; } else { foreach (var trigger in prTriggers) { if (EnsurePrTriggerDefaults(trigger)) { hasChanges = true; } } } return(hasChanges); }
protected override async Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component) { var hasChanges = await base.ApplyConventionAsync(definition, component); // Ensure PR trigger var prTriggers = definition.Triggers.OfType <PullRequestTrigger>(); if (prTriggers == default || !prTriggers.Any()) { var newTrigger = GetDefaultPrTrigger(); definition.Triggers.Add(newTrigger); hasChanges = true; } else { foreach (var trigger in prTriggers) { if (EnsurePrTriggerDefaults(trigger)) { hasChanges = true; } } } return(hasChanges); }
protected abstract Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component);