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); } }
/// <summary> /// Deletes a build from a channel. /// </summary> /// <returns>Process exit code.</returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); // Find the build to give someone info Build build = await remote.GetBuildAsync(_options.Id); if (build == null) { Console.WriteLine($"Could not find a build with id '{_options.Id}'"); return(Constants.ErrorCode); } Channel targetChannel = await UxHelpers.ResolveSingleChannel(remote, _options.Channel); if (targetChannel == null) { return(Constants.ErrorCode); } if (!build.Channels.Any(c => c.Id == targetChannel.Id)) { Console.WriteLine($"Build '{build.Id}' is not assigned to channel '{targetChannel.Name}'"); return(Constants.SuccessCode); } Console.WriteLine($"Deleting the following build from channel '{targetChannel.Name}':"); Console.WriteLine(); Console.Write(UxHelpers.GetTextBuildDescription(build)); await remote.DeleteBuildFromChannelAsync(_options.Id, targetChannel.Id); // Let the user know they can trigger subscriptions if they'd like. Console.WriteLine("Subscriptions can be triggered to revert to the previous state using the following command:"); Console.WriteLine($"darc trigger-subscriptions --source-repo {build.GitHubRepository ?? build.AzureDevOpsRepository} --channel {targetChannel.Name}"); return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, $"Error: Failed to delete build '{_options.Id}' from channel '{_options.Channel}'."); return(Constants.ErrorCode); } }
/// <summary> /// Assigns a build to a channel. /// </summary> /// <returns>Process exit code.</returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); // Find the build to give someone info Build build = await remote.GetBuildAsync(_options.Id); if (build == null) { Console.WriteLine($"Could not find a build with id '{_options.Id}'"); return(Constants.ErrorCode); } Channel targetChannel = await UxHelpers.ResolveSingleChannel(remote, _options.Channel); if (targetChannel == null) { return(Constants.ErrorCode); } if (build.Channels.Any(c => c.Id == targetChannel.Id)) { Console.WriteLine($"Build '{build.Id}' has already been assigned to '{targetChannel.Name}'"); return(Constants.SuccessCode); } Console.WriteLine($"Assigning the following build to channel '{targetChannel.Name}':"); Console.WriteLine(); OutputHelpers.PrintBuild(build); await remote.AssignBuildToChannel(_options.Id, targetChannel.Id); // Be helpful. Let the user know what will happen. string buildRepo = build.GitHubRepository ?? build.AzureDevOpsRepository; List <Subscription> applicableSubscriptions = (await remote.GetSubscriptionsAsync( sourceRepo: buildRepo, channelId: targetChannel.Id)).ToList(); PrintSubscriptionInfo(applicableSubscriptions); return(Constants.SuccessCode); } catch (Exception e) { Logger.LogError(e, $"Error: Failed to assign build '{_options.Id}' to channel '{_options.Channel}'."); return(Constants.ErrorCode); } }
public override async Task <int> ExecuteAsync() { try { RemoteFactory remoteFactory = new RemoteFactory(_options); var barOnlyRemote = await remoteFactory.GetBarOnlyRemoteAsync(Logger); Channel targetChannel = null; if (!string.IsNullOrEmpty(_options.Channel)) { // Resolve the channel. targetChannel = await UxHelpers.ResolveSingleChannel(barOnlyRemote, _options.Channel); if (targetChannel == null) { return(Constants.ErrorCode); } } var flowGraph = await barOnlyRemote.GetDependencyFlowGraph( targetChannel?.Id ?? 0, _options.Days, includeArcade : true, includeBuildTimes : _options.IncludeBuildTimes, includeDisabledSubscriptions : _options.IncludeDisabledSubscriptions, includedFrequencies : _options.IncludedFrequencies?.ToList()); await LogGraphVizAsync(targetChannel, flowGraph, _options.IncludeBuildTimes); return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception exc) { Logger.LogError(exc, "Something failed while getting the dependency graph."); return(Constants.ErrorCode); } }
/// <summary> /// /// </summary> /// <param name="channels"></param> /// <returns></returns> private HashSet <string> ComputeChannelsToEvaluate(IEnumerable <Channel> channels) { if (!string.IsNullOrEmpty(_options.Channel)) { HashSet <string> channelsToTarget = new HashSet <string>(StringComparer.OrdinalIgnoreCase); Channel targetChannel = UxHelpers.ResolveSingleChannel(channels, _options.Channel); if (targetChannel != null) { channelsToTarget.Add(targetChannel.Name); } return(channelsToTarget); } else { // Look up all channels return(channels.Select(c => c.Name).ToHashSet()); } }
public override async Task <int> ExecuteAsync() { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); try { Channel targetChannel = null; if (!string.IsNullOrEmpty(_options.Channel)) { targetChannel = await UxHelpers.ResolveSingleChannel(remote, _options.Channel); if (targetChannel == null) { return(Constants.ErrorCode); } } // Starting with the remote, get information on the asset name + version List <Asset> matchingAssets = (await remote.GetAssetsAsync(name: _options.Name, version: _options.Version)).ToList(); string queryDescriptionString = $"name '{_options.Name}'{(!string.IsNullOrEmpty(_options.Version) ? $" and version '{_options.Version}'" : "")}" + $"{(targetChannel != null ? $" on channel '{targetChannel.Name}'" : "")} in the last {_options.MaxAgeInDays} days"; // Only print the lookup string if the output type is text. if (_options.OutputFormat == DarcOutputType.text) { Console.WriteLine($"Looking up assets with {queryDescriptionString}"); } // Walk the assets and look up the corresponding builds, potentially filtering based on channel // if there is a target channel int maxAgeInDays = _options.MaxAgeInDays; var now = DateTimeOffset.Now; int checkedAssets = 0; List <(Asset asset, Build build)> matchingAssetsAfterDate = new List <(Asset, Build)>(); foreach (Asset asset in matchingAssets) { // Get build info for asset Build buildInfo = await remote.GetBuildAsync(asset.BuildId); if (now.Subtract(buildInfo.DateProduced).TotalDays > maxAgeInDays) { break; } checkedAssets++; if (targetChannel != null && !buildInfo.Channels.Any(c => c.Id == targetChannel.Id)) { continue; } matchingAssetsAfterDate.Add((asset, buildInfo)); } if (!matchingAssetsAfterDate.Any()) { Console.WriteLine($"No assets found with {queryDescriptionString}"); int remaining = matchingAssets.Count - checkedAssets; if (remaining > 0) { Console.WriteLine($"Skipping build lookup for {remaining} assets. Consider increasing --max-age to check the rest."); } return(Constants.ErrorCode); } switch (_options.OutputFormat) { case DarcOutputType.text: foreach ((Asset asset, Build build) in matchingAssetsAfterDate) { Console.WriteLine($"{asset.Name} @ {asset.Version}"); Console.Write(UxHelpers.GetTextBuildDescription(build)); Console.WriteLine("Locations:"); if (asset.Locations.Any()) { foreach (var location in asset.Locations) { if (location.IsValid) { Console.WriteLine($"- {location.Location} ({location.Type})"); } } } else { Console.WriteLine("- None"); } Console.WriteLine(); } break; case DarcOutputType.json: var assets = matchingAssetsAfterDate.Select(assetAndBuild => { return(new { name = assetAndBuild.asset.Name, version = assetAndBuild.asset.Version, build = UxHelpers.GetJsonBuildDescription(assetAndBuild.build), locations = assetAndBuild.asset.Locations.Select(location => location.Location) }); }); Console.WriteLine(JsonConvert.SerializeObject(assets, Formatting.Indented)); break; } return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve information about assets."); return(Constants.ErrorCode); } }
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); } }
public override async Task <int> ExecuteAsync() { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); try { Channel targetChannel = null; if (!string.IsNullOrEmpty(_options.Channel)) { targetChannel = await UxHelpers.ResolveSingleChannel(remote, _options.Channel); if (targetChannel == null) { return(Constants.ErrorCode); } } // Starting with the remote, get information on the asset name + version List <Asset> matchingAssets = (await remote.GetAssetsAsync(name: _options.Name, version: _options.Version)).ToList(); string queryDescriptionString = $"name '{_options.Name}'{(!string.IsNullOrEmpty(_options.Version) ? $"and version '{_options.Version}'" : "")}" + $"{(targetChannel != null ? $" on channel '{targetChannel.Name}'" : "")} in the last {_options.MaxAgeInDays} days"; Console.WriteLine($"Looking up assets with {queryDescriptionString}"); // Walk the assets and look up the corresponding builds, potentially filtering based on channel // if there is a target channel bool foundMatching = false; int maxAgeInDays = _options.MaxAgeInDays; var now = DateTimeOffset.Now; int checkedAssets = 0; foreach (var asset in matchingAssets) { checkedAssets++; // Get build info for asset Build buildInfo = await remote.GetBuildAsync(asset.BuildId); if (targetChannel != null && !buildInfo.Channels.Any(c => c.Id == targetChannel.Id)) { continue; } if (now.Subtract(buildInfo.DateProduced).TotalDays > maxAgeInDays) { break; } foundMatching = true; Console.WriteLine($"{asset.Name} @ {asset.Version}"); Console.Write(UxHelpers.GetBuildDescription(buildInfo)); Console.WriteLine("Locations:"); if (asset.Locations.Any()) { foreach (var location in asset.Locations) { if (location.IsValid) { Console.WriteLine($"- {location.Location} ({location.Type})"); } } } else { Console.WriteLine("- None"); } Console.WriteLine(); } if (!foundMatching) { Console.WriteLine($"No assets found with {queryDescriptionString}"); int remaining = matchingAssets.Count - checkedAssets; if (remaining > 0) { Console.WriteLine($"Skipping build lookup for {remaining} assets. Consider increasing --max-age to check the rest."); } } return(Constants.SuccessCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve information about assets."); return(Constants.ErrorCode); } }