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