Esempio n. 1
0
 public string CreateRelease(ReleaseResource release)
 {
     release.Id = Guid.NewGuid().ToString();
     _releases.Add(release);
     return(release.Id);
 }
 public async Task Execute(IOctopusAsyncClient client, ModifyReleaseParams releaseParams, ReleaseResource release)
 {
     await client.Repository.Releases.Delete(release);
 }
        private async Task <IReadOnlyList <DeploymentResource> > DeployToEnvironments(ProjectResource project, ReleaseResource release)
        {
            if (DeployToEnvironmentNames.Count == 0)
            {
                return(new List <DeploymentResource>());
            }

            var releaseTemplate = await Repository.Releases.GetTemplate(release).ConfigureAwait(false);

            var promotingEnvironments =
                (from environment in DeployToEnvironmentNames.Distinct(StringComparer.CurrentCultureIgnoreCase)
                 let promote = releaseTemplate.PromoteTo.FirstOrDefault(p => string.Equals(p.Name, environment, StringComparison.CurrentCultureIgnoreCase))
                               select new { Name = environment, Promotion = promote }).ToList();

            var unknownEnvironments = promotingEnvironments.Where(p => p.Promotion == null).ToList();

            if (unknownEnvironments.Count > 0)
            {
                throw new CommandException(
                          string.Format(
                              "Release '{0}' of project '{1}' cannot be deployed to {2} not in the list of environments that this release can be deployed to. This may be because a) the environment does not exist or is misspelled, b) The lifecycle has not reached this phase, possibly due to previous deployment failure, c) you don't have permission to deploy to this environment, or d) the environment is not in the list of environments defined by the lifecycle.",
                              release.Version,
                              project.Name,
                              unknownEnvironments.Count == 1
                            ? "environment '" + unknownEnvironments[0].Name + "' because the environment is"
                            : "environments " + string.Join(", ", unknownEnvironments.Select(e => "'" + e.Name + "'")) +
                              " because the environments are"
                              ));
            }

            LogScheduledDeployment();
            var specificMachineIds = await GetSpecificMachines().ConfigureAwait(false);

            var createTasks = promotingEnvironments.Select(promotion => CreateDeploymentTask(project, release, promotion.Promotion, specificMachineIds));

            return(await Task.WhenAll(createTasks).ConfigureAwait(false));
        }
        private async Task <bool> CanDeployToMachineCheckingRoles(IOctopusAsyncClient client, MachineResource machine, ReleaseResource release, string envId)
        {
            var deployTarget = await GetDeploymentTargetEnvironment(client, release, envId);

            var preview = await client.Repository.Releases.GetPreview(deployTarget);

            var stepsNeedRole = preview.StepsToExecute.Where(s => s.Roles.Any()).ToList();

            if (stepsNeedRole.Count < preview.StepsToExecute.Count)
            { // if any step doesn't require a role, then we can deploy the step to the machine.
                return(true);
            }

            return(stepsNeedRole.Any(step => step.Roles.Any(r => machine.Roles.Contains(r))));
        }
Esempio n. 5
0
        private async Task <DeploymentResource> CreateDeploymentTask(ProjectResource project, ReleaseResource release, DeploymentPromotionTarget promotionTarget, ReferenceCollection specificMachineIds, TenantResource tenant = null)
        {
            var preview = await Repository.Releases.GetPreview(promotionTarget).ConfigureAwait(false);

            // Validate skipped steps
            var skip = new ReferenceCollection();

            foreach (var step in SkipStepNames)
            {
                var stepToExecute =
                    preview.StepsToExecute.SingleOrDefault(s => string.Equals(s.ActionName, step, StringComparison.CurrentCultureIgnoreCase));
                if (stepToExecute == null)
                {
                    Log.Warning("No step/action named '{Step:l}' could be found when deploying to environment '{Environment:l}', so the step cannot be skipped.", step, promotionTarget.Name);
                }
                else
                {
                    Log.Debug("Skipping step: {Step:l}", stepToExecute.ActionName);
                    skip.Add(stepToExecute.ActionId);
                }
            }

            // Validate form values supplied
            if (preview.Form != null && preview.Form.Elements != null && preview.Form.Values != null)
            {
                foreach (var element in preview.Form.Elements)
                {
                    var variableInput = element.Control as VariableValue;
                    if (variableInput == null)
                    {
                        continue;
                    }

                    var value = variables.Get(variableInput.Label) ?? variables.Get(variableInput.Name);

                    if (string.IsNullOrWhiteSpace(value) && element.IsValueRequired)
                    {
                        throw new ArgumentException("Please provide a variable for the prompted value " + variableInput.Label);
                    }

                    preview.Form.Values[element.Name] = value;
                }
            }

            // Log step with no machines
            foreach (var previewStep in preview.StepsToExecute)
            {
                if (previewStep.HasNoApplicableMachines)
                {
                    Log.Warning("Warning: there are no applicable machines roles used by step {Step:l}", previewStep.ActionName);
                }
            }

            var deployment = await Repository.Deployments.Create(new DeploymentResource
            {
                TenantId                 = tenant?.Id,
                EnvironmentId            = promotionTarget.Id,
                SkipActions              = skip,
                ReleaseId                = release.Id,
                ForcePackageDownload     = ForcePackageDownload,
                UseGuidedFailure         = UseGuidedFailure.GetValueOrDefault(preview.UseGuidedFailureModeByDefault),
                SpecificMachineIds       = specificMachineIds,
                ForcePackageRedeployment = ForcePackageRedeployment,
                FormValues               = (preview.Form ?? new Form()).Values,
                QueueTime                = DeployAt == null ? null : (DateTimeOffset?)DeployAt.Value
            })
                             .ConfigureAwait(false);

            Log.Information("Deploying {Project:l} {Release:} to: {PromotionTarget:l} {Tenant:l}(Guided Failure: {GuidedFailure:l})", project.Name, release.Version, promotionTarget.Name,
                            tenant == null ? string.Empty : $"for {tenant.Name} ",
                            deployment.UseGuidedFailure ? "Enabled" : "Not Enabled");

            return(deployment);
        }
