diff --git a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj index 30fddbaff6..a7a6209a26 100644 --- a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj +++ b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj @@ -86,6 +86,7 @@ + diff --git a/src/chocolatey.tests.integration/scenarios/UpgradeAllScenarios.cs b/src/chocolatey.tests.integration/scenarios/UpgradeAllScenarios.cs new file mode 100644 index 0000000000..c6132754b4 --- /dev/null +++ b/src/chocolatey.tests.integration/scenarios/UpgradeAllScenarios.cs @@ -0,0 +1,105 @@ +// Copyright © 2011 - Present RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.tests.integration.scenarios +{ + using System.Collections.Concurrent; + using System.Linq; + using NuGet; + using Should; + using bdddoc.core; + using chocolatey.infrastructure.app.commands; + using chocolatey.infrastructure.app.configuration; + using chocolatey.infrastructure.app.services; + using chocolatey.infrastructure.results; + + public class UpgradeAllScenarios + { + public abstract class ScenariosBase : TinySpec + { + protected ConcurrentDictionary Results; + protected ChocolateyConfiguration Configuration; + protected IChocolateyPackageService Service; + + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Configuration.PackageNames = Configuration.Input = "all"; + Scenario.add_packages_to_source_location(Configuration, "upgradepackage*" + Constants.PackageExtension); + Scenario.add_packages_to_source_location(Configuration, "installpackage*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "installpackage", "1.0.0"); + Scenario.install_package(Configuration, "upgradepackage", "1.0.0"); + Configuration.SkipPackageInstallProvider = true; + + Service = NUnitSetup.Container.GetInstance(); + } + } + + [Concern(typeof (ChocolateyUpgradeCommand))] + public class when_upgrading_all_packages_happy_path : ScenariosBase + { + public override void Because() + { + Results = Service.upgrade_run(Configuration); + } + + [Fact] + public void should_report_for_all_installed_packages() + { + Results.Count().ShouldEqual(2); + } + + [Fact] + public void should_upgrade_packages_with_upgrades() + { + var upgradePackageResult = Results.Where(x => x.Key == "upgradepackage").ToList(); + upgradePackageResult.Count.ShouldEqual(1, "upgradepackage must be there once"); + upgradePackageResult.First().Value.Version.ShouldEqual("1.1.0"); + } + + [Fact] + public void should_skip_packages_without_upgrades() + { + var installPackageResult = Results.Where(x => x.Key == "installpackage").ToList(); + installPackageResult.Count.ShouldEqual(1, "installpackage must be there once"); + installPackageResult.First().Value.Version.ShouldEqual("1.0.0"); + } + } + + [Concern(typeof(ChocolateyUpgradeCommand))] + public class when_upgrading_all_packages_with_except : ScenariosBase + { + public override void Because() + { + Configuration.UpgradeCommand.PackageNamesToSkip = "upgradepackage"; + Results = Service.upgrade_run(Configuration); + } + + [Fact] + public void should_report_for_all_non_skipped_packages() + { + Results.Count().ShouldEqual(1); + } + + [Fact] + public void should_skip_packages_in_except_list() + { + var upgradePackageResult = Results.Where(x => x.Key == "upgradepackage").ToList(); + upgradePackageResult.Count.ShouldEqual(0, "upgradepackage should not be in the results list"); + } + } + } +} \ No newline at end of file diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs index a5b0763faf..b8b6674142 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs @@ -85,6 +85,9 @@ public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyCon .Add("p=|password=", "Password - the user's password to the source. Defaults to empty.", option => configuration.SourceCommand.Password = option.remove_surrounding_quotes()) + .Add("except=", + "Except - a comma-separated list of package names that should not be upgraded when upgrading 'all'. Defaults to empty.", + option => configuration.UpgradeCommand.PackageNamesToSkip = option.remove_surrounding_quotes()) ; } @@ -128,6 +131,8 @@ choco upgrade notepadplusplus googlechrome atom 7zip -dvfy choco upgrade nodejs.install --version 0.10.35 choco upgrade git -s ""https://somewhere/out/there"" choco upgrade git -s ""https://somewhere/protected"" -u user -p pass + choco upgrade all + choco upgrade all --except=""skype,conemu"" "); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 8ecd74249d..144b0568d9 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -333,6 +333,7 @@ public sealed class UpgradeCommandConfiguration public bool FailOnUnfound { get; set; } public bool FailOnNotInstalled { get; set; } public bool NotifyOnlyAvailableUpgrades { get; set; } + public string PackageNamesToSkip { get; set; } } [Serializable] diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 4711f1717d..86945fa31f 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1047,13 +1047,45 @@ private void set_package_names_if_all_is_specified(ChocolateyConfiguration confi var quiet = config.QuietOutput; config.QuietOutput = true; - config.PackageNames = list_run(config).Select(p => p.Name).@join(ApplicationParameters.PackageNamesSeparator); - + var packagesToUpdate = list_run(config).Select(p => p.Name).ToList(); + + if (!String.IsNullOrWhiteSpace(config.UpgradeCommand.PackageNamesToSkip)) + { + var packagesToSkip = config.UpgradeCommand.PackageNamesToSkip + .Split(',') + .Where(x => !String.IsNullOrWhiteSpace(x)) + .Select(x => x.trim_safe()) + .ToList(); + + var unknownPackagesToSkip = packagesToSkip + .Where(x => !packagesToUpdate.Contains(x, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + if (unknownPackagesToSkip.Any()) + { + this.Log().Warn(() => "Some packages specified in the 'except' list were not found in the local packages: '{0}'".format_with(String.Join(",", unknownPackagesToSkip))); + + packagesToSkip = packagesToSkip + .Where(x => !unknownPackagesToSkip.Contains(x)) + .ToList(); + } + + if (packagesToSkip.Any()) + { + packagesToUpdate = packagesToUpdate + .Where(x => !packagesToSkip.Contains(x, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + this.Log().Info("These packages will not be upgraded because they were specified in the 'except' list: {0}".format_with(String.Join(",", packagesToSkip))); + } + } + config.QuietOutput = quiet; config.Input = input; config.Noop = noop; config.Prerelease = pre; config.Sources = sources; + config.PackageNames = packagesToUpdate.@join(ApplicationParameters.PackageNamesSeparator); if (customAction != null) customAction.Invoke(); }