Exemplo n.º 1
0
        /// <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);

                Build build = await remote.GetBuildAsync(_options.Id);

                if (build != null)
                {
                    Console.Write(UxHelpers.GetBuildDescription(build));
                }
                else
                {
                    Console.WriteLine($"Could not find build with id '{_options.Id}'");
                    return(Constants.ErrorCode);
                }

                return(Constants.SuccessCode);
            }
            catch (Exception e)
            {
                Logger.LogError(e, $"Error: Failed to retrieve build with id '{_options.Id}'");
                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);
            }
        }
Exemplo n.º 3
0
        /// <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);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Update local dependencies based on a specific channel.
        /// </summary>
        /// <param name="options">Command line options</param>
        /// <returns>Process exit code.</returns>
        public override async Task <int> ExecuteAsync()
        {
            try
            {
                DarcSettings darcSettings = darcSettings = LocalSettings.GetDarcSettings(_options, Logger);

                // TODO: PAT only used for pulling the Arcade eng/common dir,
                // so hardcoded to GitHub PAT right now. Must be more generic in the future.
                darcSettings.GitType = GitRepoType.GitHub;
                LocalSettings localSettings = LocalSettings.LoadSettingsFile(_options);

                darcSettings.GitRepoPersonalAccessToken = localSettings != null && !string.IsNullOrEmpty(localSettings.GitHubToken) ?
                                                          localSettings.GitHubToken :
                                                          _options.GitHubPat;

                IRemoteFactory remoteFactory = new RemoteFactory(_options);
                IRemote        barOnlyRemote = await remoteFactory.GetBarOnlyRemoteAsync(Logger);

                Local local = new Local(Logger);
                List <DependencyDetail> dependenciesToUpdate = new List <DependencyDetail>();
                bool   someUpToDate = false;
                string finalMessage = $"Local dependencies updated from channel '{_options.Channel}'.";

                // First we need to figure out what to query for. Load Version.Details.xml and
                // find all repository uris, optionally restricted by the input dependency parameter.
                IEnumerable <DependencyDetail> localDependencies = await local.GetDependenciesAsync(_options.Name, false);

                // If the source repository was specified, filter away any local dependencies not from that
                // source repository.
                if (!string.IsNullOrEmpty(_options.SourceRepository))
                {
                    localDependencies = localDependencies.Where(
                        dependency => dependency.RepoUri.Contains(_options.SourceRepository, StringComparison.OrdinalIgnoreCase));
                }

                if (!localDependencies.Any())
                {
                    Console.WriteLine("Found no dependencies to update.");
                    return(Constants.ErrorCode);
                }

                List <DependencyDetail> currentDependencies = localDependencies.ToList();

                if (!string.IsNullOrEmpty(_options.Name) && !string.IsNullOrEmpty(_options.Version))
                {
                    DependencyDetail dependency = currentDependencies.First();
                    dependency.Version = _options.Version;
                    dependenciesToUpdate.Add(dependency);

                    Console.WriteLine($"Updating '{dependency.Name}': '{dependency.Version}' => '{_options.Version}'");

                    finalMessage = $"Local dependency {_options.Name} updated to version '{_options.Version}'.";
                }
                else if (!string.IsNullOrEmpty(_options.PackagesFolder))
                {
                    try
                    {
                        dependenciesToUpdate.AddRange(GetDependenciesFromPackagesFolder(_options.PackagesFolder, currentDependencies));
                    }
                    catch (DarcException exc)
                    {
                        Logger.LogError(exc, $"Error: Failed to update dependencies based on folder '{_options.PackagesFolder}'");
                        return(Constants.ErrorCode);
                    }

                    finalMessage = $"Local dependencies updated based on packages folder {_options.PackagesFolder}.";
                }
                else if (_options.BARBuildId > 0)
                {
                    try
                    {
                        if (!_options.CoherencyOnly)
                        {
                            Console.WriteLine($"Looking up build with BAR id {_options.BARBuildId}");
                            var specificBuild = await barOnlyRemote.GetBuildAsync(_options.BARBuildId);

                            int nonCoherencyResult = await NonCoherencyUpdatesForBuildAsync(specificBuild, barOnlyRemote, currentDependencies, dependenciesToUpdate)
                                                     .ConfigureAwait(false);

                            if (nonCoherencyResult != Constants.SuccessCode)
                            {
                                Console.WriteLine("Error: Failed to update non-coherent parent tied dependencies.");
                                return(nonCoherencyResult);
                            }

                            string sourceRepo   = specificBuild.GitHubRepository ?? specificBuild.AzureDevOpsRepository;
                            string sourceBranch = specificBuild.GitHubBranch ?? specificBuild.AzureDevOpsBranch;

                            finalMessage = $"Local dependencies updated based on build with BAR id {_options.BARBuildId} " +
                                           $"({specificBuild.AzureDevOpsBuildNumber} from {sourceRepo}@{sourceBranch})";
                        }

                        int coherencyResult = await CoherencyUpdatesAsync(barOnlyRemote, remoteFactory, currentDependencies, dependenciesToUpdate)
                                              .ConfigureAwait(false);

                        if (coherencyResult != Constants.SuccessCode)
                        {
                            Console.WriteLine("Error: Failed to update coherent parent tied dependencies.");
                            return(coherencyResult);
                        }

                        finalMessage = string.IsNullOrEmpty(finalMessage) ? "Local dependencies successfully updated." : finalMessage;
                    }
                    catch (RestApiException e) when(e.Response.Status == 404)
                    {
                        Console.WriteLine($"Could not find build with BAR id '{_options.BARBuildId}'.");
                        return(Constants.ErrorCode);
                    }
                }
                else
                {
                    if (!_options.CoherencyOnly)
                    {
                        if (string.IsNullOrEmpty(_options.Channel))
                        {
                            Console.WriteLine($"Please supply either a channel name (--channel), a packages folder (--packages-folder) " +
                                              "a BAR build id (--id), or a specific dependency name and version (--name and --version).");
                            return(Constants.ErrorCode);
                        }

                        // Start channel query.
                        Task <Channel> channel = barOnlyRemote.GetChannelAsync(_options.Channel);

                        // Limit the number of BAR queries by grabbing the repo URIs and making a hash set.
                        // We gather the latest build for any dependencies that aren't marked with coherent parent
                        // dependencies, as those will be updated based on additional queries.
                        HashSet <string> repositoryUrisForQuery = currentDependencies
                                                                  .Where(dependency => string.IsNullOrEmpty(dependency.CoherentParentDependencyName))
                                                                  .Select(dependency => dependency.RepoUri)
                                                                  .ToHashSet();

                        ConcurrentDictionary <string, Task <Build> > getLatestBuildTaskDictionary = new ConcurrentDictionary <string, Task <Build> >();

                        Channel channelInfo = await channel;
                        if (channelInfo == null)
                        {
                            Console.WriteLine($"Could not find a channel named '{_options.Channel}'.");
                            return(Constants.ErrorCode);
                        }

                        foreach (string repoToQuery in repositoryUrisForQuery)
                        {
                            Console.WriteLine($"Looking up latest build of {repoToQuery} on {_options.Channel}");
                            var latestBuild = barOnlyRemote.GetLatestBuildAsync(repoToQuery, channelInfo.Id);
                            getLatestBuildTaskDictionary.TryAdd(repoToQuery, latestBuild);
                        }

                        // For each build, first go through and determine the required updates,
                        // updating the "live" dependency information as we go.
                        // Then run a second pass where we update any assets based on coherency information.
                        foreach (KeyValuePair <string, Task <Build> > buildKvPair in getLatestBuildTaskDictionary)
                        {
                            string repoUri = buildKvPair.Key;
                            Build  build   = await buildKvPair.Value;

                            if (build == null)
                            {
                                Logger.LogTrace($"No build of '{repoUri}' found on channel '{_options.Channel}'.");
                                continue;
                            }

                            int nonCoherencyResult = await NonCoherencyUpdatesForBuildAsync(build, barOnlyRemote, currentDependencies, dependenciesToUpdate)
                                                     .ConfigureAwait(false);

                            if (nonCoherencyResult != Constants.SuccessCode)
                            {
                                Console.WriteLine("Error: Failed to update non-coherent parent tied dependencies.");
                                return(nonCoherencyResult);
                            }
                        }
                    }

                    int coherencyResult = await CoherencyUpdatesAsync(barOnlyRemote, remoteFactory, currentDependencies, dependenciesToUpdate)
                                          .ConfigureAwait(false);

                    if (coherencyResult != Constants.SuccessCode)
                    {
                        Console.WriteLine("Error: Failed to update coherent parent tied dependencies.");
                        return(coherencyResult);
                    }
                }

                if (!dependenciesToUpdate.Any())
                {
                    // If we found some dependencies already up to date,
                    // then we consider this a success. Otherwise, we didn't even
                    // find matching dependencies so we should let the user know.
                    if (someUpToDate)
                    {
                        Console.WriteLine($"All dependencies are up to date.");
                        return(Constants.SuccessCode);
                    }
                    else
                    {
                        Console.WriteLine($"Found no dependencies to update.");
                        return(Constants.ErrorCode);
                    }
                }

                if (_options.DryRun)
                {
                    return(Constants.SuccessCode);
                }

                // Now call the local updater to run the update.
                await local.UpdateDependenciesAsync(dependenciesToUpdate, remoteFactory);

                Console.WriteLine(finalMessage);

                return(Constants.SuccessCode);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine(e.Message);
                return(Constants.ErrorCode);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Error: Failed to update dependencies.");
                return(Constants.ErrorCode);
            }
        }
