public bool IsProductDependency(
            string sourceRepositoryName,
            string sourceBranchName,
            string targetRepositoryName,
            string targetBranchName)
        {
            // Take latest target builds ordered by DateProduced
            var latestTargetBuildsQuery = Builds
                                          .Where(b =>
                                                 (b.GitHubRepository == targetRepositoryName && b.GitHubBranch == targetBranchName) ||
                                                 (b.AzureDevOpsRepository == targetRepositoryName && b.AzureDevOpsBranch == targetBranchName))
                                          .OrderByDescending(b => b.DateProduced);

            // For each build return its Id and HasProductDependencies flag saying
            // if there are any build dependencies in this build that come from source
            // and have IsProduct flag set.
            var buildDependenciesQuery = latestTargetBuildsQuery
                                         .Select(b => new
            {
                Id = b.Id,
                HasProductDependencies = BuildDependencies
                                         .Any(d =>
                                              ((d.DependentBuild.GitHubRepository == sourceRepositoryName &&
                                                d.DependentBuild.GitHubBranch == sourceBranchName) ||
                                               (d.DependentBuild.AzureDevOpsRepository == sourceRepositoryName &&
                                                d.DependentBuild.AzureDevOpsBranch == sourceBranchName)) &&
                                              d.Build == b &&
                                              d.IsProduct)
            });

            // Take the most recent build. Can be null if there are no target builds yet.
            var latestBuild = buildDependenciesQuery.FirstOrDefault();

            return(latestBuild?.HasProductDependencies ?? false);
        }
