/// <summary> /// Retrieve information about the default association between builds of a specific branch/repo /// and a channel. /// </summary> /// <returns></returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); IEnumerable <DefaultChannel> defaultChannels = (await remote.GetDefaultChannelsAsync()).Where(defaultChannel => { return((string.IsNullOrEmpty(_options.SourceRepository) || defaultChannel.Repository.Contains(_options.SourceRepository, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_options.Branch) || defaultChannel.Branch.Contains(_options.Branch, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_options.Channel) || defaultChannel.Channel.Name.Contains(_options.Channel, StringComparison.OrdinalIgnoreCase))); }); if (defaultChannels.Count() == 0) { Console.WriteLine("No matching channels were found."); } // Write out a simple list of each channel's name foreach (DefaultChannel defaultChannel in defaultChannels) { Console.WriteLine(OutputHelpers.GetDefaultChannelDescriptionString(defaultChannel)); } return(Constants.SuccessCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve default channel information."); return(Constants.ErrorCode); } }
public async Task <IEnumerable <Subscription> > FilterSubscriptions(IRemote remote) { IEnumerable <DefaultChannel> defaultChannels = await remote.GetDefaultChannelsAsync(); return((await remote.GetSubscriptionsAsync()).Where(subscription => { return SubcriptionFilter(subscription, defaultChannels); })); }
/// <summary> /// Resolve channel based on the input options. If no channel could be resolved /// based on the input options, returns null. /// </summary> /// <returns>Default channel or null</returns> protected async Task <DefaultChannel> ResolveSingleChannel() { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); IEnumerable <DefaultChannel> potentialDefaultChannels = await remote.GetDefaultChannelsAsync(); // User should have supplied id or a combo of the channel name, repo, and branch. if (_options.Id != -1) { DefaultChannel defaultChannel = potentialDefaultChannels.SingleOrDefault(d => d.Id == _options.Id); if (defaultChannel == null) { Console.WriteLine($"Could not find a default channel with id {_options.Id}"); } return(defaultChannel); } else if (string.IsNullOrEmpty(_options.Repository) || string.IsNullOrEmpty(_options.Channel) || string.IsNullOrEmpty(_options.Branch)) { Console.WriteLine("Please specify either the default channel id with --id or a combination of --channel, --branch and --repo"); return(null); } // Otherwise, filter based on the other inputs. If more than one resolves, then print the possible // matches and return null var matchingChannels = potentialDefaultChannels.Where(d => { return((string.IsNullOrEmpty(_options.Repository) || d.Repository.Contains(_options.Repository, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_options.Channel) || d.Channel.Name.Contains(_options.Channel, StringComparison.OrdinalIgnoreCase)) && (string.IsNullOrEmpty(_options.Branch) || d.Branch.Contains(GitHelpers.NormalizeBranchName(_options.Branch), StringComparison.OrdinalIgnoreCase))); }); if (!matchingChannels.Any()) { Console.WriteLine($"No channels found matching the specified criteria."); return(null); } else if (matchingChannels.Count() != 1) { Console.WriteLine($"More than one channel matching the specified criteria. Please change your options to be more specific."); foreach (DefaultChannel defaultChannel in matchingChannels) { Console.WriteLine($" {UxHelpers.GetDefaultChannelDescriptionString(defaultChannel)}"); } return(null); } else { return(matchingChannels.Single()); } }
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() { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); IEnumerable <Subscription> subscriptions = await remote.GetSubscriptionsAsync(); IEnumerable <DefaultChannel> defaultChannels = await remote.GetDefaultChannelsAsync(); IEnumerable <Channel> channels = await remote.GetChannelsAsync(); HashSet <string> channelsToEvaluate = ComputeChannelsToEvaluate(channels); HashSet <string> reposToEvaluate = ComputeRepositoriesToEvaluate(defaultChannels, subscriptions); // Print out what will be evaluated. If no channels or repos are in the initial sets, then // this is currently an error. Because different PKPIs apply to different input items differently, // this check may not be useful in the future. if (channelsToEvaluate.Any()) { Console.WriteLine("Evaluating the following channels:"); foreach (string channel in channelsToEvaluate) { Console.WriteLine($" {channel}"); } } else { Console.WriteLine($"There were no channels found to evaluate based on inputs, exiting."); return(Constants.ErrorCode); } if (reposToEvaluate.Any()) { Console.WriteLine("Evaluating the following repositories:"); foreach (string repo in reposToEvaluate) { Console.WriteLine($" {repo}"); } } else { Console.WriteLine($"There were no repositories found to evaluate based on inputs, exiting."); return(Constants.ErrorCode); } Console.WriteLine(); // Compute metrics, then run in parallel. List <Func <Task <HealthMetricWithOutput> > > metricsToRun = ComputeMetricsToRun(channelsToEvaluate, reposToEvaluate, subscriptions, defaultChannels, channels); // Run the metrics HealthMetricWithOutput[] results = await Task.WhenAll <HealthMetricWithOutput>(metricsToRun.Select(metric => metric())); // Walk through and print the results out bool passed = true; foreach (var healthResult in results) { if (healthResult.Metric.Result != HealthResult.Passed) { passed = false; } Console.WriteLine($"{healthResult.Metric.MetricDescription} - ({healthResult.Metric.Result})"); if (healthResult.Metric.Result != HealthResult.Passed) { Console.WriteLine(); Console.WriteLine(healthResult.FormattedConsoleOutput); } } return(passed ? Constants.SuccessCode : Constants.ErrorCode); }