public async Task UpdateLongestBuildPathAsync(CancellationToken cancellationToken)
        {
            using (Logger.BeginScope($"Updating Longest Build Path table"))
            {
                List <Channel> channels = Context.Channels.Select(c => new Channel()
                {
                    Id = c.Id, Name = c.Name
                }).ToList();

                // Get the flow graph
                IRemote barOnlyRemote = await RemoteFactory.GetBarOnlyRemoteAsync(Logger);

                List <Microsoft.DotNet.Maestro.Client.Models.DefaultChannel> defaultChannels = (await barOnlyRemote.GetDefaultChannelsAsync()).ToList();
                List <Microsoft.DotNet.Maestro.Client.Models.Subscription>   subscriptions   = (await barOnlyRemote.GetSubscriptionsAsync()).ToList();

                IEnumerable <string> frequencies = new[] { "everyWeek", "twiceDaily", "everyDay", "everyBuild", "none", };

                Logger.LogInformation($"Will update '{channels.Count}' channels");

                foreach (var channel in channels)
                {
                    // Build, then prune out what we don't want to see if the user specified channels.
                    DependencyFlowGraph flowGraph = await DependencyFlowGraph.BuildAsync(defaultChannels, subscriptions, barOnlyRemote, 30);

                    flowGraph.PruneGraph(
                        node => DependencyFlowGraph.IsInterestingNode(channel.Name, node),
                        edge => DependencyFlowGraph.IsInterestingEdge(edge, false, frequencies));

                    if (flowGraph.Nodes.Count > 0)
                    {
                        flowGraph.MarkBackEdges();
                        flowGraph.CalculateLongestBuildPaths();
                        flowGraph.MarkLongestBuildPath();

                        // Get the nodes on the longest path and order them by path time so that the
                        // contributing repos are in the right order
                        List <DependencyFlowNode> longestBuildPathNodes = flowGraph.Nodes
                                                                          .Where(n => n.OnLongestBuildPath)
                                                                          .OrderByDescending(n => n.BestCasePathTime)
                                                                          .ToList();

                        LongestBuildPath lbp = new LongestBuildPath()
                        {
                            ChannelId                = channel.Id,
                            BestCaseTimeInMinutes    = longestBuildPathNodes.Max(n => n.BestCasePathTime),
                            WorstCaseTimeInMinutes   = longestBuildPathNodes.Max(n => n.WorstCasePathTime),
                            ContributingRepositories = String.Join(';', longestBuildPathNodes.Select(n => $"{n.Repository}@{n.Branch}").ToArray()),
                            ReportDate               = DateTimeOffset.UtcNow,
                        };

                        Logger.LogInformation($"Will update {channel.Name} to best case time {lbp.BestCaseTimeInMinutes} and worst case time {lbp.WorstCaseTimeInMinutes}");
                        await Context.LongestBuildPaths.AddAsync(lbp);
                    }
                }

                await Context.SaveChangesAsync();
            }
        }
        public override async Task <int> ExecuteAsync()
        {
            try
            {
                RemoteFactory remoteFactory = new RemoteFactory(_options);
                var           barOnlyRemote = await remoteFactory.GetBarOnlyRemoteAsync(Logger);

                List <DefaultChannel> defaultChannels = (await barOnlyRemote.GetDefaultChannelsAsync()).ToList();
                defaultChannels.Add(
                    new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                {
                    Branch  = "master",
                    Channel = await barOnlyRemote.GetChannelAsync(".NET Tools - Latest")
                }
                    );
                defaultChannels.Add(
                    new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                {
                    Branch  = "release/3.x",
                    Channel = await barOnlyRemote.GetChannelAsync(".NET 3 Tools")
                }
                    );
                List <Subscription> subscriptions = (await barOnlyRemote.GetSubscriptionsAsync()).ToList();

                // Build, then prune out what we don't want to see if the user specified
                // channels.
                DependencyFlowGraph flowGraph = DependencyFlowGraph.Build(defaultChannels, subscriptions);

                Channel targetChannel = null;
                if (!string.IsNullOrEmpty(_options.Channel))
                {
                    // Resolve the channel.
                    targetChannel = await UxHelpers.ResolveSingleChannel(barOnlyRemote, _options.Channel);

                    if (targetChannel == null)
                    {
                        return(Constants.ErrorCode);
                    }
                }

                if (targetChannel != null)
                {
                    flowGraph.PruneGraph(node => IsInterestingNode(targetChannel, node), edge => IsInterestingEdge(edge));
                }

                await LogGraphViz(targetChannel, flowGraph);

                return(Constants.SuccessCode);
            }
            catch (Exception exc)
            {
                Logger.LogError(exc, "Something failed while getting the dependency graph.");
                return(Constants.ErrorCode);
            }
        }