Example #2
0
        /// Returns all the affected projects of the given list of projects.
        /// Since the roots may refer to each other, the roots are included in the result set.
        public static Project[] AffectedProjects(this BuildDependencies dependencies, Project[] all, Project[] roots)
        {
            var dependentMap = DependentMap(dependencies, all);
            var allKeys      = all.ToDictionary(GetProjectKey);
            var rootGuids    = roots.Select(GetProjectKey).ToArray();
            var todo         = new Queue <string>(rootGuids);
            var affected     = new HashSet <string>(rootGuids);

            while (todo.Count != 0)
            {
                var next = todo.Dequeue();

                if (!dependentMap.TryGetValue(next, out var dependents))
                {
                    continue;
                }

                dependents.ForEach(dep => {
                    if (affected.Add(dep))
                    {
                        todo.Enqueue(dep);
                    }
                });
            }

            return(affected.Select(g => allKeys[g]).ToArray());
        }
 public BuildRequest(
     BuildDependencies dependencies,
     Project[] primaryProjects,
     Project[] skippedProjects,
     string solutionConfiguration,
     string solutionPlatform,
     SolutionContexts solutionContexts,
     (string, string)[] solutionProperties
Example #4
0
        public async Task <IList <Build> > GetBuildGraphAsync(int buildId)
        {
            var dependencyEntity       = Model.FindEntityType(typeof(BuildDependency));
            var buildIdColumnName      = dependencyEntity.FindProperty(nameof(BuildDependency.BuildId)).Relational().ColumnName;
            var dependencyIdColumnName = dependencyEntity.FindProperty(nameof(BuildDependency.DependentBuildId)).Relational().ColumnName;
            var isProductColumnName    = dependencyEntity.FindProperty(nameof(BuildDependency.IsProduct)).Relational().ColumnName;
            var edgeTable = dependencyEntity.Relational().TableName;

            var edges = BuildDependencies.FromSql($@"
WITH traverse AS (
        SELECT
            {buildIdColumnName},
            {dependencyIdColumnName},
            {isProductColumnName},
            0 as Depth
        from {edgeTable}
        WHERE {buildIdColumnName} = @id
    UNION ALL
        SELECT
            {edgeTable}.{buildIdColumnName},
            {edgeTable}.{dependencyIdColumnName},
            {edgeTable}.{isProductColumnName},
            traverse.Depth + 1
        FROM {edgeTable}
        INNER JOIN traverse
        ON {edgeTable}.{buildIdColumnName} = traverse.{dependencyIdColumnName}
        WHERE traverse.{isProductColumnName} = 1 -- The thing we previously traversed was a product dependency
            AND traverse.Depth < 10 -- Don't load all the way back because of incorrect isProduct columns
)
SELECT DISTINCT {buildIdColumnName}, {dependencyIdColumnName}, {isProductColumnName}
FROM traverse;",
                                                  new SqlParameter("id", buildId));

            List <BuildDependency> things = await edges.ToListAsync();

            var buildIds = new HashSet <int>(things.SelectMany(t => new[] { t.BuildId, t.DependentBuildId }));

            buildIds.Add(buildId); // Make sure we always include the requested build, even if it has no edges.

            IQueryable <Build> builds = from build in Builds
                                        where buildIds.Contains(build.Id)
                                        select build;

            Dictionary <int, Build> dict = await builds.ToDictionaryAsync(b => b.Id,
                                                                          b =>
            {
                b.DependentBuildIds = new List <BuildDependency>();
                return(b);
            });

            foreach (var edge in things)
            {
                dict[edge.BuildId].DependentBuildIds.Add(edge);
            }

            return(dict.Values.ToList());
        }
Example #5
0
        /// Returns the keys of the direct dependencies of a project.
        public static string[] DependentProjectKeys(BuildDependencies dependencies, Project project)
        {
            var dependency = dependencies.Item(project.UniqueName);

            return(((IEnumerable)dependency.RequiredProjects)
                   .Cast <Project>()
                   .Select(rp => rp.UniqueName)
                   .ToArray());
        }
 public bool IsProductDependency(int buildId, string repositoryName, string branchName)
 {
     return(BuildDependencies
            .Any(d => d.IsProduct &&
                 d.DependentBuildId == buildId &&
                 ((d.Build.GitHubRepository == repositoryName &&
                   d.Build.GitHubBranch == branchName) ||
                  (d.Build.AzureDevOpsRepository == repositoryName &&
                   d.Build.AzureDevOpsBranch == branchName))));
 }
Example #7
0
        public static Project[] SortByBuildOrder(BuildDependencies dependencies, Project[] instances)
        {
            var rootProjects = instances.ToDictionary(GetProjectKey);

            var ordered =
                rootProjects.Keys.SortTopologicallyReverse(key =>
                                                           DependentProjectKeys(dependencies, rootProjects[key])
                                                           .Where(rootProjects.ContainsKey));

            return(ordered.Select(key => rootProjects[key]).ToArray());
        }
 public BuildRequest(
     BuildDependencies dependencies,
     Project[] primaryProjects,
     Project[] skippedProjects,
     string solutionConfiguration,
     string solutionPlatform,
     SolutionContexts solutionContexts,
     string SolutionDir)
 {
     var allProjects = primaryProjects.Concat(skippedProjects).ToArray();
     var allOrdered  = Projects.SortByBuildOrder(dependencies, allProjects);
     Dictionary <string, (string, string)[]> fixedProjectProperties = new Dictionary <string, (string, string)[]>();
Example #9
0
        /// Returns the keys of the direct dependencies of a project.
        public static string[] DependentProjectKeys(BuildDependencies dependencies, Project project)
        {
            var uniqueName = project.UniqueName;
            var dependency = dependencies.Item(uniqueName);

            // dependency might be null, see #52.
            if (dependency == null)
            {
                return(new string[0]);
            }
            return(((IEnumerable)dependency.RequiredProjects)
                   .Cast <Project>()
                   .Select(rp => rp.UniqueName)
                   .ToArray());
        }
Example #10
0
        // dependencies calculated during built
        // This will be updated when it rebuilt
        public ResultCode AddBuildDependency(Asset dependency)
        {
            // Skip if they are already depend on each other
            if (Dependencies.Contains(dependency.Dependencies))
            {
                return(new ResultCode(ResultCode.SUCCESS));
            }

            var result = BuildDependencies.AddDependency(dependency.BuildDependencies);

            if (!result.IsSuccessed())
            {
                ToolDebug.Error("Add dependency is failed: {0} <-> {1}", Name, dependency.Name);
                return(result);
            }

            return(new ResultCode(ResultCode.SUCCESS));
        }
Example #11
0
        public static Dictionary <string, HashSet <string> > DependentMap(BuildDependencies dependencies, Project[] all)
        {
            var allKeys = all.ToDictionary(GetProjectKey);
            var dict    = new Dictionary <string, HashSet <string> >();

            foreach (var project in all)
            {
                var key  = project.GetProjectKey();
                var deps = DependentProjectKeys(dependencies, project).Where(allKeys.ContainsKey).ToArray();
                foreach (var dep in deps)
                {
                    if (!dict.TryGetValue(dep, out var dependents))
                    {
                        dependents = new HashSet <string>();
                        dict.Add(dep, dependents);
                    }
                    dependents.Add(key);
                }
            }
            return(dict);
        }
Example #12
0
        /// Returns all the dependencies of a number of projects (direct and transitive).
        /// Never returns a root, even if roots hold references to each other.
        public static Project[] Dependencies(BuildDependencies buildDependencies, Project[] allProjects, Project[] roots)
        {
            var allKeys      = allProjects.ToDictionary(GetProjectKey);
            var todo         = new Queue <string>(roots.Select(GetProjectKey));
            var rootSet      = new HashSet <string>(roots.Select(GetProjectKey));
            var dependencies = new HashSet <string>();

            while (todo.Count != 0)
            {
                var next = todo.Dequeue();

                DependentProjectKeys(buildDependencies, allKeys[next])
                .Where(g => !dependencies.Contains(g) && !rootSet.Contains(g) && allKeys.ContainsKey(g))
                .ForEach(g =>
                {
                    todo.Enqueue(g);
                    dependencies.Add(g);
                });
            }

            return(dependencies
                   .Select(g => allKeys[g])
                   .ToArray());
        }
Example #13
0
        public async Task <IList <Build> > GetBuildGraphAsync(int buildId)
        {
            var dependencyEntity                   = Model.FindEntityType(typeof(BuildDependency));
            var buildIdColumnName                  = dependencyEntity.FindProperty(nameof(BuildDependency.BuildId)).Relational().ColumnName;
            var dependencyIdColumnName             = dependencyEntity.FindProperty(nameof(BuildDependency.DependentBuildId)).Relational().ColumnName;
            var isProductColumnName                = dependencyEntity.FindProperty(nameof(BuildDependency.IsProduct)).Relational().ColumnName;
            var timeToInclusionInMinutesColumnName = dependencyEntity.FindProperty(nameof(BuildDependency.TimeToInclusionInMinutes)).Relational().ColumnName;
            var edgeTable = dependencyEntity.Relational().TableName;

            var edges = BuildDependencies.FromSql($@"
WITH traverse AS (
        SELECT
            {buildIdColumnName},
            {dependencyIdColumnName},
            {isProductColumnName},
            {timeToInclusionInMinutesColumnName},
            0 as Depth
        from {edgeTable}
        WHERE {buildIdColumnName} = @id
    UNION ALL
        SELECT
            {edgeTable}.{buildIdColumnName},
            {edgeTable}.{dependencyIdColumnName},
            {edgeTable}.{isProductColumnName},
            {edgeTable}.{timeToInclusionInMinutesColumnName},
            traverse.Depth + 1
        FROM {edgeTable}
        INNER JOIN traverse
        ON {edgeTable}.{buildIdColumnName} = traverse.{dependencyIdColumnName}
        WHERE traverse.{isProductColumnName} = 1 -- The thing we previously traversed was a product dependency
            AND traverse.Depth < 10 -- Don't load all the way back because of incorrect isProduct columns
)
SELECT DISTINCT {buildIdColumnName}, {dependencyIdColumnName}, {isProductColumnName}, {timeToInclusionInMinutesColumnName}
FROM traverse;",
                                                  new SqlParameter("id", buildId));

            List <BuildDependency> things = await edges.ToListAsync();

            var buildIds = new HashSet <int>(things.SelectMany(t => new[] { t.BuildId, t.DependentBuildId }));

            buildIds.Add(buildId); // Make sure we always include the requested build, even if it has no edges.

            IQueryable <Build> builds = from build in Builds
                                        where buildIds.Contains(build.Id)
                                        select build;

            Dictionary <int, Build> dict = await builds.ToDictionaryAsync(b => b.Id,
                                                                          b =>
            {
                b.DependentBuildIds = new List <BuildDependency>();
                return(b);
            });

            foreach (var edge in things)
            {
                dict[edge.BuildId].DependentBuildIds.Add(edge);
            }

            // Gather subscriptions used by this build.
            Build primaryBuild       = Builds.First(b => b.Id == buildId);
            var   validSubscriptions = await Subscriptions.Where(s => (s.TargetRepository == primaryBuild.AzureDevOpsRepository || s.TargetRepository == primaryBuild.GitHubRepository) &&
                                                                 (s.TargetBranch == primaryBuild.AzureDevOpsBranch || s.TargetBranch == primaryBuild.GitHubBranch ||
                                                                  $"refs/heads/{s.TargetBranch}" == primaryBuild.AzureDevOpsBranch || $"refs/heads/{s.TargetBranch}" == primaryBuild.GitHubBranch)).ToListAsync();

            // Use the subscriptions to determine what channels are relevant for this build, so just grab the unique channel ID's from valid suscriptions
            var channelIds = validSubscriptions.GroupBy(x => x.ChannelId).Select(y => y.First()).Select(s => s.ChannelId);

            // Acquire list of builds in valid channels
            var channelBuildIds = await BuildChannels.Where(b => channelIds.Any(c => c == b.ChannelId)).Select(s => s.BuildId).ToListAsync();

            var possibleBuilds = await Builds.Where(b => channelBuildIds.Any(c => c == b.Id)).ToListAsync();

            // Calculate total number of builds that are newer.
            foreach (var id in dict.Keys)
            {
                var build = dict[id];
                // Get newer builds data for this channel.
                var newer = possibleBuilds.Where(b => b.GitHubRepository == build.GitHubRepository &&
                                                 b.AzureDevOpsRepository == build.AzureDevOpsRepository &&
                                                 b.DateProduced > build.DateProduced);
                dict[id].Staleness = newer.Count();
            }
            return(dict.Values.ToList());
        }
Example #14
0
 public BuildDependenciesNodeFactory(BuildDependencies buildDependencies)
 {
     _buildDependencies = buildDependencies;
 }