Esempio n. 6
0
        public void SetUp()
        {
            deployReleaseCommand = new DeployReleaseCommand(RepositoryFactory, FileSystem, ClientFactory, CommandOutputProvider, ExecutionResourceWaiterFactory);

            var project = new ProjectResource();
            var release = new ReleaseResource {
                Version = "1.0.0"
            };
            var release2 = new ReleaseResource {
                Version = "somedockertag"
            };
            var releases = new ResourceCollection <ReleaseResource>(new[] { release, release2 }, new LinkCollection());
            var deploymentPromotionTarget = new DeploymentPromotionTarget {
                Name = ValidEnvironment, Id = "Env-1"
            };
            var promotionTargets = new List <DeploymentPromotionTarget> {
                deploymentPromotionTarget
            };
            var tenantPromotionTarget1 = new DeploymentPromomotionTenant()
            {
                Id = "Tenant-1", PromoteTo = promotionTargets
            };
            var tenantPromotionTarget2 = new DeploymentPromomotionTenant()
            {
                Id = "Tenant-2", PromoteTo = new List <DeploymentPromotionTarget>()
            };
            var deploymentTemplate = new DeploymentTemplateResource {
                PromoteTo = promotionTargets, TenantPromotions = { tenantPromotionTarget1, tenantPromotionTarget2 }
            };
            var deploymentPreviewResource = new DeploymentPreviewResource {
                StepsToExecute = new List <DeploymentTemplateStep>()
            };
            var deployment = new DeploymentResource {
                TaskId = "Task-1"
            };

            taskResource = new TaskResource()
            {
                Id = "Task-1"
            };

            Repository.Projects.FindByName(ProjectName).Returns(project);
            Repository.Projects.GetReleases(project).Returns(releases);
            Repository.Projects.GetReleaseByVersion(project, "1.0.0").Returns(release);
            Repository.Projects.GetReleaseByVersion(project, "somedockertag").Returns(release2);
            Repository.Releases.GetPreview(deploymentPromotionTarget).Returns(deploymentPreviewResource);
            Repository.Releases.GetTemplate(release).Returns(deploymentTemplate);
            Repository.Releases.GetTemplate(release2).Returns(deploymentTemplate);
            Repository.Deployments.Create(Arg.Any <DeploymentResource>()).Returns(deployment);
            Repository.Tasks.Get(deployment.TaskId).Returns(taskResource);
            Repository.Tenants.Get(Arg.Is <string[]>(arg => arg.All(arg2 => arg2 == "Tenant-1" || arg2 == "Tenant-2")))
            .Returns(new List <TenantResource>()
            {
                new TenantResource()
                {
                    Id = "Tenant-1"
                },
                new TenantResource()
                {
                    Id = "Tenant-2"
                },
            });
        }
Esempio n. 7
0
 public void RaiseDefect(ReleaseResource release, string description)
 {
     Client.Post(release.Link("ReportDefect"), new DefectResource(description));
 }
