private async Task <WebApiTeam> EnsureTeamExists( BuildDefinition pipeline, string suffix, TeamPurpose purpose, IEnumerable <WebApiTeam> teams, bool persistChanges) { // Ensure team name fits within maximum 64 character limit // https://docs.microsoft.com/en-us/azure/devops/organizations/settings/naming-restrictions?view=azure-devops#teams string teamName = StringHelper.MaxLength($"{pipeline.Name} -- {suffix}", MaxTeamNameLength); bool updateMetadataAndName = false; var result = teams.FirstOrDefault( team => { // Swallowing exceptions because parse errors on // free form text fields which might be non-yaml text // are not exceptional var metadata = YamlHelper.Deserialize <TeamMetadata>(team.Description, swallowExceptions: true); bool metadataMatches = (metadata?.PipelineId == pipeline.Id && metadata?.Purpose == purpose); bool nameMatches = (team.Name == teamName); if (metadataMatches && nameMatches) { return(true); } if (metadataMatches) { logger.LogInformation("Found team with matching pipeline id {0} but different name '{1}', expected '{2}'. Purpose = '{3}'", metadata?.PipelineId, team.Name, teamName, metadata?.Purpose); updateMetadataAndName = true; return(true); } if (nameMatches) { logger.LogInformation("Found team with matching name {0} but different pipeline id {1}, expected {2}. Purpose = '{3}'", team.Name, metadata?.PipelineId, pipeline.Id, metadata?.Purpose); updateMetadataAndName = true; return(true); } return(false); }); if (result == default) { logger.LogInformation("Team Not Found Suffix = {0}", suffix); var teamMetadata = new TeamMetadata { PipelineId = pipeline.Id, Purpose = purpose, }; var newTeam = new WebApiTeam { Description = YamlHelper.Serialize(teamMetadata), Name = teamName }; logger.LogInformation("Create Team for Pipeline PipelineId = {0} Purpose = {1} Name = '{2}'", pipeline.Id, purpose, teamName); if (persistChanges) { result = await service.CreateTeamForProjectAsync(pipeline.Project.Id.ToString(), newTeam); } } else if (updateMetadataAndName) { var teamMetadata = new TeamMetadata { PipelineId = pipeline.Id, Purpose = purpose, }; result.Description = YamlHelper.Serialize(teamMetadata); result.Name = teamName; logger.LogInformation("Update Team for Pipeline PipelineId = {0} Purpose = {1} Name = '{2}'", pipeline.Id, purpose, teamName); if (persistChanges) { result = await service.UpdateTeamForProjectAsync(pipeline.Project.Id.ToString(), result); } } return(result); }
private async Task <WebApiTeam> EnsureTeamExists( BuildDefinition pipeline, TeamPurpose purpose, IEnumerable <WebApiTeam> teams, GitHubToAADConverter gitHubToAADConverter, bool persistChanges) { string teamName = $"{pipeline.Id} "; if (purpose == TeamPurpose.ParentNotificationTeam) { // Ensure team name fits within maximum 64 character limit // https://docs.microsoft.com/en-us/azure/devops/organizations/settings/naming-restrictions?view=azure-devops#teams string fullTeamName = teamName + $"{pipeline.Name}"; teamName = StringHelper.MaxLength(fullTeamName, MaxTeamNameLength); if (fullTeamName.Length > teamName.Length) { logger.LogWarning($"Notification team name (length {fullTeamName.Length}) will be truncated to {teamName}"); } } else if (purpose == TeamPurpose.SynchronizedNotificationTeam) { teamName += $"Code owners sync notifications"; } bool updateMetadataAndName = false; var result = teams.FirstOrDefault( team => { // Swallowing exceptions because parse errors on // free form text fields which might be non-yaml text // are not exceptional var metadata = YamlHelper.Deserialize <TeamMetadata>(team.Description, swallowExceptions: true); bool metadataMatches = (metadata?.PipelineId == pipeline.Id && metadata?.Purpose == purpose); bool nameMatches = (team.Name == teamName); if (metadataMatches && nameMatches) { return(true); } if (metadataMatches) { logger.LogInformation("Found team with matching pipeline id {0} but different name '{1}', expected '{2}'. Purpose = '{3}'", metadata?.PipelineId, team.Name, teamName, metadata?.Purpose); updateMetadataAndName = true; return(true); } if (nameMatches) { logger.LogInformation("Found team with matching name {0} but different pipeline id {1}, expected {2}. Purpose = '{3}'", team.Name, metadata?.PipelineId, pipeline.Id, metadata?.Purpose); updateMetadataAndName = true; return(true); } return(false); }); if (result == default) { logger.LogInformation("Team Not Found purpose = {0}", purpose); var teamMetadata = new TeamMetadata { PipelineId = pipeline.Id, Purpose = purpose, PipelineName = pipeline.Name, }; var newTeam = new WebApiTeam { Description = YamlHelper.Serialize(teamMetadata), Name = teamName }; logger.LogInformation("Create Team for Pipeline PipelineId = {0} Purpose = {1} Name = '{2}'", pipeline.Id, purpose, teamName); if (persistChanges) { result = await service.CreateTeamForProjectAsync(pipeline.Project.Id.ToString(), newTeam); if (purpose == TeamPurpose.ParentNotificationTeam) { await EnsureScheduledBuildFailSubscriptionExists(pipeline, result, true); } } } else if (updateMetadataAndName) { var teamMetadata = new TeamMetadata { PipelineId = pipeline.Id, Purpose = purpose, }; result.Description = YamlHelper.Serialize(teamMetadata); result.Name = teamName; logger.LogInformation("Update Team for Pipeline PipelineId = {0} Purpose = {1} Name = '{2}'", pipeline.Id, purpose, teamName); if (persistChanges) { result = await service.UpdateTeamForProjectAsync(pipeline.Project.Id.ToString(), result); if (purpose == TeamPurpose.ParentNotificationTeam) { await EnsureScheduledBuildFailSubscriptionExists(pipeline, result, true); } } } if (purpose == TeamPurpose.SynchronizedNotificationTeam) { await SyncTeamWithCodeOwnerFile(pipeline, result, gitHubToAADConverter, gitHubService, persistChanges); } return(result); }