Beispiel #3
0
        public async Task <IActionResult> GetFlowGraphAsync(
            int channelId = 0,
            bool includeDisabledSubscriptions = false,
#pragma warning disable API0001 // Versioned API methods should not expose non-versioned types.
            IEnumerable <string> includedFrequencies = default,
#pragma warning restore API0001 // Versioned API methods should not expose non-versioned types.
            bool includeBuildTimes = false,
            int days           = 7,
            bool includeArcade = true)
        {
            var barOnlyRemote = await _remoteFactory.GetBarOnlyRemoteAsync(Logger);

            Microsoft.DotNet.Maestro.Client.Models.Channel engLatestChannel = await barOnlyRemote.GetChannelAsync(EngLatestChannelId);

            Microsoft.DotNet.Maestro.Client.Models.Channel eng3Channel = await barOnlyRemote.GetChannelAsync(Eng3ChannelId);

            List <Microsoft.DotNet.Maestro.Client.Models.DefaultChannel> defaultChannels = (await barOnlyRemote.GetDefaultChannelsAsync()).ToList();

            if (includeArcade)
            {
                if (engLatestChannel != null)
                {
                    defaultChannels.Add(
                        new Microsoft.DotNet.Maestro.Client.Models.DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "master",
                        Channel = engLatestChannel
                    }
                        );
                }

                if (eng3Channel != null)
                {
                    defaultChannels.Add(
                        new Microsoft.DotNet.Maestro.Client.Models.DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "release/3.x",
                        Channel = eng3Channel
                    }
                        );
                }
            }

            List <Microsoft.DotNet.Maestro.Client.Models.Subscription> subscriptions = (await barOnlyRemote.GetSubscriptionsAsync()).ToList();

            // Build, then prune out what we don't want to see if the user specified
            // channels.
            DependencyFlowGraph flowGraph = await DependencyFlowGraph.BuildAsync(defaultChannels, subscriptions, barOnlyRemote, days);

            IEnumerable <string> frequencies = includedFrequencies == default || includedFrequencies.Count() == 0 ?
                                               new string[] { "everyWeek", "twiceDaily", "everyDay", "everyBuild", "none", } :
            includedFrequencies;

            Microsoft.DotNet.Maestro.Client.Models.Channel targetChannel = null;

            if (channelId != 0)
            {
                targetChannel = await barOnlyRemote.GetChannelAsync((int)channelId);
            }

            if (targetChannel != null)
            {
                flowGraph.PruneGraph(
                    node => DependencyFlowGraph.IsInterestingNode(targetChannel.Name, node),
                    edge => DependencyFlowGraph.IsInterestingEdge(edge, includeDisabledSubscriptions, frequencies));
            }

            if (includeBuildTimes)
            {
                flowGraph.MarkBackEdges();
                flowGraph.CalculateLongestBuildPaths();
                flowGraph.MarkLongestBuildPath();
            }

            // Convert flow graph to correct return type
            return(Ok(FlowGraph.Create(flowGraph)));
        }
