示例#1
0
        /// <summary>
        /// Implements the 'subscription-status' operation
        /// </summary>
        /// <param name="options"></param>
        public override async Task <int> ExecuteAsync()
        {
            if ((_options.Enable && _options.Disable) ||
                (!_options.Enable && !_options.Disable))
            {
                Console.WriteLine("Please specify either --enable or --disable");
                return(Constants.ErrorCode);
            }

            string presentTenseStatusMessage = _options.Enable ? "enable" : "disable";
            string pastTenseStatusMessage    = _options.Enable ? "enabled" : "disabled";
            string actionStatusMessage       = _options.Enable ? "Enabling" : "Disabling";

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

                bool noConfirm = _options.NoConfirmation;
                List <Subscription> subscriptionsToEnableDisable = 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);

                        subscriptionsToEnableDisable.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 {pastTenseStatusMessage} (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);
                    }

                    subscriptionsToEnableDisable.AddRange(subscriptions);
                }

                // Filter away subscriptions that already have the desired state:
                subscriptionsToEnableDisable = subscriptionsToEnableDisable.Where(s => s.Enabled != _options.Enable).ToList();

                if (!subscriptionsToEnableDisable.Any())
                {
                    Console.WriteLine($"All subscriptions are already {pastTenseStatusMessage}.");
                    return(Constants.SuccessCode);
                }

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

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

                Console.Write($"{actionStatusMessage} {subscriptionsToEnableDisable.Count} subscriptions...{(noConfirm ? Environment.NewLine : "")}");
                foreach (var subscription in subscriptionsToEnableDisable)
                {
                    // If noConfirm was passed, print out the subscriptions as we go
                    if (noConfirm)
                    {
                        Console.WriteLine($"  {UxHelpers.GetSubscriptionDescription(subscription)}");
                    }

                    SubscriptionUpdate subscriptionToUpdate = new SubscriptionUpdate
                    {
                        ChannelName      = subscription.Channel.Name,
                        SourceRepository = subscription.SourceRepository,
                        Enabled          = _options.Enable,
                        Policy           = subscription.Policy
                    };
                    subscriptionToUpdate.Policy.Batchable       = subscription.Policy.Batchable;
                    subscriptionToUpdate.Policy.UpdateFrequency = subscription.Policy.UpdateFrequency;
                    subscriptionToUpdate.Policy.MergePolicies   = subscription.Policy.MergePolicies;

                    var updatedSubscription = await remote.UpdateSubscriptionAsync(
                        subscription.Id.ToString(),
                        subscriptionToUpdate);
                }
                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 {actionStatusMessage.ToLower()} subscriptions.");
                return(Constants.ErrorCode);
            }
        }
        /// <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.StatusCode == HttpStatusCode.NotFound)
                    {
                        Console.WriteLine($"Subscription with id '{_options.Id}' was not found.");
                        return(Constants.ErrorCode);
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(_options.TargetRepository) &&
                        string.IsNullOrEmpty(_options.TargetBranch) &&
                        string.IsNullOrEmpty(_options.SourceRepository) &&
                        string.IsNullOrEmpty(_options.Channel))
                    {
                        Console.WriteLine($"Please specify one or more filters to select which subscriptions should be triggered (see help).");
                        return(Constants.ErrorCode);
                    }

                    IEnumerable <Subscription> subscriptions = (await remote.GetSubscriptionsAsync()).Where(subscription =>
                    {
                        return(_options.SubcriptionFilter(subscription));
                    });

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

                    subscriptionsToTrigger.AddRange(subscriptions);
                }

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

                    char keyChar;
                    do
                    {
                        Console.Write("Continue? (y/n) ");
                        ConsoleKeyInfo keyInfo = Console.ReadKey();
                        keyChar = char.ToUpperInvariant(keyInfo.KeyChar);
                        Console.WriteLine();
                    }while (keyChar != 'Y' && keyChar != 'N');

                    if (keyChar == 'N')
                    {
                        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)}");
                    }
                    await remote.TriggerSubscriptionAsync(subscription.Id.ToString());
                }
                Console.WriteLine($"done");

                return(Constants.SuccessCode);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Unexpected error while triggering subscriptions.");
                return(Constants.ErrorCode);
            }
        }
        /// <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);
            }
        }
        /// <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 (!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)}");
                    }
                    await remote.TriggerSubscriptionAsync(subscription.Id.ToString());
                }
                Console.WriteLine("done");

                return(Constants.SuccessCode);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Unexpected error while triggering subscriptions.");
                return(Constants.ErrorCode);
            }
        }
        /// <summary>
        ///     Compute the subscription health metrics to run based on the channels and input repositories
        /// </summary>
        /// <param name="channelsToEvaluate">Channels in the initial set.</param>
        /// <param name="reposToEvaluate">Repositories in the initial set.</param>
        /// <param name="subscriptions">Subscriptions in the build asset registry.</param>
        /// <returns>List of subscription health metrics</returns>
        /// <remarks>
        ///     Subscription health is based on repo and branch.  We need to find all the combinations that
        ///     that make sense to evaluate.
        ///
        ///     Since this is a target-of-subscription focused metric, use the set of target repos+branches from
        ///     <paramref name="subscriptions"/> where the target repo is in <paramref name="reposToEvaluate"/> and
        ///     the source channel is in <paramref name="channelsToEvaluate"/> or the target branch is in branches.
        ///     Also add in repos (in <paramref name="reposToEvaluate"/>) who have a default channel association targeting
        ///     a channel in <paramref name="channelsToEvaluate"/>
        ///
        ///     Note that this will currently miss completely untargeted branches, until those have at least one
        ///     default channel or subscription. This is a fairly benign limitation.
        /// </remarks>
        private List <Func <Task <HealthMetricWithOutput> > > ComputeSubscriptionHealthMetricsToRun(HashSet <string> channelsToEvaluate,
                                                                                                    HashSet <string> reposToEvaluate, IEnumerable <Subscription> subscriptions, IEnumerable <DefaultChannel> defaultChannels)
        {
            IRemoteFactory remoteFactory = new RemoteFactory(_options);

            HashSet <(string repo, string branch)> repoBranchCombinations =
                GetRepositoryBranchCombinations(channelsToEvaluate, reposToEvaluate, subscriptions, defaultChannels);

            return(repoBranchCombinations.Select <(string repo, string branch), Func <Task <HealthMetricWithOutput> > >(t =>
                                                                                                                        async() =>
            {
                SubscriptionHealthMetric healthMetric = new SubscriptionHealthMetric(t.repo, t.branch,
                                                                                     d => true, Logger, remoteFactory);

                await healthMetric.EvaluateAsync();

                StringBuilder outputBuilder = new StringBuilder();

                if (healthMetric.ConflictingSubscriptions.Any())
                {
                    outputBuilder.AppendLine($"  Conflicting subscriptions:");
                    foreach (var conflict in healthMetric.ConflictingSubscriptions)
                    {
                        outputBuilder.AppendLine($"    {conflict.Asset} would be updated by the following subscriptions:");
                        foreach (var subscription in conflict.Subscriptions)
                        {
                            outputBuilder.AppendLine($"      {UxHelpers.GetSubscriptionDescription(subscription)} ({subscription.Id})");
                        }
                    }
                }

                if (healthMetric.DependenciesMissingSubscriptions.Any())
                {
                    outputBuilder.AppendLine($"  Dependencies missing subscriptions:");
                    foreach (DependencyDetail dependency in healthMetric.DependenciesMissingSubscriptions)
                    {
                        outputBuilder.AppendLine($"    {dependency.Name}");
                    }
                }

                if (healthMetric.DependenciesThatDoNotFlow.Any())
                {
                    outputBuilder.AppendLine($"  Dependencies that do not flow automatically (disabled or frequency=none):");
                    foreach (DependencyDetail dependency in healthMetric.DependenciesThatDoNotFlow)
                    {
                        outputBuilder.AppendLine($"    {dependency.Name}");
                    }
                }

                if (healthMetric.UnusedSubscriptions.Any())
                {
                    outputBuilder.AppendLine($"  Subscriptions that do not have any effect:");
                    foreach (Subscription subscription in healthMetric.UnusedSubscriptions)
                    {
                        outputBuilder.AppendLine($"    {UxHelpers.GetSubscriptionDescription(subscription)} ({subscription.Id})");
                    }
                }

                return new HealthMetricWithOutput(healthMetric, outputBuilder.ToString());
            })
                   .ToList());
        }