Example #1
0
        public IEnumerable <SdkComponent> Scan(DirectoryInfo path, string searchPattern)
        {
            string variantPattern = searchPattern.Replace(".yml", "\\.(?<variant>([a-z]+))\\.yml");
            Regex  variantExtractionExpression = new Regex($"^{variantPattern}$");

            Logger.LogDebug($"Scanning directory '{path.FullName}' for components with search pattern '{searchPattern}' variant pattern '{variantPattern}'");

            if (!path.Exists)
            {
                throw new ArgumentException(nameof(path), "Path does not exist.");
            }

            var pipelineYamlFiles = path.EnumerateFiles(searchPattern, SearchOption.AllDirectories);

            pipelineYamlFiles = pipelineYamlFiles.Concat(path.EnumerateFiles(searchPattern.Replace(".yml", ".*.yml"), SearchOption.AllDirectories));

            if (pipelineYamlFiles.Count() == 0)
            {
                Logger.LogWarning("Did not find any YAML files with search pattern '{0}' in path '{1}'.", searchPattern, path.FullName);
            }

            Logger.LogDebug("Finding repository root from '{0}'.", path.FullName);
            var repositoryHelper = new RepositoryHelper();
            var root             = repositoryHelper.GetRepositoryRoot(path);

            Logger.LogDebug("Found repository root at: {0}", root);

            foreach (var pipelineYamlFile in pipelineYamlFiles)
            {
                var relativePath = Path.GetRelativePath(root, pipelineYamlFile.FullName);
                Logger.LogDebug("Repository root relative path for '{0}' is: {1}", pipelineYamlFile, relativePath);

                var component = new SdkComponent()
                {
                    Name             = pipelineYamlFile.Directory.Name,
                    Path             = pipelineYamlFile.Directory,
                    RelativeYamlPath = relativePath
                };

                // Append variant information.
                if (variantExtractionExpression.IsMatch(pipelineYamlFile.Name))
                {
                    var match   = variantExtractionExpression.Match(pipelineYamlFile.Name);
                    var variant = match.Groups["variant"].Value;
                    component.Variant = variant;
                    Logger.LogDebug($"variant = {variant}");
                }

                yield return(component);
            }
        }
        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 = 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 IEnumerable <SdkComponent> Scan(DirectoryInfo path, string searchPattern)
        {
            Logger.LogDebug("Scanning directory '{0}' for components with search pattern '{1}'.", path.FullName, searchPattern);

            if (!path.Exists)
            {
                throw new ArgumentException(nameof(path), "Path does not exist.");
            }

            var pipelineYamlFiles = path.EnumerateFiles(searchPattern, SearchOption.AllDirectories);

            if (pipelineYamlFiles.Count() == 0)
            {
                Logger.LogWarning("Did not find any YAML files with search pattern '{0}' in path '{1}'.", searchPattern, path.FullName);
            }

            Logger.LogDebug("Finding repository root from '{0}'.", path.FullName);
            var repositoryHelper = new RepositoryHelper();
            var root             = repositoryHelper.GetRepositoryRoot(path);

            Logger.LogDebug("Found repository root at: {0}", root);

            foreach (var pipelineYamlFile in pipelineYamlFiles)
            {
                var relativePath = Path.GetRelativePath(root, pipelineYamlFile.FullName);
                Logger.LogDebug("Repository root relative path for '{0}' is: {1}", pipelineYamlFile, relativePath);

                var component = new SdkComponent()
                {
                    Name             = pipelineYamlFile.Directory.Name,
                    Path             = pipelineYamlFile.Directory,
                    RelativeYamlPath = relativePath
                };

                yield return(component);
            }
        }
        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 async override Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component)
        {
            // Daniel - your custom logic goes here.!

            return(false);
        }
 protected override string GetDefinitionName(SdkComponent component)
 {
     return($"{Context.Prefix} - {component.Name} - tests");
 }
Example #7
0
        protected async 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;

            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);
        }
 protected abstract string GetDefinitionName(SdkComponent component);
 protected abstract Task <bool> ApplyConventionAsync(BuildDefinition definition, SdkComponent component);
        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 definition = new BuildDefinition()
            {
                Name       = definitionName,
                Project    = projectReference,
                Repository = buildRepository,
                Process    = new YamlProcess()
                {
                    YamlFilename = component.RelativeYamlPath
                },
                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);
        }