Beispiel #4
0
        public async Task <DependencyFlowGraph> GetDependencyFlowGraphAsync(
            int channelId,
            int days,
            bool includeArcade,
            bool includeBuildTimes,
            bool includeDisabledSubscriptions,
            IReadOnlyList <string> includedFrequencies)
        {
            var engLatestChannel = await GetChannelAsync(EngLatestChannelId);

            var eng3Channel = await GetChannelAsync(Eng3ChannelId);

            var defaultChannels = (await GetDefaultChannelsAsync()).ToList();

            if (includeArcade)
            {
                if (engLatestChannel != null)
                {
                    defaultChannels.Add(
                        new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "master",
                        Channel = engLatestChannel
                    }
                        );
                }

                if (eng3Channel != null)
                {
                    defaultChannels.Add(
                        new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "release/3.x",
                        Channel = eng3Channel
                    }
                        );
                }
            }

            var subscriptions = (await GetSubscriptionsAsync()).ToList();

            // Build, then prune out what we don't want to see if the user specified
            // channels.
            DependencyFlowGraph flowGraph = await DependencyFlowGraph.BuildAsync(
                defaultChannels,
                subscriptions,
                this,
                days);

            IEnumerable <string> frequencies
                = includedFrequencies == default || includedFrequencies.Count() == 0
                ? new string[] { "everyWeek", "twiceDaily", "everyDay", "everyBuild", "none", }
                : includedFrequencies;

            Channel targetChannel = null;

            if (channelId != 0)
            {
                targetChannel = await GetChannelAsync(channelId);
            }

            if (targetChannel != null)
            {
                flowGraph.PruneGraph(
                    node => DependencyFlowGraph.IsInterestingNode(targetChannel.Name, node),
                    edge => DependencyFlowGraph.IsInterestingEdge(edge, includeDisabledSubscriptions, frequencies));
            }

            if (includeBuildTimes)
            {
                var edgesWithLastBuild = flowGraph.Edges
                                         .Where(e => e.Subscription.LastAppliedBuild != null);

                foreach (var edge in edgesWithLastBuild)
                {
                    edge.IsToolingOnly = !_context.IsProductDependency(
                        edge.From.Repository,
                        edge.From.Branch,
                        edge.To.Repository,
                        edge.To.Branch);
                }

                flowGraph.MarkBackEdges();
                flowGraph.CalculateLongestBuildPaths();
                flowGraph.MarkLongestBuildPath();
            }

            return(flowGraph);
        }
        public override async Task <int> ExecuteAsync()
        {
            try
            {
                RemoteFactory remoteFactory = new RemoteFactory(_options);
                var           barOnlyRemote = await remoteFactory.GetBarOnlyRemoteAsync(Logger);

                Channel engLatestChannel = await barOnlyRemote.GetChannelAsync(engLatestChannelId);

                Channel eng3Channel = await barOnlyRemote.GetChannelAsync(eng3ChannelId);

                List <DefaultChannel> defaultChannels = (await barOnlyRemote.GetDefaultChannelsAsync()).ToList();
                if (engLatestChannel != null)
                {
                    defaultChannels.Add(
                        new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "master",
                        Channel = engLatestChannel
                    }
                        );
                }
                if (eng3Channel != null)
                {
                    defaultChannels.Add(
                        new DefaultChannel(0, "https://github.com/dotnet/arcade", true)
                    {
                        Branch  = "release/3.x",
                        Channel = eng3Channel
                    }
                        );
                }
                List <Subscription> subscriptions = (await barOnlyRemote.GetSubscriptionsAsync()).ToList();

                // Build, then prune out what we don't want to see if the user specified
                // channels.
                DependencyFlowGraph flowGraph = await DependencyFlowGraph.BuildAsync(defaultChannels, subscriptions, barOnlyRemote, _options.Days);

                Channel targetChannel = null;
                if (!string.IsNullOrEmpty(_options.Channel))
                {
                    // Resolve the channel.
                    targetChannel = await UxHelpers.ResolveSingleChannel(barOnlyRemote, _options.Channel);

                    if (targetChannel == null)
                    {
                        return(Constants.ErrorCode);
                    }
                }

                if (targetChannel != null)
                {
                    flowGraph.PruneGraph(
                        node => DependencyFlowGraph.IsInterestingNode(targetChannel.Name, node),
                        edge => DependencyFlowGraph.IsInterestingEdge(edge, _options.IncludeDisabledSubscriptions, _options.IncludedFrequencies));
                }

                if (_options.IncludeBuildTimes)
                {
                    flowGraph.MarkBackEdges();
                    flowGraph.CalculateLongestBuildPaths();
                    flowGraph.MarkLongestBuildPath();
                }

                await LogGraphVizAsync(targetChannel, flowGraph, _options.IncludeBuildTimes);

                return(Constants.SuccessCode);
            }
            catch (Exception exc)
            {
                Logger.LogError(exc, "Something failed while getting the dependency graph.");
                return(Constants.ErrorCode);
            }
        }