From 5594c564f48befdb5f3c71a0da9b0cfe8446ad9d Mon Sep 17 00:00:00 2001 From: Michael Noonan Date: Mon, 9 May 2016 14:21:24 +1000 Subject: [PATCH] Line endings! --- .../Commands/CreateReleaseCommandFixture.cs | 72 +-- .../Octopus.Cli.Tests.csproj | 250 +++++----- .../Commands/ChannelVersionRuleTester.cs | 44 +- .../Commands/DeleteReleasesCommand.cs | 226 ++++----- .../Commands/IChannelVersionRuleTester.cs | 20 +- .../Commands/IReleasePlanBuilder.cs | 18 +- .../Commands/ReleasePlanBuilder.cs | 228 ++++----- .../Model/ChannelVersionRuleTestResult.cs | 42 +- source/Octopus.Cli/Octopus.Cli.csproj | 458 +++++++++--------- .../Util/ResourceCollectionExtensions.cs | 66 +-- 10 files changed, 712 insertions(+), 712 deletions(-) diff --git a/source/Octopus.Cli.Tests/Commands/CreateReleaseCommandFixture.cs b/source/Octopus.Cli.Tests/Commands/CreateReleaseCommandFixture.cs index d6d021f48..da7445ca3 100644 --- a/source/Octopus.Cli.Tests/Commands/CreateReleaseCommandFixture.cs +++ b/source/Octopus.Cli.Tests/Commands/CreateReleaseCommandFixture.cs @@ -1,37 +1,37 @@ -using NSubstitute; -using NUnit.Framework; -using Octopus.Cli.Commands; -using Octopus.Cli.Infrastructure; -using Octopus.Cli.Tests.Helpers; -using Octopus.Cli.Util; - -namespace Octopus.Cli.Tests.Commands -{ - public class CreateReleaseCommandFixture : ApiCommandFixtureBase - { - CreateReleaseCommand createReleaseCommand; - IPackageVersionResolver versionResolver; - IReleasePlanBuilder releasePlanBuilder; - - [SetUp] - public void SetUp() - { - versionResolver = Substitute.For(); - releasePlanBuilder = Substitute.For(); - } - - [Test] - public void ShouldLoadOptionsFromFile() - { - createReleaseCommand = new CreateReleaseCommand(RepositoryFactory, Log, new OctopusPhysicalFileSystem(Log), versionResolver, releasePlanBuilder); - - Assert.Throws(delegate { - createReleaseCommand.Execute("--configfile=Commands/Resources/CreateRelease.config.txt"); - }); - - Assert.AreEqual("Test Project", createReleaseCommand.ProjectName); - Assert.AreEqual("1.0.0", createReleaseCommand.VersionNumber); - Assert.AreEqual("Test config file.", createReleaseCommand.ReleaseNotes); - } - } +using NSubstitute; +using NUnit.Framework; +using Octopus.Cli.Commands; +using Octopus.Cli.Infrastructure; +using Octopus.Cli.Tests.Helpers; +using Octopus.Cli.Util; + +namespace Octopus.Cli.Tests.Commands +{ + public class CreateReleaseCommandFixture : ApiCommandFixtureBase + { + CreateReleaseCommand createReleaseCommand; + IPackageVersionResolver versionResolver; + IReleasePlanBuilder releasePlanBuilder; + + [SetUp] + public void SetUp() + { + versionResolver = Substitute.For(); + releasePlanBuilder = Substitute.For(); + } + + [Test] + public void ShouldLoadOptionsFromFile() + { + createReleaseCommand = new CreateReleaseCommand(RepositoryFactory, Log, new OctopusPhysicalFileSystem(Log), versionResolver, releasePlanBuilder); + + Assert.Throws(delegate { + createReleaseCommand.Execute("--configfile=Commands/Resources/CreateRelease.config.txt"); + }); + + Assert.AreEqual("Test Project", createReleaseCommand.ProjectName); + Assert.AreEqual("1.0.0", createReleaseCommand.VersionNumber); + Assert.AreEqual("Test config file.", createReleaseCommand.ReleaseNotes); + } + } } \ No newline at end of file diff --git a/source/Octopus.Cli.Tests/Octopus.Cli.Tests.csproj b/source/Octopus.Cli.Tests/Octopus.Cli.Tests.csproj index 5a44f949b..3e386ebc8 100644 --- a/source/Octopus.Cli.Tests/Octopus.Cli.Tests.csproj +++ b/source/Octopus.Cli.Tests/Octopus.Cli.Tests.csproj @@ -1,126 +1,126 @@ - - - - Debug - AnyCPU - {B05E3858-5607-46DB-876C-4E1F5728A4BB} - Library - Properties - Octopus.Cli.Tests - Octopus.Cli.Tests - v4.5 - 512 - ..\ - true - - - - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - x86 - false - - - pdbonly - true - bin\ - TRACE - prompt - 4 - true - false - - - - ..\packages\log4net.2.0.2\lib\net40-full\log4net.dll - - - ..\packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll - True - - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - - ..\packages\Octopus.Client.3.3.9\lib\net40\Octopus.Client.dll - True - - - - - - - - - - - ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll - - - - - Properties\SolutionInfo.cs - - - Properties\VersionInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - {D1BFD88F-FB8E-49EC-968F-F4D9A8A52519} - OctopusTools - - - - - - PreserveNewest - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + Debug + AnyCPU + {B05E3858-5607-46DB-876C-4E1F5728A4BB} + Library + Properties + Octopus.Cli.Tests + Octopus.Cli.Tests + v4.5 + 512 + ..\ + true + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + x86 + false + + + pdbonly + true + bin\ + TRACE + prompt + 4 + true + false + + + + ..\packages\log4net.2.0.2\lib\net40-full\log4net.dll + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll + True + + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + ..\packages\Octopus.Client.3.3.9\lib\net40\Octopus.Client.dll + True + + + + + + + + + + + ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll + + + + + Properties\SolutionInfo.cs + + + Properties\VersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + {D1BFD88F-FB8E-49EC-968F-F4D9A8A52519} + OctopusTools + + + + + + PreserveNewest + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/source/Octopus.Cli/Commands/ChannelVersionRuleTester.cs b/source/Octopus.Cli/Commands/ChannelVersionRuleTester.cs index 9e9854b0f..eb5b51363 100644 --- a/source/Octopus.Cli/Commands/ChannelVersionRuleTester.cs +++ b/source/Octopus.Cli/Commands/ChannelVersionRuleTester.cs @@ -1,22 +1,22 @@ -using Octopus.Cli.Model; -using Octopus.Client; -using Octopus.Client.Model; - -namespace Octopus.Cli.Commands -{ - public class ChannelVersionRuleTester : IChannelVersionRuleTester - { - public ChannelVersionRuleTestResult Test(IOctopusRepository repository, ChannelVersionRuleResource rule, string packageVersion) - { - var link = repository.Client.RootDocument.Link("VersionRuleTest"); - var response = repository.Client.Get(link, new - { - version = packageVersion, - versionRange = rule.VersionRange, - preReleaseTag = rule.Tag - }); - - return response; - } - } -} +using Octopus.Cli.Model; +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Commands +{ + public class ChannelVersionRuleTester : IChannelVersionRuleTester + { + public ChannelVersionRuleTestResult Test(IOctopusRepository repository, ChannelVersionRuleResource rule, string packageVersion) + { + var link = repository.Client.RootDocument.Link("VersionRuleTest"); + var response = repository.Client.Get(link, new + { + version = packageVersion, + versionRange = rule.VersionRange, + preReleaseTag = rule.Tag + }); + + return response; + } + } +} diff --git a/source/Octopus.Cli/Commands/DeleteReleasesCommand.cs b/source/Octopus.Cli/Commands/DeleteReleasesCommand.cs index 47d70cade..f77d92db5 100644 --- a/source/Octopus.Cli/Commands/DeleteReleasesCommand.cs +++ b/source/Octopus.Cli/Commands/DeleteReleasesCommand.cs @@ -1,114 +1,114 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using log4net; -using Octopus.Cli.Infrastructure; -using Octopus.Cli.Util; -using Octopus.Client.Model; - -namespace Octopus.Cli.Commands -{ - [Command("delete-releases", Description = "Deletes a range of releases")] - public class DeleteReleasesCommand : ApiCommand - { - public DeleteReleasesCommand(IOctopusRepositoryFactory repositoryFactory, ILog log, IOctopusFileSystem fileSystem) - : base(repositoryFactory, log, fileSystem) - { - var options = Options.For("Deletion"); - options.Add("project=", "Name of the project", v => ProjectName = v); - options.Add("minversion=", "Minimum (inclusive) version number for the range of versions to delete", v => MinVersion = v); - options.Add("maxversion=", "Maximum (inclusive) version number for the range of versions to delete", v => MaxVersion = v); - options.Add("channel=", "[Optional] if specified, only releases associated with the channel will be deleted; specify this argument multiple times to target multiple channels.", v => ChannelNames.Add(v)); - options.Add("whatif", "[Optional, Flag] if specified, releases won't actually be deleted, but will be listed as if simulating the command", v => WhatIf = true); - } - - public string ProjectName { get; set; } - public string MaxVersion { get; set; } - public string MinVersion { get; set; } - public List ChannelNames { get; } = new List(); - public bool WhatIf { get; set; } - - protected override void Execute() - { - if (ChannelNames.Any() && !Repository.SupportsChannels()) throw new CommandException("Your Octopus server does not support channels, which was introduced in Octopus 3.2. Please upgrade your Octopus server, or remove the --channel arguments."); - if (string.IsNullOrWhiteSpace(ProjectName)) throw new CommandException("Please specify a project name using the parameter: --project=XYZ"); - if (string.IsNullOrWhiteSpace(MinVersion)) throw new CommandException("Please specify a minimum version number using the parameter: --minversion=X.Y.Z"); - if (string.IsNullOrWhiteSpace(MaxVersion)) throw new CommandException("Please specify a maximum version number using the parameter: --maxversion=X.Y.Z"); - - var min = SemanticVersion.Parse(MinVersion); - var max = SemanticVersion.Parse(MaxVersion); - - var project = GetProject(); - var channels = GetChannelIds(project); - - Log.Debug("Finding releases for project..."); - - var releases = Repository.Projects.GetReleases(project); - var toDelete = new List(); - while (releases.Items.Count > 0) - { - foreach (var release in releases.Items) - { - if (channels.Any() && !channels.Contains(release.ChannelId)) - continue; - - var version = SemanticVersion.Parse(release.Version); - if (min > version || version > max) - continue; - - if (WhatIf) - { - Log.InfoFormat("[Whatif] Version {0} would have been deleted", version); - } - else - { - toDelete.Add(release.Link("Self")); - Log.InfoFormat("Deleting version {0}", version); - } - } - - if (!releases.HasNextPage()) - { - break; - } - - releases = Repository.Client.List(releases.NextPageLink()); - } - - if (!WhatIf) - { - foreach (var release in toDelete) - { - Repository.Client.Delete(release); - } - } - } - - private HashSet GetChannelIds(ProjectResource project) - { - if (ChannelNames.None()) - return new HashSet(); - - Log.Debug("Finding channels: " + ChannelNames.CommaSeperate()); - - var channels = Repository.Projects.GetChannels(project).GetAllPages(Repository) - .Where(c => ChannelNames.Contains(c.Name, StringComparer.InvariantCultureIgnoreCase)) - .ToArray(); - - var notFoundChannels = ChannelNames.Except(channels.Select(c => c.Name), StringComparer.InvariantCultureIgnoreCase).ToArray(); - if(notFoundChannels.Any()) - throw new CouldNotFindException("the channels named", notFoundChannels.CommaSeperate()); - - return channels.Select(c => c.Id).ToHashSet(); - } - - private ProjectResource GetProject() - { - Log.Debug("Finding project: " + ProjectName); - var project = Repository.Projects.FindByName(ProjectName); - if (project == null) - throw new CouldNotFindException("a project named", ProjectName); - return project; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using log4net; +using Octopus.Cli.Infrastructure; +using Octopus.Cli.Util; +using Octopus.Client.Model; + +namespace Octopus.Cli.Commands +{ + [Command("delete-releases", Description = "Deletes a range of releases")] + public class DeleteReleasesCommand : ApiCommand + { + public DeleteReleasesCommand(IOctopusRepositoryFactory repositoryFactory, ILog log, IOctopusFileSystem fileSystem) + : base(repositoryFactory, log, fileSystem) + { + var options = Options.For("Deletion"); + options.Add("project=", "Name of the project", v => ProjectName = v); + options.Add("minversion=", "Minimum (inclusive) version number for the range of versions to delete", v => MinVersion = v); + options.Add("maxversion=", "Maximum (inclusive) version number for the range of versions to delete", v => MaxVersion = v); + options.Add("channel=", "[Optional] if specified, only releases associated with the channel will be deleted; specify this argument multiple times to target multiple channels.", v => ChannelNames.Add(v)); + options.Add("whatif", "[Optional, Flag] if specified, releases won't actually be deleted, but will be listed as if simulating the command", v => WhatIf = true); + } + + public string ProjectName { get; set; } + public string MaxVersion { get; set; } + public string MinVersion { get; set; } + public List ChannelNames { get; } = new List(); + public bool WhatIf { get; set; } + + protected override void Execute() + { + if (ChannelNames.Any() && !Repository.SupportsChannels()) throw new CommandException("Your Octopus server does not support channels, which was introduced in Octopus 3.2. Please upgrade your Octopus server, or remove the --channel arguments."); + if (string.IsNullOrWhiteSpace(ProjectName)) throw new CommandException("Please specify a project name using the parameter: --project=XYZ"); + if (string.IsNullOrWhiteSpace(MinVersion)) throw new CommandException("Please specify a minimum version number using the parameter: --minversion=X.Y.Z"); + if (string.IsNullOrWhiteSpace(MaxVersion)) throw new CommandException("Please specify a maximum version number using the parameter: --maxversion=X.Y.Z"); + + var min = SemanticVersion.Parse(MinVersion); + var max = SemanticVersion.Parse(MaxVersion); + + var project = GetProject(); + var channels = GetChannelIds(project); + + Log.Debug("Finding releases for project..."); + + var releases = Repository.Projects.GetReleases(project); + var toDelete = new List(); + while (releases.Items.Count > 0) + { + foreach (var release in releases.Items) + { + if (channels.Any() && !channels.Contains(release.ChannelId)) + continue; + + var version = SemanticVersion.Parse(release.Version); + if (min > version || version > max) + continue; + + if (WhatIf) + { + Log.InfoFormat("[Whatif] Version {0} would have been deleted", version); + } + else + { + toDelete.Add(release.Link("Self")); + Log.InfoFormat("Deleting version {0}", version); + } + } + + if (!releases.HasNextPage()) + { + break; + } + + releases = Repository.Client.List(releases.NextPageLink()); + } + + if (!WhatIf) + { + foreach (var release in toDelete) + { + Repository.Client.Delete(release); + } + } + } + + private HashSet GetChannelIds(ProjectResource project) + { + if (ChannelNames.None()) + return new HashSet(); + + Log.Debug("Finding channels: " + ChannelNames.CommaSeperate()); + + var channels = Repository.Projects.GetChannels(project).GetAllPages(Repository) + .Where(c => ChannelNames.Contains(c.Name, StringComparer.InvariantCultureIgnoreCase)) + .ToArray(); + + var notFoundChannels = ChannelNames.Except(channels.Select(c => c.Name), StringComparer.InvariantCultureIgnoreCase).ToArray(); + if(notFoundChannels.Any()) + throw new CouldNotFindException("the channels named", notFoundChannels.CommaSeperate()); + + return channels.Select(c => c.Id).ToHashSet(); + } + + private ProjectResource GetProject() + { + Log.Debug("Finding project: " + ProjectName); + var project = Repository.Projects.FindByName(ProjectName); + if (project == null) + throw new CouldNotFindException("a project named", ProjectName); + return project; + } + } } \ No newline at end of file diff --git a/source/Octopus.Cli/Commands/IChannelVersionRuleTester.cs b/source/Octopus.Cli/Commands/IChannelVersionRuleTester.cs index 2526f3584..b8ac3f042 100644 --- a/source/Octopus.Cli/Commands/IChannelVersionRuleTester.cs +++ b/source/Octopus.Cli/Commands/IChannelVersionRuleTester.cs @@ -1,11 +1,11 @@ -using Octopus.Cli.Model; -using Octopus.Client; -using Octopus.Client.Model; - -namespace Octopus.Cli.Commands -{ - public interface IChannelVersionRuleTester - { - ChannelVersionRuleTestResult Test(IOctopusRepository repository, ChannelVersionRuleResource rule, string packageVersion); - } +using Octopus.Cli.Model; +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Commands +{ + public interface IChannelVersionRuleTester + { + ChannelVersionRuleTestResult Test(IOctopusRepository repository, ChannelVersionRuleResource rule, string packageVersion); + } } \ No newline at end of file diff --git a/source/Octopus.Cli/Commands/IReleasePlanBuilder.cs b/source/Octopus.Cli/Commands/IReleasePlanBuilder.cs index a29a726b8..35f72651d 100644 --- a/source/Octopus.Cli/Commands/IReleasePlanBuilder.cs +++ b/source/Octopus.Cli/Commands/IReleasePlanBuilder.cs @@ -1,10 +1,10 @@ -using Octopus.Client; -using Octopus.Client.Model; - -namespace Octopus.Cli.Commands -{ - public interface IReleasePlanBuilder - { - ReleasePlan Build(IOctopusRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag); - } +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Commands +{ + public interface IReleasePlanBuilder + { + ReleasePlan Build(IOctopusRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag); + } } \ No newline at end of file diff --git a/source/Octopus.Cli/Commands/ReleasePlanBuilder.cs b/source/Octopus.Cli/Commands/ReleasePlanBuilder.cs index e2abc2355..053b6ace3 100644 --- a/source/Octopus.Cli/Commands/ReleasePlanBuilder.cs +++ b/source/Octopus.Cli/Commands/ReleasePlanBuilder.cs @@ -1,115 +1,115 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using log4net; -using Octopus.Cli.Infrastructure; -using Octopus.Client; -using Octopus.Client.Model; - -namespace Octopus.Cli.Commands -{ - public class ReleasePlanBuilder : IReleasePlanBuilder - { - private readonly ILog log; - private readonly IPackageVersionResolver versionResolver; - private readonly IChannelVersionRuleTester versionRuleTester; - - public ReleasePlanBuilder(ILog log, IPackageVersionResolver versionResolver, IChannelVersionRuleTester versionRuleTester) - { - this.log = log; - this.versionResolver = versionResolver; - this.versionRuleTester = versionRuleTester; - } - - public ReleasePlan Build(IOctopusRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag) - { - if (repository == null) throw new ArgumentNullException(nameof(repository)); - if (project == null) throw new ArgumentNullException(nameof(project)); - - log.Debug("Finding deployment process..."); - var deploymentProcess = repository.DeploymentProcesses.Get(project.DeploymentProcessId); - - log.Debug("Finding release template..."); - var releaseTemplate = repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel); - - var plan = new ReleasePlan(project, channel, releaseTemplate, versionResolver); - - if (plan.UnresolvedSteps.Any()) - { - log.Debug("The package version for some steps was not specified. Going to try and resolve those automatically..."); - foreach (var unresolved in plan.UnresolvedSteps) - { - if (!unresolved.IsResolveable) - { - log.ErrorFormat("The version number for step '{0}' cannot be automatically resolved because the feed or package ID is dynamic.", unresolved.StepName); - continue; - } - - if (!string.IsNullOrEmpty(versionPreReleaseTag)) - log.DebugFormat("Finding latest package with pre-release '{1}' for step: {0}", unresolved.StepName, versionPreReleaseTag); - else - log.DebugFormat("Finding latest package for step: {0}", unresolved.StepName); - - var feed = repository.Feeds.Get(unresolved.PackageFeedId); - if (feed == null) - throw new CommandException(string.Format("Could not find a feed with ID {0}, which is used by step: " + unresolved.StepName, unresolved.PackageFeedId)); - - var filters = BuildChannelVersionFilters(unresolved.StepName, channel); - filters["packageId"] = unresolved.PackageId; - if (!string.IsNullOrWhiteSpace(versionPreReleaseTag)) - filters["preReleaseTag"] = versionPreReleaseTag; - - var packages = repository.Client.Get>(feed.Link("SearchTemplate"), filters); - var latestPackage = packages.FirstOrDefault(); - - if (latestPackage == null) - { - log.ErrorFormat("Could not find any packages with ID '{0}' in the feed '{1}'", unresolved.PackageId, feed.FeedUri); - } - else - { - log.DebugFormat("Selected '{0}' version '{1}' for '{2}'", latestPackage.NuGetPackageId, latestPackage.Version, unresolved.StepName); - unresolved.SetVersionFromLatest(latestPackage.Version); - } - } - } - - // Test each step in this plan satisfies the channel version rules - if (channel != null) - { - foreach (var step in plan.Steps) - { - var rule = - channel.Rules.SingleOrDefault( - r => r.Actions.Any(s => s.Equals(step.StepName, StringComparison.OrdinalIgnoreCase))); - if (rule == null) continue; - - var result = versionRuleTester.Test(repository, rule, step.Version); - step.SetChannelVersionRuleTestResult(result); - } - } - - return plan; - } - - IDictionary BuildChannelVersionFilters(string stepName, ChannelResource channel) - { - var filters = new Dictionary(); - - if (channel == null) - return filters; - - var rule = channel.Rules.FirstOrDefault(r => r.Actions.Contains(stepName)); - if (rule == null) - return filters; - - if (!string.IsNullOrWhiteSpace(rule.VersionRange)) - filters["versionRange"] = rule.VersionRange; - - if (!string.IsNullOrWhiteSpace(rule.Tag)) - filters["preReleaseTag"] = rule.Tag; - - return filters; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using log4net; +using Octopus.Cli.Infrastructure; +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Commands +{ + public class ReleasePlanBuilder : IReleasePlanBuilder + { + private readonly ILog log; + private readonly IPackageVersionResolver versionResolver; + private readonly IChannelVersionRuleTester versionRuleTester; + + public ReleasePlanBuilder(ILog log, IPackageVersionResolver versionResolver, IChannelVersionRuleTester versionRuleTester) + { + this.log = log; + this.versionResolver = versionResolver; + this.versionRuleTester = versionRuleTester; + } + + public ReleasePlan Build(IOctopusRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag) + { + if (repository == null) throw new ArgumentNullException(nameof(repository)); + if (project == null) throw new ArgumentNullException(nameof(project)); + + log.Debug("Finding deployment process..."); + var deploymentProcess = repository.DeploymentProcesses.Get(project.DeploymentProcessId); + + log.Debug("Finding release template..."); + var releaseTemplate = repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel); + + var plan = new ReleasePlan(project, channel, releaseTemplate, versionResolver); + + if (plan.UnresolvedSteps.Any()) + { + log.Debug("The package version for some steps was not specified. Going to try and resolve those automatically..."); + foreach (var unresolved in plan.UnresolvedSteps) + { + if (!unresolved.IsResolveable) + { + log.ErrorFormat("The version number for step '{0}' cannot be automatically resolved because the feed or package ID is dynamic.", unresolved.StepName); + continue; + } + + if (!string.IsNullOrEmpty(versionPreReleaseTag)) + log.DebugFormat("Finding latest package with pre-release '{1}' for step: {0}", unresolved.StepName, versionPreReleaseTag); + else + log.DebugFormat("Finding latest package for step: {0}", unresolved.StepName); + + var feed = repository.Feeds.Get(unresolved.PackageFeedId); + if (feed == null) + throw new CommandException(string.Format("Could not find a feed with ID {0}, which is used by step: " + unresolved.StepName, unresolved.PackageFeedId)); + + var filters = BuildChannelVersionFilters(unresolved.StepName, channel); + filters["packageId"] = unresolved.PackageId; + if (!string.IsNullOrWhiteSpace(versionPreReleaseTag)) + filters["preReleaseTag"] = versionPreReleaseTag; + + var packages = repository.Client.Get>(feed.Link("SearchTemplate"), filters); + var latestPackage = packages.FirstOrDefault(); + + if (latestPackage == null) + { + log.ErrorFormat("Could not find any packages with ID '{0}' in the feed '{1}'", unresolved.PackageId, feed.FeedUri); + } + else + { + log.DebugFormat("Selected '{0}' version '{1}' for '{2}'", latestPackage.NuGetPackageId, latestPackage.Version, unresolved.StepName); + unresolved.SetVersionFromLatest(latestPackage.Version); + } + } + } + + // Test each step in this plan satisfies the channel version rules + if (channel != null) + { + foreach (var step in plan.Steps) + { + var rule = + channel.Rules.SingleOrDefault( + r => r.Actions.Any(s => s.Equals(step.StepName, StringComparison.OrdinalIgnoreCase))); + if (rule == null) continue; + + var result = versionRuleTester.Test(repository, rule, step.Version); + step.SetChannelVersionRuleTestResult(result); + } + } + + return plan; + } + + IDictionary BuildChannelVersionFilters(string stepName, ChannelResource channel) + { + var filters = new Dictionary(); + + if (channel == null) + return filters; + + var rule = channel.Rules.FirstOrDefault(r => r.Actions.Contains(stepName)); + if (rule == null) + return filters; + + if (!string.IsNullOrWhiteSpace(rule.VersionRange)) + filters["versionRange"] = rule.VersionRange; + + if (!string.IsNullOrWhiteSpace(rule.Tag)) + filters["preReleaseTag"] = rule.Tag; + + return filters; + } + } } \ No newline at end of file diff --git a/source/Octopus.Cli/Model/ChannelVersionRuleTestResult.cs b/source/Octopus.Cli/Model/ChannelVersionRuleTestResult.cs index 1a2af942e..3797b7a2c 100644 --- a/source/Octopus.Cli/Model/ChannelVersionRuleTestResult.cs +++ b/source/Octopus.Cli/Model/ChannelVersionRuleTestResult.cs @@ -1,21 +1,21 @@ -using System.Collections.Generic; -using Octopus.Client.Model; - -namespace Octopus.Cli.Model -{ - public class ChannelVersionRuleTestResult : Resource - { - public IEnumerable Errors { get; set; } - public bool SatisfiesVersionRange { get; set; } - public bool SatisfiesPreReleaseTag { get; set; } - public bool IsSatisfied => SatisfiesVersionRange && SatisfiesPreReleaseTag; - - const string Pass = "PASS"; - const string Fail = "FAIL"; - - public string ToSummaryString() - { - return $"Range: {(SatisfiesVersionRange ? Pass : Fail)} Tag: {(SatisfiesPreReleaseTag ? Pass : Fail)}"; - } - } -} +using System.Collections.Generic; +using Octopus.Client.Model; + +namespace Octopus.Cli.Model +{ + public class ChannelVersionRuleTestResult : Resource + { + public IEnumerable Errors { get; set; } + public bool SatisfiesVersionRange { get; set; } + public bool SatisfiesPreReleaseTag { get; set; } + public bool IsSatisfied => SatisfiesVersionRange && SatisfiesPreReleaseTag; + + const string Pass = "PASS"; + const string Fail = "FAIL"; + + public string ToSummaryString() + { + return $"Range: {(SatisfiesVersionRange ? Pass : Fail)} Tag: {(SatisfiesPreReleaseTag ? Pass : Fail)}"; + } + } +} diff --git a/source/Octopus.Cli/Octopus.Cli.csproj b/source/Octopus.Cli/Octopus.Cli.csproj index 6b18fc2c9..e303621ec 100644 --- a/source/Octopus.Cli/Octopus.Cli.csproj +++ b/source/Octopus.Cli/Octopus.Cli.csproj @@ -1,236 +1,236 @@ - - - - Debug - x86 - {D1BFD88F-FB8E-49EC-968F-F4D9A8A52519} - Exe - Properties - Octopus.Cli - Octo - v4.5 - - - 512 - ..\ - true - - - - - x86 - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - true - false - default - - - x86 - none - true - bin\ - TRACE - prompt - 4 - true - false - - - Properties\Icon.ico - false - - - - ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - - ..\packages\log4net.2.0.2\lib\net40-full\log4net.dll - True - - - ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll - True - - - ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll - True - - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True - - - ..\packages\NuGet.Core.2.9.0\lib\net40-Client\NuGet.Core.dll - True - - - ..\packages\Octopus.Client.3.3.9\lib\net40\Octopus.Client.dll - True - - - ..\packages\Octostache.1.0.2.21\lib\net40\Octostache.dll - True - - - ..\packages\Sprache.2.0.0.50\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll - True - - - - - - - - - - - - - - - - - - - Properties\SolutionInfo.cs - - - Properties\VersionInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - - - - - - - logging.config - - - logging-unix.config - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + + Debug + x86 + {D1BFD88F-FB8E-49EC-968F-F4D9A8A52519} + Exe + Properties + Octopus.Cli + Octo + v4.5 + + + 512 + ..\ + true + + + + + x86 + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + true + false + default + + + x86 + none + true + bin\ + TRACE + prompt + 4 + true + false + + + Properties\Icon.ico + false + + + + ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True + + + ..\packages\log4net.2.0.2\lib\net40-full\log4net.dll + True + + + ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll + True + + + ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll + True + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\NuGet.Core.2.9.0\lib\net40-Client\NuGet.Core.dll + True + + + ..\packages\Octopus.Client.3.3.9\lib\net40\Octopus.Client.dll + True + + + ..\packages\Octostache.1.0.2.21\lib\net40\Octostache.dll + True + + + ..\packages\Sprache.2.0.0.50\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll + True + + + + + + + + + + + + + + + + + + + Properties\SolutionInfo.cs + + + Properties\VersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + + logging.config + + + logging-unix.config + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + --> \ No newline at end of file diff --git a/source/Octopus.Cli/Util/ResourceCollectionExtensions.cs b/source/Octopus.Cli/Util/ResourceCollectionExtensions.cs index 85ca690d1..e687f319c 100644 --- a/source/Octopus.Cli/Util/ResourceCollectionExtensions.cs +++ b/source/Octopus.Cli/Util/ResourceCollectionExtensions.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Octopus.Client; -using Octopus.Client.Model; - -namespace Octopus.Cli.Util -{ - public static class ResourceCollectionExtensions - { - private const string PageNext = "Page.Next"; - - public static bool HasNextPage(this ResourceCollection source) - { - return source.HasLink(PageNext); - } - - public static string NextPageLink(this ResourceCollection source) - { - return source.Link(PageNext); - } - - public static IEnumerable GetAllPages(this ResourceCollection source, IOctopusRepository repository) - { - foreach (var item in source.Items) - yield return item; - - while (source.HasNextPage()) - { - source = repository.Client.List(source.NextPageLink()); - foreach (var item in source.Items) - yield return item; - } - } - } +using System.Collections.Generic; +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Util +{ + public static class ResourceCollectionExtensions + { + private const string PageNext = "Page.Next"; + + public static bool HasNextPage(this ResourceCollection source) + { + return source.HasLink(PageNext); + } + + public static string NextPageLink(this ResourceCollection source) + { + return source.Link(PageNext); + } + + public static IEnumerable GetAllPages(this ResourceCollection source, IOctopusRepository repository) + { + foreach (var item in source.Items) + yield return item; + + while (source.HasNextPage()) + { + source = repository.Client.List(source.NextPageLink()); + foreach (var item in source.Items) + yield return item; + } + } + } } \ No newline at end of file