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);
        }