public async override Task <int> ExecuteAsync() { if (!(_options.Released ^ _options.NotReleased)) { Console.WriteLine("Please specify either --released or --not-released."); return(Constants.ErrorCode); } try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); Build updatedBuild = await remote.UpdateBuildAsync(_options.Id, new BuildUpdate { Released = _options.Released }); Console.WriteLine($"Updated build {_options.Id} with new information."); Console.WriteLine(UxHelpers.GetTextBuildDescription(updatedBuild)); } catch (Exception e) { Logger.LogError(e, $"Error: Failed to update build with id '{_options.Id}'"); return(Constants.ErrorCode); } return(Constants.SuccessCode); }
/// <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> /// Get a specific build of a repository /// </summary> /// <returns>Process exit code.</returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); List <Build> matchingBuilds = null; if (_options.Id != 0) { if (!string.IsNullOrEmpty(_options.BuildUri) || !string.IsNullOrEmpty(_options.Repo) || !string.IsNullOrEmpty(_options.Commit)) { Console.WriteLine("--id should not be used with other options."); return(Constants.ErrorCode); } matchingBuilds = new List <Build>() { await remote.GetBuildAsync(_options.Id) }; } else if (!string.IsNullOrEmpty(_options.BuildUri)) { if (_options.Id != 0 || !string.IsNullOrEmpty(_options.Repo) || !string.IsNullOrEmpty(_options.Commit)) { Console.WriteLine("--uri should not be used with other options."); return(Constants.ErrorCode); } Console.WriteLine("This option is not yet supported."); return(Constants.ErrorCode); } else if (!string.IsNullOrEmpty(_options.Repo) || !string.IsNullOrEmpty(_options.Commit)) { if (string.IsNullOrEmpty(_options.Repo) != string.IsNullOrEmpty(_options.Commit)) { Console.WriteLine("--repo and --commit should be used together."); return(Constants.ErrorCode); } else if (_options.Id != 0 || !string.IsNullOrEmpty(_options.BuildUri)) { Console.WriteLine("--repo and --commit should not be used with other options."); return(Constants.ErrorCode); } matchingBuilds = (await remote.GetBuildsAsync(_options.Repo, _options.Commit)).ToList(); } else { Console.WriteLine("Please specify --id, --uri, or --repo and --commit to lookup a build."); return(Constants.ErrorCode); } // Print the build info. if (!matchingBuilds.Any()) { Console.WriteLine($"Could not any builds matching the given criteria."); return(Constants.ErrorCode); } switch (_options.OutputFormat) { case DarcOutputType.text: foreach (Build build in matchingBuilds) { Console.Write(UxHelpers.GetTextBuildDescription(build)); } break; case DarcOutputType.json: Console.WriteLine(JsonConvert.SerializeObject( matchingBuilds.Select(build => UxHelpers.GetJsonBuildDescription(build)), Formatting.Indented)); break; default: throw new NotImplementedException($"Output format type {_options.OutputFormat} not yet supported for get-build."); } return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve build information."); 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"; // 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); } }
/// <summary> /// Gets the latest build for a repo /// </summary> /// <returns>Process exit code.</returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); // Calculate out possible repos based on the input strings. // Today the DB has no way of searching for builds by substring, so for now // grab source/targets repos of subscriptions matched on substring, // and then add the explicit repo from the options. // Then search channels by substring // Then run GetLatestBuild for each permutation. var subscriptions = await remote.GetSubscriptionsAsync(); var possibleRepos = subscriptions .SelectMany(subscription => new List <string> { subscription.SourceRepository, subscription.TargetRepository }) .Where(r => r.Contains(_options.Repo, StringComparison.OrdinalIgnoreCase)) .ToHashSet(StringComparer.OrdinalIgnoreCase); possibleRepos.Add(_options.Repo); var channels = (await remote.GetChannelsAsync()) .Where(c => string.IsNullOrEmpty(_options.Channel) || c.Name.Contains(_options.Channel, StringComparison.OrdinalIgnoreCase)); if (!channels.Any()) { Console.WriteLine($"Could not find a channel with name containing '{_options.Channel}'"); return(Constants.ErrorCode); } bool foundBuilds = false; foreach (string possibleRepo in possibleRepos) { foreach (Channel channel in channels) { Build latestBuild = await remote.GetLatestBuildAsync(possibleRepo, channel.Id); if (latestBuild != null) { if (foundBuilds) { Console.WriteLine(); } foundBuilds = true; Console.Write(UxHelpers.GetTextBuildDescription(latestBuild)); } } } if (!foundBuilds) { Console.WriteLine("No latest build found matching the specified criteria"); return(Constants.ErrorCode); } return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve latest build."); return(Constants.ErrorCode); } }
/// <summary> /// Get a specific build of a repository /// </summary> /// <returns>Process exit code.</returns> public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); List <Build> matchingBuilds = null; if (_options.Id != 0) { if (!string.IsNullOrEmpty(_options.Repo) || !string.IsNullOrEmpty(_options.Commit)) { Console.WriteLine("--id should not be used with other options."); return(Constants.ErrorCode); } matchingBuilds = new List <Build>() { await remote.GetBuildAsync(_options.Id) }; } else if (!string.IsNullOrEmpty(_options.Repo) || !string.IsNullOrEmpty(_options.Commit)) { if (string.IsNullOrEmpty(_options.Repo) != string.IsNullOrEmpty(_options.Commit)) { Console.WriteLine("--repo and --commit should be used together."); return(Constants.ErrorCode); } var subscriptions = await remote.GetSubscriptionsAsync(); var possibleRepos = subscriptions .SelectMany(subscription => new List <string> { subscription.SourceRepository, subscription.TargetRepository }) .Where(r => r.Contains(_options.Repo, StringComparison.OrdinalIgnoreCase)) .ToHashSet(StringComparer.OrdinalIgnoreCase); matchingBuilds = new List <Build>(); foreach (string repo in possibleRepos) { matchingBuilds.AddRange(await remote.GetBuildsAsync(repo, _options.Commit)); } } else { Console.WriteLine("Please specify --id, --uri, or --repo and --commit to lookup a build."); return(Constants.ErrorCode); } // Print the build info. if (!matchingBuilds.Any()) { Console.WriteLine($"Could not any builds matching the given criteria."); return(Constants.ErrorCode); } switch (_options.OutputFormat) { case DarcOutputType.text: foreach (Build build in matchingBuilds) { Console.Write(UxHelpers.GetTextBuildDescription(build)); } break; case DarcOutputType.json: Console.WriteLine(JsonConvert.SerializeObject( matchingBuilds.Select(build => UxHelpers.GetJsonBuildDescription(build)), Formatting.Indented)); break; default: throw new NotImplementedException($"Output format type {_options.OutputFormat} not yet supported for get-build."); } return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to retrieve build information."); return(Constants.ErrorCode); } }