Esempio n. 8
0
 public string CreateRelease(ReleaseResource release)
 {
     return(_octopusRepository.Releases.Create(release).Id);
 }
        private static void LogDeploymentInfo(ICommandOutputProvider commandOutputProvider, DashboardItemResource dashboardItem, ReleaseResource release, ChannelResource channel,
                                              IDictionary <string, string> environmentsById, IDictionary <string, string> projectedById, IDictionary <string, string> tenantsById)
        {
            var nameOfDeploymentEnvironment = environmentsById[dashboardItem.EnvironmentId];
            var nameOfDeploymentProject     = projectedById[dashboardItem.ProjectId];

            commandOutputProvider.Information(" - Project: {Project:l}", nameOfDeploymentProject);
            commandOutputProvider.Information(" - Environment: {Environment:l}", nameOfDeploymentEnvironment);
            if (!string.IsNullOrEmpty(dashboardItem.TenantId))
            {
                var nameOfDeploymentTenant = GetNameOfDeploymentTenant(tenantsById, dashboardItem.TenantId);
                commandOutputProvider.Information(" - Tenant: {Tenant:l}", nameOfDeploymentTenant);
            }

            if (channel != null)
            {
                commandOutputProvider.Information(" - Channel: {Channel:l}", channel.Name);
            }

            commandOutputProvider.Information("   Date: {$Date:l}", dashboardItem.QueueTime);
            commandOutputProvider.Information("   Duration: {Duration:l}", dashboardItem.Duration);

            if (dashboardItem.State == TaskState.Failed)
            {
                commandOutputProvider.Error("   State: {$State:l}", dashboardItem.State);
            }
            else
            {
                commandOutputProvider.Information("   State: {$State:l}", dashboardItem.State);
            }

            commandOutputProvider.Information("   Version: {Version:l}", release.Version);
            commandOutputProvider.Information("   Assembled: {$Assembled:l}", release.Assembled);
            commandOutputProvider.Information("   Package Versions: {PackageVersion:l}", GetPackageVersionsAsString(release.SelectedPackages));
            commandOutputProvider.Information("   Release Notes: {ReleaseNotes:l}", GetReleaseNotes(release));
            commandOutputProvider.Information(string.Empty);
        }
Esempio n. 10
0
 protected static string GetReleaseNotes(ReleaseResource release)
 {
     return(release.ReleaseNotes != null?release.ReleaseNotes.Replace(System.Environment.NewLine, @"\n") : "");
 }
        public async Task Request()
        {
            var serverSupportsChannels = await ServerSupportsChannels();

            commandOutputProvider.Debug(serverSupportsChannels ? "This Octopus Server supports channels" : "This Octopus Server does not support channels");

            project = await Repository.Projects.FindByNameOrIdOrFail(ProjectNameOrId).ConfigureAwait(false);

            plan = await BuildReleasePlan(project).ConfigureAwait(false);


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

            commandOutputProvider.Write(
                plan.IsViableReleasePlan() ? LogEventLevel.Information : LogEventLevel.Warning,
                "Release plan for {Project:l} {Version:l}" + System.Environment.NewLine + "{Plan:l}",
                project.Name, versionNumber, plan.FormatAsTable()
                );
            if (plan.HasUnresolvedSteps())
            {
                throw new CommandException(
                          "Package versions could not be resolved for one or more of the package packageSteps 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.");
            }
            if (plan.ChannelHasAnyEnabledSteps() == false)
            {
                if (serverSupportsChannels)
                {
                    throw new CommandException($"Channel {plan.Channel.Name} has no available steps");
                }
                else
                {
                    throw new CommandException($"Plan has no available steps");
                }
            }

            if (plan.HasStepsViolatingChannelVersionRules())
            {
                if (IgnoreChannelRules)
                {
                    commandOutputProvider.Warning("At least one step violates the package version rules for the Channel '{Channel:l}'. Forcing the release to be created ignoring these rules...", plan.Channel.Name);
                }
                else
                {
                    throw new CommandException(
                              $"At least one step violates the package version rules for the Channel '{plan.Channel.Name}'. Either correct the package versions for this release, let Octopus select the best channel by omitting the --channel argument, select a different channel using --channel=MyChannel argument, or ignore these version rules altogether by using the --ignoreChannelRules argument.");
                }
            }

            if (IgnoreIfAlreadyExists)
            {
                commandOutputProvider.Debug("Checking for existing release for {Project:l} {Version:l} because you specified --ignoreexisting...", project.Name, versionNumber);
                try
                {
                    var found = await Repository.Projects.GetReleaseByVersion(project, versionNumber)
                                .ConfigureAwait(false);

                    if (found != null)
                    {
                        commandOutputProvider.Information("A release of {Project:l} with the number {Version:l} already exists, and you specified --ignoreexisting, so we won't even attempt to create the release.", project.Name, versionNumber);
                        return;
                    }
                }
                catch (OctopusResourceNotFoundException)
                {
                    // Expected
                    commandOutputProvider.Debug("No release exists - the coast is clear!");
                }
            }

            if (WhatIf)
            {
                // We were just doing a dry run - bail out here
                if (DeployToEnvironmentNamesOrIds.Any())
                {
                    commandOutputProvider.Information("[WhatIf] This release would have been created using the release plan and deployed to {Environments:l}", DeployToEnvironmentNamesOrIds.CommaSeperate());
                }
                else
                {
                    commandOutputProvider.Information("[WhatIf] This release would have been created using the release plan");
                }
            }
            else
            {
                // Actually create the release!
                commandOutputProvider.Debug("Creating release...");

                // if no release notes were provided on the command line, but the project has a template, then use the template
                if (string.IsNullOrWhiteSpace(ReleaseNotes) && !string.IsNullOrWhiteSpace(project.ReleaseNotesTemplate))
                {
                    ReleaseNotes = project.ReleaseNotesTemplate;
                }

                release = await Repository.Releases.Create(new ReleaseResource(versionNumber, project.Id, plan.Channel?.Id)
                {
                    ReleaseNotes     = ReleaseNotes,
                    SelectedPackages = plan.GetSelections()
                }, ignoreChannelRules : IgnoreChannelRules)
                          .ConfigureAwait(false);

                commandOutputProvider.Information("Release {Version:l} created successfully!", release.Version);
                commandOutputProvider.ServiceMessage("setParameter", new { name = "octo.releaseNumber", value = release.Version });
                commandOutputProvider.TfsServiceMessage(ServerBaseUrl, project, release);

                await DeployRelease(project, release).ConfigureAwait(false);
            }
        }