Exemplo n.º 5
0
        /// <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);
            }
        }
Exemplo n.º 6
0
        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>
        ///     Obtain the root build.
        /// </summary>
        /// <returns>Root build to start with.</returns>
        private async Task <Build> GetRootBuildAsync()
        {
            if (!ValidateRootBuildOptions())
            {
                return(null);
            }

            IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger);

            string repoUri = GetRepoUri();

            if (_options.RootBuildId != 0)
            {
                Console.WriteLine($"Looking up build by id {_options.RootBuildId}");
                Build rootBuild = await remote.GetBuildAsync(_options.RootBuildId);

                if (rootBuild == null)
                {
                    Console.WriteLine($"No build found with id {_options.RootBuildId}");
                    return(null);
                }
                return(rootBuild);
            }
            else if (!string.IsNullOrEmpty(repoUri))
            {
                if (!string.IsNullOrEmpty(_options.Channel))
                {
                    IEnumerable <Channel> channels = await remote.GetChannelsAsync();

                    IEnumerable <Channel> desiredChannels = channels.Where(channel => channel.Name.Contains(_options.Channel, StringComparison.OrdinalIgnoreCase));
                    if (desiredChannels.Count() != 1)
                    {
                        Console.WriteLine($"Channel name {_options.Channel} did not match a unique channel. Available channels:");
                        foreach (var channel in channels)
                        {
                            Console.WriteLine($"  {channel.Name}");
                        }
                        return(null);
                    }
                    Channel targetChannel = desiredChannels.First();
                    Console.WriteLine($"Looking up latest build of '{repoUri}' on channel '{targetChannel.Name}'");
                    Build rootBuild = await remote.GetLatestBuildAsync(repoUri, targetChannel.Id);

                    if (rootBuild == null)
                    {
                        Console.WriteLine($"No build of '{repoUri}' found on channel '{targetChannel.Name}'");
                        return(null);
                    }
                    return(rootBuild);
                }
                else if (!string.IsNullOrEmpty(_options.Commit))
                {
                    Console.WriteLine($"Looking up builds of {_options.RepoUri}@{_options.Commit}");
                    IEnumerable <Build> builds = await remote.GetBuildsAsync(_options.RepoUri, _options.Commit);

                    // If more than one is available, print them with their IDs.
                    if (builds.Count() > 1)
                    {
                        Console.WriteLine($"There were {builds.Count()} potential root builds.  Please select one and pass it with --id");
                        foreach (var build in builds)
                        {
                            Console.WriteLine($"  {build.Id}: {build.AzureDevOpsBuildNumber} @ {build.DateProduced.ToLocalTime()}");
                        }
                        return(null);
                    }
                    Build rootBuild = builds.SingleOrDefault();
                    if (rootBuild == null)
                    {
                        Console.WriteLine($"No builds were found of {_options.RepoUri}@{_options.Commit}");
                    }
                    return(rootBuild);
                }
            }
            // Shouldn't get here if ValidateRootBuildOptions is correct.
            throw new DarcException("Options for root builds were not validated properly. Please contact @dnceng");
        }
        /// <summary>
        /// Triggers subscriptions
        /// </summary>
        /// <returns></returns>
        public override async Task <int> ExecuteAsync()
        {
            try
            {
                IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger);

                bool noConfirm = _options.NoConfirmation;
                List <Subscription> subscriptionsToTrigger = new List <Subscription>();

                if (!string.IsNullOrEmpty(_options.Id))
                {
                    // Look up subscription so we can print it later.
                    try
                    {
                        Subscription subscription = await remote.GetSubscriptionAsync(_options.Id);

                        subscriptionsToTrigger.Add(subscription);
                    }
                    catch (RestApiException e) when(e.Response.Status == (int)HttpStatusCode.NotFound)
                    {
                        Console.WriteLine($"Subscription with id '{_options.Id}' was not found.");
                        return(Constants.ErrorCode);
                    }
                }
                else
                {
                    if (!_options.HasAnyFilters())
                    {
                        Console.WriteLine($"Please specify one or more filters to select which subscriptions should be triggered (see help).");
                        return(Constants.ErrorCode);
                    }

                    IEnumerable <Subscription> subscriptions = await _options.FilterSubscriptions(remote);

                    if (!subscriptions.Any())
                    {
                        Console.WriteLine("No subscriptions found matching the specified criteria.");
                        return(Constants.ErrorCode);
                    }

                    subscriptionsToTrigger.AddRange(subscriptions);
                }

                if (_options.Build != 0)
                {
                    var specificBuild = await remote.GetBuildAsync(_options.Build);

                    if (specificBuild == null)
                    {
                        Console.WriteLine($"No build found in the BAR with id '{_options.Build}'");
                        return(Constants.ErrorCode);
                    }

                    // If the user specified repo and a build number, error out if anything doesn't match.
                    if (!_options.SubscriptionParameterMatches(_options.SourceRepository, specificBuild.GitHubRepository))
                    {
                        Console.WriteLine($"Build #{_options.Build} was made with repo {specificBuild.GitHubRepository} and does not match provided value ({_options.SourceRepository})");
                        return(Constants.ErrorCode);
                    }

                    Console.WriteLine($"Subscription updates will use Build # {_options.Build} instead of latest available");
                }

                // Filter away subscriptions that are disabled
                List <Subscription> disabledSubscriptions = subscriptionsToTrigger.Where(s => !s.Enabled).ToList();
                subscriptionsToTrigger = subscriptionsToTrigger.Where(s => s.Enabled).ToList();

                if (disabledSubscriptions.Any())
                {
                    Console.WriteLine($"The following {disabledSubscriptions.Count} subscription(s) are disabled and will not be triggered");
                    foreach (var subscription in disabledSubscriptions)
                    {
                        Console.WriteLine($"  {UxHelpers.GetSubscriptionDescription(subscription)}");
                    }
                }

                if (!subscriptionsToTrigger.Any())
                {
                    Console.WriteLine("No enabled subscriptions found matching the specified criteria.");
                    return(Constants.ErrorCode);
                }

                if (!noConfirm)
                {
                    // Print out the list of subscriptions about to be triggered.
                    Console.WriteLine($"Will trigger the following {subscriptionsToTrigger.Count} subscriptions...");
                    foreach (var subscription in subscriptionsToTrigger)
                    {
                        Console.WriteLine($"  {UxHelpers.GetSubscriptionDescription(subscription)}");
                    }

                    if (!UxHelpers.PromptForYesNo("Continue?"))
                    {
                        Console.WriteLine($"No subscriptions triggered, exiting.");
                        return(Constants.ErrorCode);
                    }
                }

                Console.Write($"Triggering {subscriptionsToTrigger.Count} subscriptions...{(noConfirm ? Environment.NewLine : "")}");
                foreach (var subscription in subscriptionsToTrigger)
                {
                    // If noConfirm was passed, print out the subscriptions as we go
                    if (noConfirm)
                    {
                        Console.WriteLine($"  {UxHelpers.GetSubscriptionDescription(subscription)}");
                    }
                    if (_options.Build > 0)
                    {
                        await remote.TriggerSubscriptionAsync(subscription.Id.ToString(), _options.Build);
                    }
                    else
                    {
                        await remote.TriggerSubscriptionAsync(subscription.Id.ToString());
                    }
                }
                Console.WriteLine("done");

                return(Constants.SuccessCode);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine(e.Message);
                return(Constants.ErrorCode);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Unexpected error while triggering subscriptions.");
                return(Constants.ErrorCode);
            }
        }
Exemplo n.º 9
0
        /// <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);
            }
        }
Exemplo n.º 10
0
        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);
            }
        }