diff --git a/src/chocolatey.tests/chocolatey.tests.csproj b/src/chocolatey.tests/chocolatey.tests.csproj
index 0afc2017fd..9033d98df5 100644
--- a/src/chocolatey.tests/chocolatey.tests.csproj
+++ b/src/chocolatey.tests/chocolatey.tests.csproj
@@ -68,6 +68,7 @@
+
diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyOutdatedCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyOutdatedCommandSpecs.cs
new file mode 100644
index 0000000000..4a67f2dad1
--- /dev/null
+++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyOutdatedCommandSpecs.cs
@@ -0,0 +1,142 @@
+// 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.infrastructure.app.commands
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Moq;
+ using Should;
+ using chocolatey.infrastructure.app.attributes;
+ using chocolatey.infrastructure.app.commands;
+ using chocolatey.infrastructure.app.configuration;
+ using chocolatey.infrastructure.app.domain;
+ using chocolatey.infrastructure.app.services;
+ using chocolatey.infrastructure.commandline;
+
+ public class ChocolateyOutdatedCommandSpecs
+ {
+ public abstract class ChocolateyOutdatedCommandSpecsBase : TinySpec
+ {
+ protected ChocolateyOutdatedCommand command;
+ protected Mock packageService = new Mock();
+ protected ChocolateyConfiguration configuration = new ChocolateyConfiguration();
+
+ public override void Context()
+ {
+ configuration.Sources = "bob";
+ command = new ChocolateyOutdatedCommand(packageService.Object);
+ }
+ }
+
+ public class when_implementing_command_for : ChocolateyOutdatedCommandSpecsBase
+ {
+ private List results;
+
+ public override void Because()
+ {
+ results = command.GetType().GetCustomAttributes(typeof (CommandForAttribute), false).Cast().Select(a => a.CommandName).ToList();
+ }
+
+ [Fact]
+ public void should_implement_outdated()
+ {
+ results.ShouldContain(CommandNameType.outdated.to_string());
+ }
+ }
+
+ public class when_configurating_the_argument_parser : ChocolateyOutdatedCommandSpecsBase
+ {
+ private OptionSet optionSet;
+
+ public override void Context()
+ {
+ base.Context();
+ optionSet = new OptionSet();
+ }
+
+ public override void Because()
+ {
+ command.configure_argument_parser(optionSet, configuration);
+ }
+
+ [Fact]
+ public void should_add_source_to_the_option_set()
+ {
+ optionSet.Contains("source").ShouldBeTrue();
+ }
+
+ [Fact]
+ public void should_add_short_version_of_source_to_the_option_set()
+ {
+ optionSet.Contains("s").ShouldBeTrue();
+ }
+
+ [Fact]
+ public void should_add_user_to_the_option_set()
+ {
+ optionSet.Contains("user").ShouldBeTrue();
+ }
+
+ [Fact]
+ public void should_add_short_version_of_user_to_the_option_set()
+ {
+ optionSet.Contains("u").ShouldBeTrue();
+ }
+
+ [Fact]
+ public void should_add_password_to_the_option_set()
+ {
+ optionSet.Contains("password").ShouldBeTrue();
+ }
+
+ [Fact]
+ public void should_add_short_version_of_password_to_the_option_set()
+ {
+ optionSet.Contains("p").ShouldBeTrue();
+ }
+
+ }
+
+ public class when_noop_is_called : ChocolateyOutdatedCommandSpecsBase
+ {
+ public override void Because()
+ {
+ command.noop(configuration);
+ }
+
+ [Fact]
+ public void should_call_service_outdated_noop()
+ {
+ packageService.Verify(c => c.outdated_noop(configuration), Times.Once);
+ }
+ }
+
+ public class when_run_is_called : ChocolateyOutdatedCommandSpecsBase
+ {
+ public override void Because()
+ {
+ command.run(configuration);
+ }
+
+ [Fact]
+ public void should_call_service_oudated_run()
+ {
+ packageService.Verify(c => c.outdated_run(configuration), Times.Once);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/chocolatey/chocolatey.csproj b/src/chocolatey/chocolatey.csproj
index f75bdca93a..2daec58295 100644
--- a/src/chocolatey/chocolatey.csproj
+++ b/src/chocolatey/chocolatey.csproj
@@ -81,6 +81,7 @@
+
diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs
new file mode 100644
index 0000000000..7a608c6959
--- /dev/null
+++ b/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs
@@ -0,0 +1,102 @@
+// 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.infrastructure.app.commands
+{
+ using System.Collections.Generic;
+ using attributes;
+ using commandline;
+ using configuration;
+ using domain;
+ using infrastructure.commands;
+ using logging;
+ using services;
+
+ [CommandFor(CommandNameType.outdated)]
+ public sealed class ChocolateyOutdatedCommand : ICommand
+ {
+ private readonly IChocolateyPackageService _packageService;
+
+ public ChocolateyOutdatedCommand(IChocolateyPackageService packageService)
+ {
+ _packageService = packageService;
+ }
+
+ public void configure_argument_parser(OptionSet optionSet, ChocolateyConfiguration configuration)
+ {
+ optionSet
+ .Add("s=|source=",
+ "Source - The source to find the package(s) to install. Special sources include: ruby, webpi, cygwin, windowsfeatures, and python. Defaults to default feeds.",
+ option => configuration.Sources = option.remove_surrounding_quotes())
+ .Add("u=|user=",
+ "User - used with authenticated feeds. Defaults to empty.",
+ option => configuration.SourceCommand.Username = option.remove_surrounding_quotes())
+ .Add("p=|password=",
+ "Password - the user's password to the source. Defaults to empty.",
+ option => configuration.SourceCommand.Password = option.remove_surrounding_quotes())
+ ;
+ }
+
+ public void handle_additional_argument_parsing(IList unparsedArguments, ChocolateyConfiguration configuration)
+ {
+ configuration.Input = string.Join(" ", unparsedArguments);
+ configuration.PackageNames = string.Join(ApplicationParameters.PackageNamesSeparator.to_string(), unparsedArguments);
+ }
+
+ public void handle_validation(ChocolateyConfiguration configuration)
+ {
+ }
+
+ public void help_message(ChocolateyConfiguration configuration)
+ {
+ this.Log().Info(ChocolateyLoggers.Important, "Outdated Command");
+ this.Log().Info(@"
+Returns a list of outdated packages
+");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Usage");
+ "chocolatey".Log().Info(@"
+ choco outdated []
+");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Examples");
+ "chocolatey".Log().Info(@"
+ choco outdated
+ choco outdated -s ""https://somewhere/out/there""
+ choco outdated -s ""https://somewhere/protected"" -u user -p pass
+
+If you use `--source=https://somewhere/out/there`, it is
+ going to look for outdated packages only based on that source.
+");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches");
+ }
+
+ public void noop(ChocolateyConfiguration configuration)
+ {
+ _packageService.outdated_noop(configuration);
+ }
+
+ public void run(ChocolateyConfiguration configuration)
+ {
+ _packageService.outdated_run(configuration);
+ }
+
+ public bool may_require_admin_access()
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
index dadd8b4322..7b6abd6984 100644
--- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
+++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
@@ -313,6 +313,7 @@ public sealed class ListCommandConfiguration
public sealed class UpgradeCommandConfiguration
{
public bool FailOnUnfound { get; set; }
+ public bool NotifyOnlyAvailableUpgrades { get; set; }
}
[Serializable]
diff --git a/src/chocolatey/infrastructure.app/domain/CommandNameType.cs b/src/chocolatey/infrastructure.app/domain/CommandNameType.cs
index 334ad2f4c3..d2e54a032f 100644
--- a/src/chocolatey/infrastructure.app/domain/CommandNameType.cs
+++ b/src/chocolatey/infrastructure.app/domain/CommandNameType.cs
@@ -27,6 +27,7 @@ public enum CommandNameType
//[Description("update - updates package index")] update,
[Description("update - [DEPRECATED] RESERVED for future use (you are looking for upgrade, these are not the droids you are looking for)")] update,
[Description("upgrade - upgrades packages from various sources")] upgrade,
+ [Description("outdated - retrieves packages that are outdated. Similar to upgrade all --noop")] outdated,
[Description("uninstall - uninstalls a package")] uninstall,
[Description("source - view and configure default sources")] source,
[Description("sources - view and configure default sources (alias for source)")]
diff --git a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
index 794b3463b5..fd35fb716a 100644
--- a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
+++ b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
@@ -72,6 +72,7 @@ public void RegisterComponents(Container container)
new ChocolateyListCommand(container.GetInstance()),
new ChocolateyInstallCommand(container.GetInstance()),
new ChocolateyPinCommand(container.GetInstance(), container.GetInstance(), container.GetInstance()),
+ new ChocolateyOutdatedCommand(container.GetInstance()),
new ChocolateyUpgradeCommand(container.GetInstance()),
new ChocolateyUninstallCommand(container.GetInstance()),
new ChocolateyPackCommand(container.GetInstance()),
diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs
index aa8db5f3ba..2cddc469d6 100644
--- a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs
+++ b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs
@@ -284,6 +284,48 @@ public ConcurrentDictionary install_run(ChocolateyConfigu
return packageInstalls;
}
+ public void outdated_noop(ChocolateyConfiguration config)
+ {
+ this.Log().Info(@"
+Would have determined packages that are out of date based on what is
+ installed and what versions are available for upgrade.");
+ }
+
+ public void outdated_run(ChocolateyConfiguration config)
+ {
+ this.Log().Info(ChocolateyLoggers.Important, @"Outdated Packages
+ Output is package name | current version | available version | pinned?
+");
+
+ config.PackageNames = ApplicationParameters.AllPackages;
+ config.UpgradeCommand.NotifyOnlyAvailableUpgrades = true;
+
+ var output = config.RegularOutput;
+ config.RegularOutput = false;
+ var oudatedPackages = _nugetService.upgrade_noop(config, null);
+ config.RegularOutput = output;
+
+ if (config.RegularOutput)
+ {
+ var upgradeWarnings = oudatedPackages.Count(p => p.Value.Warning);
+ this.Log().Warn(() => @"{0}{1} has determined {2} package(s) are outdated. {3}.".format_with(
+ Environment.NewLine,
+ ApplicationParameters.Name,
+ oudatedPackages.Count(p => p.Value.Success && !p.Value.Inconclusive),
+ upgradeWarnings == 0 ? string.Empty : "{0} {1} package(s) had warnings.".format_with(Environment.NewLine, upgradeWarnings)
+ ));
+
+ if (upgradeWarnings != 0)
+ {
+ this.Log().Warn(ChocolateyLoggers.Important, "Warnings:");
+ foreach (var warning in oudatedPackages.Where(p => p.Value.Warning).or_empty_list_if_null())
+ {
+ this.Log().Warn(ChocolateyLoggers.Important, " - {0}".format_with(warning.Value.Name));
+ }
+ }
+ }
+ }
+
private IEnumerable set_config_from_package_names_and_packages_config(ChocolateyConfiguration config, ConcurrentDictionary packageInstalls)
{
// if there are any .config files, split those off of the config. Then return the config without those package names.
diff --git a/src/chocolatey/infrastructure.app/services/IChocolateyPackageService.cs b/src/chocolatey/infrastructure.app/services/IChocolateyPackageService.cs
index 7e468977a5..45b0e2f206 100644
--- a/src/chocolatey/infrastructure.app/services/IChocolateyPackageService.cs
+++ b/src/chocolatey/infrastructure.app/services/IChocolateyPackageService.cs
@@ -75,6 +75,18 @@ public interface IChocolateyPackageService
/// results of installs
ConcurrentDictionary install_run(ChocolateyConfiguration config);
+ ///
+ /// Run outdated in noop mode
+ ///
+ /// The configuration.
+ void outdated_noop(ChocolateyConfiguration config);
+
+ ///
+ /// Determines all packages that are out of date
+ ///
+ /// The configuration.
+ void outdated_run(ChocolateyConfiguration config);
+
///
/// Run upgrade in noop mode
///
diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs
index b9359f10b2..1c2ccc30f5 100644
--- a/src/chocolatey/infrastructure.app/services/NugetService.cs
+++ b/src/chocolatey/infrastructure.app/services/NugetService.cs
@@ -505,14 +505,18 @@ packages as of version 1.0.0. That is what the install command is for.
string logMessage = "{0} v{1} is newer than the most recent.{2} You must be smarter than the average bear...".format_with(installedPackage.Id, installedPackage.Version, Environment.NewLine);
packageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, logMessage));
- if (config.RegularOutput)
- {
- this.Log().Info(ChocolateyLoggers.Important, logMessage);
- }
- else
+ if (!config.UpgradeCommand.NotifyOnlyAvailableUpgrades)
{
- this.Log().Info("{0}|{1}|{1}|{2}".format_with(installedPackage.Id, installedPackage.Version, isPinned.to_string().to_lower()));
+ if (config.RegularOutput)
+ {
+ this.Log().Info(ChocolateyLoggers.Important, logMessage);
+ }
+ else
+ {
+ this.Log().Info("{0}|{1}|{1}|{2}".format_with(installedPackage.Id, installedPackage.Version, isPinned.to_string().to_lower()));
+ }
}
+
continue;
}
@@ -527,15 +531,18 @@ packages as of version 1.0.0. That is what the install command is for.
packageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, logMessage));
}
- if (config.RegularOutput)
- {
- this.Log().Info(logMessage);
- }
- else
+ if (!config.UpgradeCommand.NotifyOnlyAvailableUpgrades)
{
- this.Log().Info("{0}|{1}|{2}|{3}".format_with(installedPackage.Id, installedPackage.Version, availablePackage.Version, isPinned.to_string().to_lower()));
+ if (config.RegularOutput)
+ {
+ this.Log().Info(logMessage);
+ }
+ else
+ {
+ this.Log().Info("{0}|{1}|{2}|{3}".format_with(installedPackage.Id, installedPackage.Version, availablePackage.Version, isPinned.to_string().to_lower()));
+ }
}
-
+
continue;
}
@@ -547,7 +554,7 @@ packages as of version 1.0.0. That is what the install command is for.
{
if (availablePackage.Version > installedPackage.Version)
{
- string logMessage = "You have {0} v{1} installed. Version {2} is available based on your source(s)".format_with(installedPackage.Id, installedPackage.Version, availablePackage.Version);
+ string logMessage = "You have {0} v{1} installed. Version {2} is available based on your source(s).".format_with(installedPackage.Id, installedPackage.Version, availablePackage.Version);
packageResult.Messages.Add(new ResultMessage(ResultType.Note, logMessage));
if (config.RegularOutput)