Esempio n. 12
0
 public Task ResolveDefect(ReleaseResource release)
 {
     return(Client.Post(release.Link("ResolveDefect")));
 }
Esempio n. 13
0
 public Task RaiseDefect(ReleaseResource release, string description)
 {
     return(Client.Post(release.Link("ReportDefect"), new DefectResource(description)));
 }
Esempio n. 14
0
        public static void TfsServiceMessage(this ILogger log, string serverBaseUrl, ProjectResource project, ReleaseResource release)
        {
            if (!serviceMessagesEnabled)
            {
                return;
            }
            if (buildEnvironment == AutomationEnvironment.AzureDevOps || buildEnvironment == AutomationEnvironment.NoneOrUnknown)
            {
                var workingDirectory = Environment.GetEnvironmentVariable("SYSTEM_DEFAULTWORKINGDIRECTORY") ?? new FileInfo(typeof(LogExtensions).GetTypeInfo().Assembly.Location).DirectoryName;
                var selflink         = new Uri(new Uri(serverBaseUrl), release.Links["Web"].AsString());
                var markdown         = $"[Release {release.Version} created for '{project.Name}']({selflink})";
                var markdownFile     = Path.Combine(workingDirectory, Guid.NewGuid() + ".md");

                try
                {
                    File.WriteAllText(markdownFile, markdown);
                }
                catch (UnauthorizedAccessException uae)
                {
                    throw new UnauthorizedAccessException($"Could not write the TFS service message file '{markdownFile}'. Please make sure the SYSTEM_DEFAULTWORKINGDIRECTORY environment variable is set to a writeable directory. If this command is not being run on a build agent, omit the --enableServiceMessages parameter.", uae);
                }

                log.Information("##vso[task.addattachment type=Distributedtask.Core.Summary;name=Octopus Deploy;]{MarkdownFile:l}", markdownFile);
            }
        }
Esempio n. 15
0
 void AddOverrideForEnvironment(ProjectResource project, EnvironmentResource environment, ReleaseResource release)
 {
     createdDeploymentOverides.Add(new Tuple <EnvironmentResource, TenantResource, CreatedOutcome>(environment, null, CreatedOutcome.Created));
     project.AddAutoDeployReleaseOverride(environment, release);
     commandOutputProvider.Information("Auto deploy will deploy version {Version:l} of the project {Project:l} to the environment {Environment:l}", release.Version, project.Name, environment.Name);
 }
        /// <summary>
        /// Gathers the last deployment of the passed releases for the specified environment.
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to call against.</param>
        /// <param name="environment">Environment to call against.</param>
        /// <returns>DeploymentResource</returns>
        public static DeploymentResource GetLastDeploymentOfEnvironmentRelease(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment)
        {
            var releaseDeployments = octRepository.Client.GetReleaseDeployments(release);

            if (releaseDeployments != null && releaseDeployments.Count() > 0)
            {
                return(releaseDeployments.Where(x => x.EnvironmentId == environment.Id).OrderBy(x => x.Created).FirstOrDefault());
            }
            else
            {
                return(null);
            }
        }
Esempio n. 17
0
        void AddOverrideForTenant(ProjectResource project, EnvironmentResource environment, TenantResource tenant, ReleaseResource release)
        {
            if (!tenant.ProjectEnvironments.ContainsKey(project.Id))
            {
                createdDeploymentOverides.Add(new Tuple <EnvironmentResource, TenantResource, CreatedOutcome>(environment, tenant, CreatedOutcome.NotConnectedToProject));
                commandOutputProvider.Warning("The tenant {Tenant:l} was skipped because it has not been connected to the project {Project:l}", tenant.Name, project.Name);
                return;
            }
            if (!tenant.ProjectEnvironments[project.Id].Contains(environment.Id))
            {
                createdDeploymentOverides.Add(new Tuple <EnvironmentResource, TenantResource, CreatedOutcome>(environment, tenant, CreatedOutcome.NotConnectedToEnvironment));
                commandOutputProvider.Warning("The tenant {Tenant:l} was skipped because it has not been connected to the environment {Environment:l}", tenant.Name, environment.Name);
                return;
            }

            createdDeploymentOverides.Add(new Tuple <EnvironmentResource, TenantResource, CreatedOutcome>(environment, tenant, CreatedOutcome.Created));
            project.AddAutoDeployReleaseOverride(environment, tenant, release);
            commandOutputProvider.Information("Auto deploy will deploy version {Version:l} of the project {Project:l} to the environment {Environment:l} for the tenant {Tenant:l}", release.Version, project.Name, environment.Name, tenant.Name);
        }
        /// <summary>
        /// Gathers the Deployment Variables needed for a deployment
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">The release to gather the variables from</param>
        /// <param name="environment">The environment used to gather the variables from</param>
        /// <returns>Dictionary of DeploymentVariables.</returns>
        public static IDictionary <string, string> GetDeploymentVariables(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment)
        {
            var releaseTemplate           = octRepository.Releases.GetTemplate(release);
            var deploymentPromotionTarget = releaseTemplate.PromoteTo.SingleOrDefault(x => x.Id.Equals(environment.Id, StringComparison.OrdinalIgnoreCase));
            var deploymentPreview         = octRepository.Releases.GetPreview(deploymentPromotionTarget);

            return(deploymentPreview.Form.Values);
        }
