public async Task <ReleasePlan> Build(IOctopusAsyncRepository 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 = await repository.DeploymentProcesses.Get(project.DeploymentProcessId).ConfigureAwait(false);

            log.Debug("Finding release template...");
            var releaseTemplate = await repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel).ConfigureAwait(false);

            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.Error("The version number for step '{Step:l}' cannot be automatically resolved because the feed or package ID is dynamic.", unresolved.StepName);
                        continue;
                    }

                    if (!string.IsNullOrEmpty(versionPreReleaseTag))
                    {
                        log.Debug("Finding latest package with pre-release '{Tag:l}' for step: {StepName:l}", versionPreReleaseTag, unresolved.StepName);
                    }
                    else
                    {
                        log.Debug("Finding latest package for step: {StepName:l}", unresolved.StepName);
                    }

                    var feed = await repository.Feeds.Get(unresolved.PackageFeedId).ConfigureAwait(false);

                    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 = await repository.Client.Get <List <PackageResource> >(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);

                    var latestPackage = packages.FirstOrDefault();

                    if (latestPackage == null)
                    {
                        log.Error("Could not find any packages with ID '{PackageId:l}' in the feed '{FeedUri:l}'", unresolved.PackageId, feed.FeedUri);
                    }
                    else
                    {
                        log.Debug("Selected '{PackageId:l}' version '{Version:l}' for '{StepName:l}'", latestPackage.PackageId, 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)
                {
                    // Note the rule can be null, meaning: anything goes
                    var rule   = channel.Rules.SingleOrDefault(r => r.Actions.Any(s => s.Equals(step.StepName, StringComparison.OrdinalIgnoreCase)));
                    var result = await versionRuleTester.Test(repository, rule, step.Version).ConfigureAwait(false);

                    step.SetChannelVersionRuleTestResult(result);
                }
            }

            return(plan);
        }
        protected override void Execute()
        {
            if (string.IsNullOrWhiteSpace(ProjectName))
            {
                throw new CommandException("Please specify a project name using the parameter: --project=XYZ");
            }

            Log.Debug("Finding project: " + ProjectName);
            var project = Repository.Projects.FindByName(ProjectName);

            if (project == null)
            {
                throw new CouldNotFindException("a project named", ProjectName);
            }

            var channel = default(ChannelResource);

            if (!string.IsNullOrWhiteSpace(ChannelName))
            {
                Log.Debug("Finding channel: " + ChannelName);
                var channels = Repository.Projects.GetChannels(project).Items;
                channel = channels.SingleOrDefault(c => string.Equals(c.Name, ChannelName, StringComparison.OrdinalIgnoreCase));
                if (channel == null)
                {
                    throw new CouldNotFindException("a channel named", ChannelName);
                }
            }

            Log.Debug("Finding deployment process for project: " + ProjectName);
            var deploymentProcess = Repository.DeploymentProcesses.Get(project.DeploymentProcessId);

            Log.Debug("Finding release template...");
            var releaseTemplate = Repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel);

            var plan = new ReleasePlan(releaseTemplate, versionResolver);

            if (plan.UnresolvedSteps.Count > 0)
            {
                Log.Debug("Resolving NuGet package versions...");
                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(VersionPrerelease))
                    {
                        Log.DebugFormat("Finding latest NuGet package with pre-release '{1}' for step: {0}", unresolved.StepName, VersionPrerelease);
                    }
                    else
                    {
                        Log.DebugFormat("Finding latest NuGet package for step: {0}", unresolved.StepName);
                    }

                    var feed = Repository.Feeds.Get(unresolved.NuGetFeedId);
                    if (feed == null)
                    {
                        throw new CommandException(string.Format("Could not find a feed with ID {0}, which is used by step: " + unresolved.StepName, unresolved.NuGetFeedId));
                    }

                    var filters = GetChannelVersionFilters(unresolved.StepName, channel);
                    filters["packageId"] = unresolved.PackageId;
                    if (!string.IsNullOrWhiteSpace(VersionPrerelease))
                    {
                        filters["preReleaseTag"] = VersionPrerelease;
                    }

                    var packages = Repository.Client.Get <List <PackageResource> >(feed.Link("SearchTemplate"), filters);
                    var version  = packages.FirstOrDefault();

                    if (version == null)
                    {
                        Log.ErrorFormat("Could not find any packages with ID '{0}' in the feed '{1}'", unresolved.PackageId, feed.FeedUri);
                    }
                    else
                    {
                        unresolved.SetVersionFromLatest(version.Version);
                    }
                }
            }

            string versionNumber;

            if (!string.IsNullOrWhiteSpace(VersionNumber))
            {
                Log.Debug("Using version number provided on command-line.");
                versionNumber = VersionNumber;
            }
            else if (!string.IsNullOrWhiteSpace(releaseTemplate.NextVersionIncrement))
            {
                Log.Debug("Using version number from release template.");
                versionNumber = releaseTemplate.NextVersionIncrement;
            }
            else if (!string.IsNullOrWhiteSpace(releaseTemplate.VersioningPackageStepName))
            {
                Log.Debug("Using version number from package step.");
                versionNumber = plan.GetActionVersionNumber(releaseTemplate.VersioningPackageStepName);
            }
            else
            {
                throw new CommandException("A version number was not specified and could not be automatically selected.");
            }

            if (plan.Steps.Count > 0)
            {
                Log.Info("Release plan for release:    " + versionNumber);
                Log.Info("Steps: ");
                Log.Info(plan.FormatAsTable());
            }

            if (plan.HasUnresolvedSteps())
            {
                throw new CommandException("Package versions could not be resolved for one or more of the package steps in this release. See the errors above for details. Either ensure the latest version of the package can be automatically resolved, or set the version to use specifically by using the --package argument.");
            }

            Log.Debug("Creating release...");

            if (IgnoreIfAlreadyExists)
            {
                try
                {
                    var found = Repository.Projects.GetReleaseByVersion(project, versionNumber);
                    if (found != null)
                    {
                        Log.Info("A release with the number " + versionNumber + " already exists.");
                        return;
                    }
                }
                catch (OctopusResourceNotFoundException)
                {
                    // Expected
                }
            }

            var release = Repository.Releases.Create(new ReleaseResource(versionNumber, project.Id, channel?.Id)
            {
                ReleaseNotes     = ReleaseNotes,
                SelectedPackages = plan.GetSelections()
            }, Force);

            Log.Info("Release " + release.Version + " created successfully!");
            Log.ServiceMessage("setParameter", new { name = "octo.releaseNumber", value = release.Version });
            Log.TfsServiceMessage(ServerBaseUrl, project, release);

            DeployRelease(project, release, DeployToEnvironmentNames);
        }
        public async Task<ReleasePlan> Build(IOctopusAsyncRepository 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 = await repository.DeploymentProcesses.Get(project.DeploymentProcessId).ConfigureAwait(false);

            log.Debug("Finding release template...");
            var releaseTemplate = await repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel).ConfigureAwait(false);

            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.Error("The version number for step '{Step:l}' cannot be automatically resolved because the feed or package ID is dynamic.", unresolved.StepName);
                        continue;
                    }

                    if (!string.IsNullOrEmpty(versionPreReleaseTag))
                        log.Debug("Finding latest package with pre-release '{Tag:l}' for step: {StepName:l}", versionPreReleaseTag, unresolved.StepName);
                    else
                        log.Debug("Finding latest package for step: {StepName:l}", unresolved.StepName);

                    var feed = await repository.Feeds.Get(unresolved.PackageFeedId).ConfigureAwait(false);
                    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 = await repository.Client.Get<List<PackageResource>>(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);
                    var latestPackage = packages.FirstOrDefault();

                    if (latestPackage == null)
                    {
                        log.Error("Could not find any packages with ID '{PackageId:l}' in the feed '{FeedUri:l}'", unresolved.PackageId, feed.FeedUri);
                    }
                    else
                    {
                        log.Debug("Selected '{PackageId:l}' version '{Version:l}' for '{StepName:l}'", latestPackage.PackageId, 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)
                {
                    // Note the rule can be null, meaning: anything goes
                    var rule = channel.Rules.SingleOrDefault(r => r.Actions.Any(s => s.Equals(step.StepName, StringComparison.OrdinalIgnoreCase)));
                    var result = await versionRuleTester.Test(repository, rule, step.Version).ConfigureAwait(false);
                    step.SetChannelVersionRuleTestResult(result);
                }
            }

            return plan;
        }
        protected override void Execute()
        {
            if (string.IsNullOrWhiteSpace(ProjectName)) throw new CommandException("Please specify a project name using the parameter: --project=XYZ");

            Log.Debug("Finding project: " + ProjectName);
            var project = Repository.Projects.FindByName(ProjectName);
            if (project == null)
                throw new CouldNotFindException("a project named", ProjectName);

            var channel = default(ChannelResource);
            if (!string.IsNullOrWhiteSpace(ChannelName))
            {
                Log.Debug("Finding channel: " + ChannelName);
                var channels = Repository.Projects.GetChannels(project).Items;
                channel = channels.SingleOrDefault(c => string.Equals(c.Name, ChannelName, StringComparison.OrdinalIgnoreCase));
                if (channel == null)
                    throw new CouldNotFindException("a channel named", ChannelName);
            }

            Log.Debug("Finding deployment process for project: " + ProjectName);
            var deploymentProcess = Repository.DeploymentProcesses.Get(project.DeploymentProcessId);

            Log.Debug("Finding release template...");
            var releaseTemplate = Repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel);

            var plan = new ReleasePlan(releaseTemplate, versionResolver);

            if (plan.UnresolvedSteps.Count > 0)
            {
                Log.Debug("Resolving package versions...");
                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(VersionPrerelease))
                        Log.DebugFormat("Finding latest package with pre-release '{1}' for step: {0}", unresolved.StepName, VersionPrerelease);
                    else
                        Log.DebugFormat("Finding latest package for step: {0}", unresolved.StepName);

                    var feed = Repository.Feeds.Get(unresolved.NuGetFeedId);
                    if (feed == null)
                        throw new CommandException(string.Format("Could not find a feed with ID {0}, which is used by step: " + unresolved.StepName, unresolved.NuGetFeedId));

                    var filters = GetChannelVersionFilters(unresolved.StepName, channel);
                    filters["packageId"] = unresolved.PackageId;
                    if (!string.IsNullOrWhiteSpace(VersionPrerelease))
                        filters["preReleaseTag"] = VersionPrerelease;

                    var packages = Repository.Client.Get<List<PackageResource>>(feed.Link("SearchTemplate"), filters);
                    var version = packages.FirstOrDefault();

                    if (version == null)
                    {
                        Log.ErrorFormat("Could not find any packages with ID '{0}' in the feed '{1}'", unresolved.PackageId, feed.FeedUri);
                    }
                    else
                    {
                        Log.DebugFormat("Selected version for package with ID '{0}' determined to be '{1}'", unresolved.PackageId, version.Version);
                        unresolved.SetVersionFromLatest(version.Version);
                    }
                }
            }

            string versionNumber;
            if (!string.IsNullOrWhiteSpace(VersionNumber))
            {
                Log.Debug("Using version number provided on command-line.");
                versionNumber = VersionNumber;
            }
            else if (!string.IsNullOrWhiteSpace(releaseTemplate.NextVersionIncrement))
            {
                Log.Debug("Using version number from release template.");
                versionNumber = releaseTemplate.NextVersionIncrement;
            }
            else if (!string.IsNullOrWhiteSpace(releaseTemplate.VersioningPackageStepName))
            {
                Log.Debug("Using version number from package step.");
                versionNumber = plan.GetActionVersionNumber(releaseTemplate.VersioningPackageStepName);
            }
            else
            {
                throw new CommandException("A version number was not specified and could not be automatically selected.");
            }

            if (plan.Steps.Count > 0)
            {
                Log.Info("Release plan for release:    " + versionNumber);
                Log.Info("Steps: ");
                Log.Info(plan.FormatAsTable());
            }

            if (plan.HasUnresolvedSteps())
            {
                throw new CommandException("Package versions could not be resolved for one or more of the package steps in this release. See the errors above for details. Either ensure the latest version of the package can be automatically resolved, or set the version to use specifically by using the --package argument.");
            }

            Log.Debug("Creating release...");

            if (IgnoreIfAlreadyExists)
            {
                try
                {
                    var found = Repository.Projects.GetReleaseByVersion(project, versionNumber);
                    if (found != null)
                    {
                        Log.Info("A release with the number " + versionNumber + " already exists.");
                        return;
                    }
                }
                catch (OctopusResourceNotFoundException)
                {
                    // Expected
                }
            }

            var release = Repository.Releases.Create(new ReleaseResource(versionNumber, project.Id, channel?.Id)
            {
                ReleaseNotes = ReleaseNotes,
                SelectedPackages = plan.GetSelections()
            }, Force);
            Log.Info("Release " + release.Version + " created successfully!");
            Log.ServiceMessage("setParameter", new {name = "octo.releaseNumber", value = release.Version});
            Log.TfsServiceMessage(ServerBaseUrl, project, release);

            DeployRelease(project, release, DeployToEnvironmentNames);
        }