Esempio n. 19
0
 public ResourceCollection <DefectResource> GetDefects(ReleaseResource release)
 {
     return(Client.List <DefectResource>(release.Link("Defects")));
 }
        /// <summary>
        /// Gathers the last non active deployment of the passed releases for the specified environment.
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to call against.</param>
        /// <param name="environment">Environment to call against.</param>
        /// <returns>DeploymentResource</returns>
        public static DeploymentResource GetNonActiveLastDeploymentOfEnvironmentRelease(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment)
        {
            var nonActiveStatusList = new List <TaskState>()
            {
                TaskState.Queued,
                TaskState.Executing
            };
            var releaseDeployments = octRepository.Client.GetReleaseDeployments(release);

            if (releaseDeployments != null && releaseDeployments.Count() > 0)
            {
                var nonActiveReleaseDeployments = releaseDeployments.Where(x => x.EnvironmentId == environment.Id && !(nonActiveStatusList.Contains(TaskHelper.GetTaskFromId(octRepository, x.TaskId).State)));
                if (nonActiveReleaseDeployments != null && nonActiveReleaseDeployments.Count() > 0)
                {
                    var lastDeployment = nonActiveReleaseDeployments.OrderBy(x => x.Created).FirstOrDefault();
                    return(lastDeployment);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                return(null);
            }
        }
Esempio n. 21
0
 public void ResolveDefect(ReleaseResource release)
 {
     Client.Post(release.Link("ResolveDefect"));
 }
        /// <summary>
        /// Gathers deployment of the passed releases for the specified environment of the specified state.
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to call against.</param>
        /// <param name="environment">Environment to call against.</param>
        /// <param name="state">State of the Task</param>
        /// <returns>DeploymentResource</returns>
        public static DeploymentResource GetLastDeploymentOfEnvironmentReleaseByState(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment, TaskState state)
        {
            var releaseDeployments = octRepository.Client.GetReleaseDeployments(release);

            if (releaseDeployments != null && releaseDeployments.Count() > 0)
            {
                return(releaseDeployments.Where(x => x.EnvironmentId == environment.Id && TaskHelper.GetTaskFromId(octRepository, x.TaskId).State == state).OrderBy(x => x.Created).FirstOrDefault());
            }
            else
            {
                return(null);
            }
        }
Esempio n. 23
0
        /// <summary>
        /// Gathers the deployment steps for the passed release and environment.
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to gather steps from.</param>
        /// <param name="environment">Environment to gather steps from.</param>
        /// <returns>Enumerable of DeploymentTemplateSteps</returns>
        public static IEnumerable <DeploymentTemplateStep> GetReleaseEnvironmentDeploymentSteps(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment)
        {
            var releaseTemplate           = octRepository.Releases.GetTemplate(release);
            var deploymentPromotionTarget = releaseTemplate.PromoteTo.SingleOrDefault(x => x.Id.Equals(environment.Id, StringComparison.OrdinalIgnoreCase));

            return(octRepository.Releases.GetPreview(deploymentPromotionTarget).StepsToExecute);
        }
        /// <summary>
        /// Returns the variables associated to a deployment
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to call against.</param>
        /// <param name="environment">Environment to call against.</param>
        /// <returns>DeploymentResource</returns>
        public static IEnumerable <string> GetDeploymentFormVariables(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment)
        {
            var varList                   = new List <string>();
            var releaseTemplate           = octRepository.Releases.GetTemplate(release);
            var deploymentPromotionTarget = releaseTemplate.PromoteTo.SingleOrDefault(x => x.Id.Equals(environment.Id, StringComparison.OrdinalIgnoreCase));
            var deploymentPreview         = octRepository.Releases.GetPreview(deploymentPromotionTarget);

            foreach (var element in deploymentPreview.Form.Elements)
            {
                var variableInput = element.Control as VariableValue;
                if (variableInput != null)
                {
                    varList.Add(variableInput.Label);
                }
            }
            return(varList);
        }
Esempio n. 25
0
        public async Task WaitForDeploymentToComplete(IReadOnlyList <DeploymentResource> deployments, ProjectResource project, ReleaseResource release)
        {
            var getTasks        = deployments.Select(dep => Repository.Tasks.Get(dep.TaskId));
            var deploymentTasks = await Task.WhenAll(getTasks).ConfigureAwait(false);

            if (showProgress && deployments.Count > 1)
            {
                Log.Information("Only progress of the first task ({Task:l}) will be shown", deploymentTasks.First().Name);
            }

            try
            {
                Log.Information("Waiting for {NumberOfTasks} deployment(s) to complete....", deploymentTasks.Length);
                await Repository.Tasks.WaitForCompletion(deploymentTasks.ToArray(), DeploymentStatusCheckSleepCycle.Seconds, (int)DeploymentTimeout.TotalMinutes, PrintTaskOutput).ConfigureAwait(false);

                var failed = false;
                foreach (var deploymentTask in deploymentTasks)
                {
                    var updated = await Repository.Tasks.Get(deploymentTask.Id).ConfigureAwait(false);

                    if (updated.FinishedSuccessfully)
                    {
                        Log.Information("{Task:l}: {State}", updated.Description, updated.State);
                    }
                    else
                    {
                        Log.Error("{Task:l}: {State}, {Error:l}", updated.Description, updated.State, updated.ErrorMessage);
                        failed = true;

                        if (noRawLog)
                        {
                            continue;
                        }

                        try
                        {
                            var raw = await Repository.Tasks.GetRawOutputLog(updated).ConfigureAwait(false);

                            if (!string.IsNullOrEmpty(rawLogFile))
                            {
                                File.WriteAllText(rawLogFile, raw);
                            }
                            else
                            {
                                Log.Error(raw);
                            }
                        }
                        catch (Exception ex)
                        {
                            Log.Error(ex, "Could not retrieve the raw task log for the failed task.");
                        }
                    }
                }
                if (failed)
                {
                    throw new CommandException("One or more deployment tasks failed.");
                }

                Log.Information("Done!");
            }
            catch (TimeoutException e)
            {
                Log.Error(e.Message);

                await CancelDeploymentOnTimeoutIfRequested(deploymentTasks).ConfigureAwait(false);

                var guidedFailureDeployments =
                    from d in deployments
                    where d.UseGuidedFailure
                    select d;
                if (guidedFailureDeployments.Any())
                {
                    Log.Warning("One or more deployments are using Guided Failure. Use the links below to check if intervention is required:");
                    foreach (var guidedFailureDeployment in guidedFailureDeployments)
                    {
                        var environment = await Repository.Environments.Get(guidedFailureDeployment.Link("Environment")).ConfigureAwait(false);

                        Log.Warning("  - {Environment:l}: {Url:l}", environment.Name, GetPortalUrl(string.Format("/app#/projects/{0}/releases/{1}/deployments/{2}", project.Slug, release.Version, guidedFailureDeployment.Id)));
                    }
                }
                throw new CommandException(e.Message);
            }
        }
        /// <summary>
        /// Builds a DeploymentResource for the release and environment passed, creates what steps to skip based on a string list.
        /// </summary>
        /// <param name="octRepository">The repository to call against.</param>
        /// <param name="release">Release to deploy.</param>
        /// <param name="environment">Environment to deploy to.</param>
        /// <param name="formValues">Form value variable dictionary.</param>
        /// <param name="guidedFailure">Enable Guided Failure.</param>
        /// <param name="skippedSteps">Steps to skip.</param>
        /// <param name="dateToDeploy">Deployment Date.</param>
        /// <returns>DeploymentResource</returns>
        public static DeploymentResource BuildDeployment(OctopusRepository octRepository, ReleaseResource release, EnvironmentResource environment, Dictionary <string, string> formValues, bool guidedFailure, IEnumerable <string> skippedSteps, DateTimeOffset?dateToDeploy)
        {
            var machineIDs      = new ReferenceCollection();
            var skippedStepIDs  = new ReferenceCollection();
            var projectSteps    = StepHelper.GetReleaseEnvironmentDeploymentSteps(octRepository, release, environment);
            var skippedStepList = projectSteps.Where(p => skippedSteps.Any(s => s.Equals(p.ActionName, StringComparison.OrdinalIgnoreCase))).Select(d => d.ActionId);

            skippedStepIDs.ReplaceAll(skippedStepList);
            var releaseTemplate           = octRepository.Releases.GetTemplate(release);
            var deploymentPromotionTarget = releaseTemplate.PromoteTo.SingleOrDefault(x => x.Id.Equals(environment.Id, StringComparison.OrdinalIgnoreCase));
            var deploymentPreview         = octRepository.Releases.GetPreview(deploymentPromotionTarget);

            foreach (var element in deploymentPreview.Form.Elements)
            {
                var variableInput = element.Control as VariableValue;
                if (variableInput != null)
                {
                    var variableValue = formValues[variableInput.Label] ?? formValues[variableInput.Name];
                    if (string.IsNullOrWhiteSpace(variableValue) && element.IsValueRequired)
                    {
                        throw new ArgumentException(string.Format(ErrorStrings.MissingRequiredVar, variableInput.Label ?? variableInput.Name, ResourceStrings.FormValuesArgException));
                    }
                }
            }
            var deploymentResource = new DeploymentResource
            {
                EnvironmentId            = environment.Id,
                SkipActions              = skippedStepIDs,
                ReleaseId                = release.Id,
                ForcePackageDownload     = false,
                UseGuidedFailure         = guidedFailure,
                SpecificMachineIds       = machineIDs,
                ForcePackageRedeployment = true,
                FormValues               = formValues,
                QueueTime                = dateToDeploy
            };

            return(deploymentResource);
        }
Esempio n. 27
0
        private async Task <IReadOnlyList <DeploymentResource> > DeployTenantedRelease(ProjectResource project, ReleaseResource release)
        {
            if (DeployToEnvironmentNames.Count != 1)
            {
                return(new List <DeploymentResource>());
            }

            var environment            = DeployToEnvironmentNames[0];
            var specificMachineIdsTask = GetSpecificMachines();
            var releaseTemplate        = await Repository.Releases.GetTemplate(release).ConfigureAwait(false);

            deploymentTenants = await GetTenants(project, environment, release, releaseTemplate).ConfigureAwait(false);

            var specificMachineIds = await specificMachineIdsTask.ConfigureAwait(false);

            LogScheduledDeployment();

            var createTasks = deploymentTenants.Select(tenant =>
            {
                var promotion =
                    releaseTemplate.TenantPromotions
                    .First(t => t.Id == tenant.Id).PromoteTo
                    .First(tt => tt.Name.Equals(environment, StringComparison.CurrentCultureIgnoreCase));
                promotionTargets.Add(promotion);
                return(CreateDeploymentTask(project, release, promotion, specificMachineIds, tenant));
            });

            return(await Task.WhenAll(createTasks).ConfigureAwait(false));
        }
Esempio n. 28
0
        public static DeploymentResource CreateDeployment(OctoProject project, ReleaseResource release,
                                                          SingleProjectDeploymentSettings settings)
        {
            var client = WebClient.GetWebClientRef();

            // Check if the project has been disabled
            if (project.IsDisabled() || settings.Force || release == null)
            {
                return(null);
            }

            Console.WriteLine($"Starting to Create Deployment for {project.ProjectName}");
            // Update the variable set
            if (settings.UpdateVariableSetNow)
            {
                Console.WriteLine($"Update Release {release.Version} variables now");

                release = client.GetReleaseRepo().SnapshotVariables(release);
            }

            if (settings.NeedRebootAfterDeployment)
            {
                Console.WriteLine("Deployment Target Server(s) Will Reboot After Deployment");
                settings.WaitingForFinish = true;
            }

            //creating the deployment object
            var deployment = new DeploymentResource
            {
                ReleaseId          = release.Id,
                ProjectId          = project.GetProjectId(),
                EnvironmentId      = client.GetEnvironmentIdByName(settings.TargetEnvironmentName),
                SpecificMachineIds = settings.ConvertMachineNames(),
                Comments           = settings.Comments,
                UseGuidedFailure   = settings.UseGuidedFailure,
                SkipActions        = settings.ConvertSkipSteps()
            };

            // Schedule the deployment if deployment time is greater than now
            if (settings.DeployAt > DateTime.Now)
            {
                deployment.QueueTime      = new DateTimeOffset(settings.DeployAt);
                settings.WaitingForFinish = false;
            }

            deployment = client.GetDeploymentRepo().Create(deployment);

            Console.WriteLine($"{project.ProjectName} will {deployment.Name}");

            var task = new OctoTask(deployment);

            task.PrintCurrentState(settings.WaitingForFinish);

            if (!settings.NeedRebootAfterDeployment)
            {
                return(deployment);
            }
            var rolesNameList = project.GetTargetRolesNameList();
            var machines      = OctoMachines.GetMachinesByEnvName(settings.TargetEnvironmentName, rolesNameList);

            machines.RestartServer();

            return(deployment);
        }
Esempio n. 29
0
        private async Task <List <TenantResource> > GetTenants(ProjectResource project, string environmentName, ReleaseResource release,
                                                               DeploymentTemplateResource releaseTemplate)
        {
            if (!Tenants.Any() && !TenantTags.Any())
            {
                return(new List <TenantResource>());
            }

            var deployableTenants = new List <TenantResource>();

            if (Tenants.Contains("*"))
            {
                var tenantPromotions = releaseTemplate.TenantPromotions.Where(
                    tp => tp.PromoteTo.Any(
                        promo => promo.Name.Equals(environmentName, StringComparison.CurrentCultureIgnoreCase))).Select(tp => tp.Id).ToArray();

                var tentats = await Repository.Tenants.Get(tenantPromotions).ConfigureAwait(false);

                deployableTenants.AddRange(tentats);

                commandOutputProvider.Information("Found {NumberOfTenants} Tenants who can deploy {Project:l} {Version:l} to {Environment:l}", deployableTenants.Count, project.Name, release.Version, environmentName);
            }
            else
            {
                if (Tenants.Any())
                {
                    var tenantsByName = await Repository.Tenants.FindByNames(Tenants).ConfigureAwait(false);

                    var missing = tenantsByName == null || !tenantsByName.Any()
                        ? Tenants.ToArray()
                        : Tenants.Except(tenantsByName.Select(e => e.Name), StringComparer.OrdinalIgnoreCase).ToArray();

                    var tenantsById = await Repository.Tenants.Get(missing).ConfigureAwait(false);

                    missing = tenantsById == null || !tenantsById.Any()
                        ? missing
                        : missing.Except(tenantsById.Select(e => e.Id), StringComparer.OrdinalIgnoreCase).ToArray();

                    if (missing.Any())
                    {
                        throw new ArgumentException(
                                  $"Could not find the {"tenant" + (missing.Length == 1 ? "" : "s")} {string.Join(", ", missing)} on the Octopus server.");
                    }

                    deployableTenants.AddRange(tenantsByName);
                    deployableTenants.AddRange(tenantsById);

                    var unDeployableTenants =
                        deployableTenants.Where(dt => !dt.ProjectEnvironments.ContainsKey(project.Id))
                        .Select(dt => $"'{dt.Name}'")
                        .ToList();
                    if (unDeployableTenants.Any())
                    {
                        throw new CommandException(
                                  string.Format(
                                      "Release '{0}' of project '{1}' cannot be deployed for tenant{2} {3}. This may be because either a) {4} not connected to this project, or b) you do not have permission to deploy {5} to this project.",
                                      release.Version,
                                      project.Name,
                                      unDeployableTenants.Count == 1 ? "" : "s",
                                      string.Join(" or ", unDeployableTenants),
                                      unDeployableTenants.Count == 1 ? "it is" : "they are",
                                      unDeployableTenants.Count == 1 ? "it" : "them"));
                    }

                    unDeployableTenants = deployableTenants.Where(dt =>
                    {
                        var tenantPromo = releaseTemplate.TenantPromotions.FirstOrDefault(tp => tp.Id == dt.Id);
                        return(tenantPromo == null ||
                               !tenantPromo.PromoteTo.Any(
                                   tdt => tdt.Name.Equals(environmentName, StringComparison.CurrentCultureIgnoreCase)));
                    }).Select(dt => $"'{dt.Name}'").ToList();
                    if (unDeployableTenants.Any())
                    {
                        throw new CommandException(
                                  string.Format(
                                      "Release '{0}' of project '{1}' cannot be deployed for tenant{2} {3} to environment '{4}'. This may be because a) the tenant{2} {5} not connected to this environment, a) the environment does not exist or is misspelled, b) The lifecycle has not reached this phase, possibly due to previous deployment failure,  c) you don't have permission to deploy to this environment, d) the environment is not in the list of environments defined by the lifecycle, or e) {6} unable to deploy to this channel.",
                                      release.Version,
                                      project.Name,
                                      unDeployableTenants.Count == 1 ? "" : "s",
                                      string.Join(" or ", unDeployableTenants),
                                      environmentName,
                                      unDeployableTenants.Count == 1 ? "is" : "are",
                                      unDeployableTenants.Count == 1 ? "it is" : "they are"));
                    }
                }

                if (TenantTags.Any())
                {
                    var tenantsByTag = await Repository.Tenants.FindAll(null, TenantTags.ToArray()).ConfigureAwait(false);

                    var deployableByTag = tenantsByTag.Where(dt =>
                    {
                        var tenantPromo = releaseTemplate.TenantPromotions.FirstOrDefault(tp => tp.Id == dt.Id);
                        return(tenantPromo != null && tenantPromo.PromoteTo.Any(tdt => tdt.Name.Equals(environmentName, StringComparison.CurrentCultureIgnoreCase)));
                    }).Where(tenant => !deployableTenants.Any(deployable => deployable.Id == tenant.Id));
                    deployableTenants.AddRange(deployableByTag);
                }
            }

            if (!deployableTenants.Any())
            {
                throw new CommandException(
                          string.Format(
                              "No tenants are available to be deployed for release '{0}' of project '{1}' to environment '{2}'.  This may be because a) No tenants matched the tags provided b) The tenants that do match are not connected to this project or environment, c) The tenants that do match are not yet able to release to this lifecycle phase, or d) you do not have the appropriate deployment permissions.",
                              release.Version, project.Name, environmentName));
            }


            return(deployableTenants);
        }
Esempio n. 30
0
        private List <DeploymentResource> DeployTenantedRelease(ProjectResource project, ReleaseResource release)
        {
            if (DeployToEnvironmentNames.Count != 1)
            {
                return(new List <DeploymentResource>());
            }

            var environment        = DeployToEnvironmentNames[0];
            var releaseTemplate    = Repository.Releases.GetTemplate(release);
            var deploymentTenants  = GetTenants(project, environment, release, releaseTemplate);
            var specificMachineIds = GetSpecificMachines();

            LogScheduledDeployment();

            return(deploymentTenants.Select(tenant =>
            {
                var promotion =
                    releaseTemplate.TenantPromotions
                    .First(t => t.Id == tenant.Id).PromoteTo
                    .First(tt => tt.Name.Equals(environment, StringComparison.InvariantCultureIgnoreCase));
                return CreateDeploymentTask(project, release, promotion, specificMachineIds, tenant);
            }).ToList());
        }