public async Task ShouldCreateNewChannel()
        {
            Repository.Client.RootDocument.Returns(new RootResource
            {
                Links = new LinkCollection().Add("Channels", "DOES_NOT_MATTER")
            });

            var projectName = $"Project-{Guid.NewGuid()}";
            var project = new ProjectResource()
            {
                Links = new LinkCollection().Add("Channels", "DOES_NOT_MATTER")
            };
            Repository.Projects.FindByName(projectName).Returns(project);

            var lifecycleName = $"Lifecycle-{Guid.NewGuid()}";
            Repository.Lifecycles.FindOne(Arg.Any<Func<LifecycleResource, bool>>()).Returns(new LifecycleResource());

            Repository.Projects.GetChannels(Arg.Any<ProjectResource>())
                .Returns(new ResourceCollection<ChannelResource>(Enumerable.Empty<ChannelResource>(), new LinkCollection()));

            var channelName = $"Channel-{Guid.NewGuid()}";
            CommandLineArgs.Add($"--channel={channelName}");
            CommandLineArgs.Add($"--project={projectName}");
            CommandLineArgs.Add($"--lifecycle={lifecycleName}");

            await createChannelCommand.Execute(CommandLineArgs.ToArray()).ConfigureAwait(false);

            LogLines.Should().Contain($"[Information] Channel {channelName} created");
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(GetDeployment));

            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            // Create a project
            var projectResource = new ProjectResource {Name = "Octopus"};
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(projectResource);
            octoRepo.Setup(o => o.Projects.FindByName("Gibberish")).Returns((ProjectResource) null);

            // Create a Release
            var release = new ReleaseResource { Id = "Releases-1", Links = new LinkCollection()};

            release.Links.Add("Deployments", "/api/releases/releases-1/deployments");
            octoRepo.Setup(o => o.Projects.GetReleaseByVersion(projectResource, "1.0.0")).Returns(release);
            octoRepo.Setup(o => o.Projects.GetReleaseByVersion(projectResource, "Gibberish")).Returns((ReleaseResource) null);

            // Create Deployments
            var deployments = new ResourceCollection<DeploymentResource>(new List<DeploymentResource>
            {
                new DeploymentResource {Id = "deployments-1"}
            }, new LinkCollection());
            octoRepo.Setup(o => o.Releases.GetDeployments(release, 0)).Returns(deployments);
            octoRepo.Setup(o => o.Releases.Get("Releases-1")).Returns(release);
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(GetRelease));

            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            // Create a project
            var project = new ProjectResource { Name = "Octopus" };
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(project);
            octoRepo.Setup(o => o.Projects.Get("projects-1")).Returns(project);
            octoRepo.Setup(o => o.Projects.Get("Gibberish")).Throws(new OctopusResourceNotFoundException("Not Found"));

            var releases = new List<ReleaseResource>
            {
                new ReleaseResource {Version = "1.0.0"},
                new ReleaseResource {Version = "1.0.1"},
                new ReleaseResource {Version = "1.1.0"}
            };

            octoRepo.Setup(o => o.Projects.GetReleases(project, 0))
                .Returns(new ResourceCollection<ReleaseResource>(releases, new LinkCollection()));

            octoRepo.Setup(o => o.Projects.GetReleaseByVersion(project, "1.0.0")).Returns(releases[0]);
            octoRepo.Setup(o => o.Projects.GetReleaseByVersion(project, "Gibberish")).Throws(new OctopusResourceNotFoundException("Not found"));

            octoRepo.Setup(o => o.Releases.Get("releases-1")).Returns(releases[0]);
            octoRepo.Setup(o => o.Releases.Get("Gibberish")).Throws(new OctopusResourceNotFoundException("Not found"));
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(AddVariable));
            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            _variableSet.Variables.Clear();

            var project = new ProjectResource {DeploymentProcessId = "deploymentprocesses-1"};
            project.Links.Add("Variables", "variablesets-1");
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(project);
            octoRepo.Setup(o => o.Projects.FindByName("Gibberish")).Returns((ProjectResource) null);

            octoRepo.Setup(o => o.VariableSets.Get("variablesets-1")).Returns(_variableSet);

            var process = new DeploymentProcessResource();
            process.Steps.Add(new DeploymentStepResource {Name = "Website", Id = "Step-1"});
            octoRepo.Setup(o => o.DeploymentProcesses.Get("deploymentprocesses-1")).Returns(process);

            var envs = new List<EnvironmentResource>
            {
                new EnvironmentResource {Id = "Environments-1", Name = "DEV"}
            };

            octoRepo.Setup(o => o.Environments.FindByNames(new[] {"DEV"})).Returns(envs);
            var machines = new List<MachineResource>
            {
                new MachineResource {Id = "Machines-1", Name = "web-01"}
            };
            octoRepo.Setup(o => o.Machines.FindByNames(new[] { "web-01" })).Returns(machines);
        }
        /// <summary>
        /// BeginProcessing
        /// </summary>
        protected override void BeginProcessing()
        {
            _octopus = Session.RetrieveSession(this);
            // Find the project that owns the variables we want to edit
            _project = _octopus.Projects.FindByName(Project);

            if (_project == null)
                throw new Exception(string.Format("Project '{0}' was not found.", Project));

            WriteDebug("Found project" + _project.Id);
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(UpdateVariable));
            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            var variable = new VariableResource
            {
                Id = "variables-1",
                Name = "Test",
                Value = "Test Value",
                IsSensitive = false
            };
            variable.Scope.Add(ScopeField.Action, "actions-1");
            variable.Scope.Add(ScopeField.Environment, "environments-1");
            variable.Scope.Add(ScopeField.Role, "DB");

            _variableSet.Variables.Add(variable);

            var project = new ProjectResource { DeploymentProcessId = "deploymentprocesses-1" };
            project.Links.Add("Variables", "variablesets-1");
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(project);
            octoRepo.Setup(o => o.Projects.FindByName("Gibberish")).Returns((ProjectResource)null);

            octoRepo.Setup(o => o.VariableSets.Get("variablesets-1")).Returns(_variableSet);

            var process = new DeploymentProcessResource();
            process.Steps.Add(new DeploymentStepResource { Name = "Website", Id = "Step-1" });
            octoRepo.Setup(o => o.DeploymentProcesses.Get("deploymentprocesses-1")).Returns(process);

            var envs = new List<EnvironmentResource>
            {
                new EnvironmentResource {Id = "environments-1", Name = "DEV"},
                new EnvironmentResource {Id = "environments-2", Name = "TEST"}
            };

            octoRepo.Setup(o => o.Environments.FindByNames(It.IsAny<string[]>()))
                .Returns((string[] names) => (from n in names
                    from e in envs
                    where e.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)
                    select e).ToList());

            var machines = new List<MachineResource>
            {
                new MachineResource {Id = "machines-1", Name = "db-01"},
                new MachineResource {Id = "machines-2", Name = "web-01"}
            };
            octoRepo.Setup(o => o.Machines.FindByNames(It.IsAny<string[]>())).Returns(
                (string[] names) => (from n in names
                                     from m in machines
                                     where m.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)
                                     select m).ToList());
        }
        public async Task<ReleaseResource> GetReleaseByVersion(string versionNumber, ProjectResource project, ChannelResource channel)
        {
            string message;
            ReleaseResource releaseToPromote = null;
            if (string.Equals("latest", versionNumber, StringComparison.CurrentCultureIgnoreCase))
            {
                message = channel == null
                    ? "latest release for project"
                    : $"latest release in channel '{channel.Name}'";

                log.Debug("Finding {Message:l}", message);

                var releases = await repository
                    .Projects
                    .GetReleases(project)
                    .ConfigureAwait(false);

                if (channel == null)
                {
                    releaseToPromote = releases
                        .Items // We only need the first page
                        .OrderByDescending(r => SemanticVersion.Parse(r.Version))
                        .FirstOrDefault();
                }
                else
                {
                    await releases.Paginate(repository, page =>
                    {
                        releaseToPromote = page.Items
                            .OrderByDescending(r => SemanticVersion.Parse(r.Version))
                            .FirstOrDefault(r => r.ChannelId == channel.Id);

                       // If we haven't found one yet, keep paginating
                       return releaseToPromote == null;
                    })
                    .ConfigureAwait(false);
                }
            }
            else
            {
                message = $"release {versionNumber}";
                log.Debug("Finding {Message:l}", message);
                releaseToPromote = await repository.Projects.GetReleaseByVersion(project, versionNumber).ConfigureAwait(false);
            }

            if (releaseToPromote == null)
            {
                throw new CouldNotFindException($"the {message}", project.Name);
            }
            return releaseToPromote;
        }
        public TenantResource ConnectToProjectAndEnvironments(ProjectResource project, params EnvironmentResource[] environments)
        {
            ReferenceCollection existing;
            if (ProjectEnvironments.TryGetValue(project.Id, out existing))
            {
                existing.ReplaceAll(environments.Select(e => e.Id));
            }
            else
            {
                ProjectEnvironments.Add(project.Id, new ReferenceCollection(environments.Select(e => e.Id)));
            }

            return this;
        }
 public ReleasePlan(ProjectResource project, ChannelResource channel, ReleaseTemplateResource releaseTemplate, IPackageVersionResolver versionResolver)
 {
     Project = project;
     Channel = channel;
     ReleaseTemplate = releaseTemplate;
     steps = releaseTemplate.Packages.Select(
         p => new ReleasePlanItem(
             p.StepName,
             p.PackageId,
             p.FeedId,
             p.IsResolvable,
             versionResolver.ResolveVersion(p.StepName) ?? versionResolver.ResolveVersion(p.PackageId)))
         .ToArray();
 }
        private async Task<ChannelResource> GetChannel(ProjectResource project)
        {
            var channel = default(ChannelResource);
            if (!string.IsNullOrWhiteSpace(ChannelName))
            {
                Log.Debug("Finding channel: {Channel:l}", ChannelName);
                var channels = await Repository.Projects.GetChannels(project).ConfigureAwait(false);
                channel = await channels
                    .FindOne(Repository, c => string.Equals(c.Name, ChannelName, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false);

                if (channel == null)
                    throw new CouldNotFindException("a channel named", ChannelName);
            }
            return channel;
        }
        private void DeleteOverrideForEnvironment(ProjectResource project, EnvironmentResource environment)
        {
            var autoDeployOverride = project.AutoDeployReleaseOverrides.SingleOrDefault(
                o => o.EnvironmentId == environment.Id && o.TenantId == null);

            if (autoDeployOverride == null)
            {
                Log.Warning("Did not find an auto deploy override for the project {Project:l} and environment {Environment:l}", project.Name, environment.Name);
            }
            else
            {
                project.AutoDeployReleaseOverrides.Remove(autoDeployOverride);
                Log.Information("Deleted auto deploy release override for the project {Project:l} to the environment {Environment:l}", project.Name, environment.Name);
            }
        }
        partial void ProjectResources_Inserted(ProjectResource entity)
        {
            if (entity.Employee.Email != string.Empty)
            {
                string subject = "New Project Assignment!";

                string message = string.Format("<html><body>Dear {0} {1}.<br></br><p>You have been assigned to the following project:<br></br>Project Reference: {2}.<br></br>Project Name: {3}.<br></br>Project Description: {4}.<br></br>The project starts on: {5} and is set to finish on {6}</p></body></html>", entity.Employee.FirstName, entity.Employee.LastName, entity.Project.ProjectReference, entity.Project.ProjectName, entity.Project.Description, entity.Project.StartDate, entity.Project.EndDate);

                List<string> mailTos = new List<string>();

                mailTos.Add(entity.Employee.Email);

                SendEmail(mailTos, subject, message);
            }
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof (RemoveVariable));
            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            _variableSet.Variables.Clear();

            var project = new ProjectResource();
            project.Links.Add("Variables", "variablesets-1");
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(project);
            octoRepo.Setup(o => o.Projects.FindByName("Gibberish")).Returns((ProjectResource) null);

            _variable = new VariableResource {Name = "Azure"};
            _variableSet.Variables.Add(_variable);
            _variableSet.Variables.Add(new VariableResource {Name = "ConnectionString"});
            _variableSet.Variables.Add(new VariableResource {Name = "ServerName"});
            octoRepo.Setup(o => o.VariableSets.Get("variablesets-1")).Returns(_variableSet);
        }
Exemple #14
0
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(CopyStep));
            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            // Create project
            var project = new ProjectResource
            {
                Name = "Octopus",
                Description = "Test Source",
                DeploymentProcessId = "deploymentprocesses-1",
                VariableSetId = "variablesets-1",
            };

            // Create projects
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(project);
            octoRepo.Setup(o => o.Projects.FindByName("Gibberish")).Returns((ProjectResource)null);

            // Create deployment process
            var action = new DeploymentActionResource { Name = "NuGet", ActionType = "NuGet" };
            action.Environments.Add("environments-1");
            action.Properties.Add("Something", "Value");
            action.SensitiveProperties.Add("SomethingElse", "Secret");

            var step = new DeploymentStepResource { Id = "deploymentsteps-1", Name = "Website" };
            step.Actions.Add(action);

            _process = new DeploymentProcessResource();
            _process.Steps.Add(step);

            octoRepo.Setup(o => o.DeploymentProcesses.Get(It.IsIn(new[] { "deploymentprocesses-1" }))).Returns(_process);
            octoRepo.Setup(o => o.DeploymentProcesses.Get(It.IsIn(new[] { "deploymentprocesses-2" }))).Returns(new DeploymentProcessResource());

            // Create variable set
            var variable = new VariableResource { Name = "Name", Value = "Value" };
            variable.Scope.Add(ScopeField.Action, "DeploymentsActions-1");
            variable.Scope.Add(ScopeField.Environment, "Environments-1");

            var variableSet = new VariableSetResource();
            variableSet.Variables.Add(variable);

            octoRepo.Setup(o => o.VariableSets.Get(It.IsIn(new[] { "variablesets-1" }))).Returns(variableSet);
            octoRepo.Setup(o => o.VariableSets.Get(It.IsIn(new[] { "variablesets-2" }))).Returns(new VariableSetResource());
        }
        public static VariableCollection GetProjectVariables(this List<ResourceVariableSetPair> variableSets, ProjectResource project, Dictionary<ScopeField, ScopeValue> scopeDictionary)
        {
            VariableCollection variablesPaired = new VariableCollection();

            foreach (ResourceVariableSetPair variableSetPair in variableSets)
            {
                foreach (VariableResource variableResource in variableSetPair.VariableSet.Variables)
                {
                    if (scopeDictionary != null && !variableResource.Scope.IsApplicableTo(scopeDictionary))
                    {
                        continue;
                    }

                    variablesPaired.AddOrUpdate(variableResource, variableSetPair.Resource);

                }
            }
            return variablesPaired;
        }
        public void SetUp()
        {
            createAutoDeployOverrideCommand = new CreateAutoDeployOverrideCommand(RepositoryFactory, Log, FileSystem, ClientFactory);

            environment = new EnvironmentResource { Name = "Production", Id = "Environments-001" };
            project = new ProjectResource("Projects-1", "OctoFx", "OctoFx");
            release = new ReleaseResource("1.2.0", "Projects-1", "Channels-1");
            octopusTenant = new TenantResource
            {
                Id = "Tenants-1",
                Name = "Octopus",
                ProjectEnvironments = { ["Projects-1"] = new ReferenceCollection("Environments-001") }
            };

            Repository.Environments.FindByName("Production").Returns(
                environment
            );

            Repository.Projects.FindByName("OctoFx").Returns(
                project
            );

            Repository.Projects.GetReleaseByVersion(Arg.Any<ProjectResource>(), "1.2.0").Returns(
                release
            );

            Repository.Tenants.FindByNames(Arg.Any<IEnumerable<string>>()).Returns(
                new List<TenantResource>
                {
                    octopusTenant
                }
            );
            Repository.Tenants.FindAll(null, Arg.Any<string[]>()).Returns(
                new List<TenantResource>
                {
                    octopusTenant
                }
            );

            Repository.Projects.When(x => x.Modify(Arg.Any<ProjectResource>()))
                .Do(x => savedProject = x.Args()[0] as ProjectResource);
        }
        public void SetUp()
        {
            deployReleaseCommand = new DeployReleaseCommand(RepositoryFactory, Log, FileSystem);

            var project = new ProjectResource();
            var release = new ReleaseResource { Version = "1.0.0" };
            var releases = new ResourceCollection<ReleaseResource>(new[] { release }, new LinkCollection());
            var deploymentPromotionTarget = new DeploymentPromotionTarget { Name = "TestEnvironment" };
            var promotionTargets = new List<DeploymentPromotionTarget> { deploymentPromotionTarget };
            var deploymentTemplate = new DeploymentTemplateResource { PromoteTo = promotionTargets };
            var deploymentPreviewResource = new DeploymentPreviewResource { StepsToExecute = new List<DeploymentTemplateStep>() };
            var deployment = new DeploymentResource { TaskId = "1" };
            taskResource = new TaskResource();

            Repository.Projects.FindByName(ProjectName).Returns(project);
            Repository.Projects.GetReleases(project).Returns(releases);
            Repository.Releases.GetPreview(deploymentPromotionTarget).Returns(deploymentPreviewResource);
            Repository.Releases.GetTemplate(release).Returns(deploymentTemplate);
            Repository.Deployments.Create(Arg.Any<DeploymentResource>()).Returns(deployment);
            Repository.Tasks.Get(deployment.TaskId).Returns(taskResource);
        }
Exemple #18
0
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(GetAction));

            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            // Create a project
            var projectResource = new ProjectResource {Name = "Octopus"};
            octoRepo.Setup(o => o.Projects.FindByName("Octopus")).Returns(projectResource);

            // Create a deployment process
            var stepResource = new DeploymentStepResource();
            stepResource.Actions.Add(new DeploymentActionResource { Name = "Do Stuff", Id = "Globally unique identifier"});
            stepResource.Actions.Add(new DeploymentActionResource { Name = "Do Other Stuff", Id = "Universally unique identifier" });

            var dpResource = new DeploymentProcessResource();
            dpResource.Steps.Add(stepResource);

            var dpRepo = new Mock<IDeploymentProcessRepository>();
            dpRepo.Setup(d => d.Get(It.IsAny<string>())).Returns(dpResource);

            octoRepo.Setup(o => o.DeploymentProcesses).Returns(dpRepo.Object);
        }
        public void Init()
        {
            _ps = Utilities.CreatePowerShell(CmdletName, typeof(UseVariableSet));

            var octoRepo = Utilities.AddOctopusRepo(_ps.Runspace.SessionStateProxy.PSVariable);

            // Create a project
            _projectResource = new ProjectResource {Name = "Octopus"};
            var projectRepo = new Mock<IProjectRepository>();
            projectRepo.Setup(p => p.FindByName("Octopus")).Returns(_projectResource);
            projectRepo.Setup(p => p.Modify(It.IsAny<ProjectResource>())).Returns((ProjectResource p) => p);

            octoRepo.Setup(o => o.Projects).Returns(projectRepo.Object);

            // Create some library variable sets
            var libraryResources = new List<LibraryVariableSetResource>
            {
                new LibraryVariableSetResource {Id = "LibraryVariableSets-1", Name = "ConnectionStrings"},
                new LibraryVariableSetResource {Id = "LibraryVariableSets-2", Name = "Azure"},
            };

            octoRepo.Setup(o => o.LibraryVariableSets.FindAll()).Returns(libraryResources);
        }
        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);

            var 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));
                return(CreateDeploymentTask(project, release, promotion, specificMachineIds, tenant));
            });

            return(await Task.WhenAll(createTasks).ConfigureAwait(false));
        }
        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))
                               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, is misspelled or the casing is not the same, 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));
        }
Exemple #22
0
        public void Setup()
        {
            // setup data objects
            channelVersionRules = new List <ChannelVersionRuleResource>();
            projectResource     = new ProjectResource
            {
                DeploymentProcessId = TestHelpers.GetId("deploymentprocess"),
                Id = TestHelpers.GetId("project")
            };
            deploymentProcessResource = new DeploymentProcessResource
            {
                ProjectId = projectResource.Id,
                Id        = projectResource.DeploymentProcessId
            };

            releaseTemplateResource = new ReleaseTemplateResource
            {
                DeploymentProcessId = projectResource.DeploymentProcessId,
                Packages            = new List <ReleaseTemplatePackage>(),
                Id = TestHelpers.GetId("releaseTemplate")
            };
            channelResource = new ChannelResource
            {
                IsDefault = true,
                Id        = TestHelpers.GetId("channel"),
                ProjectId = projectResource.Id,
                Rules     = channelVersionRules,
                Name      = TestHelpers.GetId("channelname")
            };
            feedResource = new FeedResource
            {
                Id    = BuiltInFeedId,
                Name  = "Built in feed",
                Links = new LinkCollection {
                    { "SearchTemplate", TestHelpers.GetId("searchUri") }
                }
            };

            // setup mocks
            logger                = Substitute.For <ILogger>();
            versionResolver       = Substitute.For <IPackageVersionResolver>();
            versionRuleTester     = Substitute.For <IChannelVersionRuleTester>();
            commandOutputProvider = Substitute.For <ICommandOutputProvider>();

            deploymentProcessRepository = Substitute.For <IDeploymentProcessRepository>();
            deploymentProcessRepository.Get(projectResource.DeploymentProcessId)
            .Returns(Task.FromResult(deploymentProcessResource));
            deploymentProcessRepository
            .GetTemplate(Arg.Is(deploymentProcessResource),
                         Arg.Is(channelResource))
            .Returns(Task.FromResult(releaseTemplateResource));
            versionRuleTester
            .Test(Arg.Any <IOctopusAsyncRepository>(), Arg.Any <ChannelVersionRuleResource>(), Arg.Any <string>(), Arg.Any <string>())
            .Returns(Task.FromResult(channelVersionRuleTestResult));

            deploymentProcessRepositoryBeta = Substitute.For <IDeploymentProcessRepositoryBeta>();
            deploymentProcessRepositoryBeta.Get(projectResource, Arg.Any <string>())
            .Returns(Task.FromResult(deploymentProcessResource));

            var feeds = new List <FeedResource>
            {
                feedResource
            };

            releaseRepository = Substitute.For <IReleaseRepository>();
            feedRepository    = Substitute.For <IFeedRepository>();
            feedRepository.Get(Arg.Any <string[]>()).Returns(feeds);
            feedRepository.FindByNames(Arg.Any <IEnumerable <string> >()).Returns(feeds);

            repository = Substitute.For <IOctopusAsyncRepository>();
            repository.DeploymentProcesses.Returns(deploymentProcessRepository);
            repository.DeploymentProcesses.Beta().Returns(deploymentProcessRepositoryBeta);
            repository.Releases.Returns(releaseRepository);
            repository.Feeds.Returns(feedRepository);
            repository.Client
            .Get <List <PackageResource> >(Arg.Any <string>(), Arg.Any <IDictionary <string, object> >())
            .Returns(packages);

            builder      = new ReleasePlanBuilder(logger, versionResolver, versionRuleTester, commandOutputProvider);
            gitReference = null;
        }
Exemple #23
0
 public TenantEditor ConnectToProjectAndEnvironments(ProjectResource project, params EnvironmentResource[] environments)
 {
     Instance.ConnectToProjectAndEnvironments(project, environments);
     return(this);
 }
        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);
            var 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));
                return CreateDeploymentTask(project, release, promotion, specificMachineIds, tenant);
            });

            return await Task.WhenAll(createTasks).ConfigureAwait(false);
        }
        private static ElementReference ResolveReference(ScopeField key, string id, IOctopusRepository repository, DeploymentProcessResource deploymentProcessResource, ProjectResource projectResource)
        {
            Logger.Trace($"Resolving reference {id}...");

            switch (key)
            {
            case ScopeField.Action:
                return(new ElementReference(GetDeploymentAction(deploymentProcessResource, a => a.Id, id, nameof(DeploymentActionResource.Id)).Name));

            case ScopeField.Environment:
                return(new ElementReference(repository.Environments.FindByName(id)?.Name));

            case ScopeField.Machine:
                return(new ElementReference(repository.Machines.FindByName(id)?.Name));

            case ScopeField.Role:
                return(new ElementReference(id));

            case ScopeField.Channel:
                return(new ElementReference(repository.Channels.Get(id).Name));

            case ScopeField.TenantTag:
                return(new ElementReference(id));

            default:
                throw new InvalidOperationException($"Unsupported ScopeField: {key}");
            }
        }
        private static string ResolveId(VariableScopeType key, ElementReference reference, IOctopusRepository repository, DeploymentProcessResource deploymentProcess, ProjectResource project)
        {
            switch (key)
            {
            case VariableScopeType.Environment:
                return(repository.Environments.ResolveResourceId(reference));

            case VariableScopeType.Machine:
                return(repository.Machines.ResolveResourceId(reference));

            case VariableScopeType.Role:
                return(reference.Name);

            case VariableScopeType.Action:
                return(GetDeploymentAction(deploymentProcess, a => a.Name, reference.Name, nameof(DeploymentActionResource.Name)).Id);

            case VariableScopeType.Channel:
                return(repository.Channels.FindByName(project, reference.Name).Id);

            case VariableScopeType.TenantTag:
                return(reference.Name);

            default:
                throw new InvalidOperationException($"Unsupported ScopeField: {key}");
            }
        }
 public static ScopeSpecification UpdateWith(this ScopeSpecification resource, IReadOnlyDictionary <VariableScopeType, IEnumerable <ElementReference> > model, IOctopusRepository repository, DeploymentProcessResource deploymentProcess, ProjectResource project)
 {
     resource.Clear();
     foreach (var kv in model)
     {
         resource.Add((ScopeField)kv.Key, new ScopeValue(kv.Value.Select(reference => ResolveId(kv.Key, reference, repository, deploymentProcess, project))));
     }
     return(resource);
 }
 public static Dictionary <VariableScopeType, IEnumerable <ElementReference> > ToModel(this ScopeSpecification resource, DeploymentProcessResource deploymentProcessResource, ProjectResource projectResource, IOctopusRepository repository)
 {
     return(resource
            .Where(kv => (VariableScopeType)kv.Key != VariableScopeType.Environment)
            .ToDictionary(kv => (VariableScopeType)kv.Key,
                          kv => kv.Value.AsParallel()
                          .Select(id =>
                                  ResolveReference(kv.Key, id, repository, deploymentProcessResource, projectResource))
                          .AsParallel().ToArray().AsEnumerable()));
 }
 public ReleasePackage(ILogger logger, IOctopusServer server, IOctopusCache octopusCache, ProjectResource project, ReleaseResource release, ChannelResource channel) : base(logger, server, project, release, true)
 {
     Cache         = octopusCache;
     Channel       = channel;
     _nugetPackage = new Lazy <byte[]>(() => Cache.GetNuGetPackage(project, release, CreateNuGetPackage));
 }
Exemple #30
0
        public async Task <ReleaseResource> GetReleaseByVersion(string versionNumber, ProjectResource project, ChannelResource channel)
        {
            string          message;
            ReleaseResource releaseToPromote = null;

            if (string.Equals("latest", versionNumber, StringComparison.CurrentCultureIgnoreCase))
            {
                message = channel == null
                    ? "latest release for project"
                    : $"latest release in channel '{channel.Name}'";

                commandOutputProvider.Debug("Finding {Message:l}", message);

                var releases = await repository
                               .Projects
                               .GetReleases(project)
                               .ConfigureAwait(false);

                if (channel == null)
                {
                    releaseToPromote = releases
                                       .Items // We only need the first page
                                       .OrderByDescending(r => SemanticVersion.Parse(r.Version))
                                       .FirstOrDefault();
                }
                else
                {
                    await releases.Paginate(repository, page =>
                    {
                        releaseToPromote = Enumerable.OrderByDescending <ReleaseResource, SemanticVersion>(page.Items, r => SemanticVersion.Parse(r.Version))
                                           .FirstOrDefault(r => r.ChannelId == channel.Id);

                        // If we haven't found one yet, keep paginating
                        return(releaseToPromote == null);
                    })
                    .ConfigureAwait(false);
                }
            }
            else
            {
                message = $"release {versionNumber}";
                commandOutputProvider.Debug("Finding {Message:l}", message);
                releaseToPromote = await repository.Projects.GetReleaseByVersion(project, versionNumber).ConfigureAwait(false);
            }

            if (releaseToPromote == null)
            {
                throw new CouldNotFindException($"the {message}", project.Name);
            }
            return(releaseToPromote);
        }
        async Task <IReadOnlyList <KeyValuePair <string, ChannelResource> > > ImportProjectChannels(List <ChannelResource> channels, ProjectResource importedProject, IDictionary <string, LifecycleResource> channelLifecycles)
        {
            Log.Debug("Importing the channels for the project");
            var allChannels = await Repository.Projects.GetChannels(importedProject).ConfigureAwait(false);

            var projectChannels       = (await allChannels.GetAllPages(Repository).ConfigureAwait(false)).ToArray();
            var defaultChannel        = projectChannels.ToArray().FirstOrDefault(c => c.IsDefault);
            var newDefaultChannel     = channels.FirstOrDefault(nc => nc.IsDefault);
            var defaultChannelUpdated = false;

            var results = new List <KeyValuePair <string, ChannelResource> >();

            foreach (var channel in channels)
            {
                var existingChannel =
                    projectChannels.FirstOrDefault(c => c.Name.Equals(channel.Name, StringComparison.OrdinalIgnoreCase));

                if (existingChannel != null)
                {
                    Log.Debug($"Channel '{existingChannel.Name}' already exists, channel will be updated with new settings");
                    existingChannel.Name        = channel.Name;
                    existingChannel.Description = channel.Description;
                    existingChannel.IsDefault   = channel.IsDefault;
                    if (channel.LifecycleId != null)
                    {
                        existingChannel.LifecycleId = channelLifecycles[channel.LifecycleId].Id;
                    }
                    if (existingChannel.IsDefault && !existingChannel.Name.Equals(newDefaultChannel?.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        existingChannel.IsDefault = false;
                    }
                    existingChannel.Rules.Clear();
                    existingChannel.Rules.AddRange(channel.Rules);
                    if (existingChannel.Name.Equals(defaultChannel?.Name))
                    {
                        defaultChannelUpdated = true;
                    }
                    var modified = await Repository.Channels.Modify(existingChannel).ConfigureAwait(false);

                    results.Add(new KeyValuePair <string, ChannelResource>(channel.Id, modified));
                }
                else
                {
                    Log.Debug($"Channel '{channel.Name}' does not exist, a new channel will be created");
                    channel.ProjectId = importedProject.Id;
                    if (channel.LifecycleId != null)
                    {
                        channel.LifecycleId = channelLifecycles[channel.LifecycleId].Id;
                    }

                    var created = await Repository.Channels.Create(channel).ConfigureAwait(false);

                    results.Add(new KeyValuePair <string, ChannelResource>(channel.Id, created));
                }
            }

            if (!KeepExistingProjectChannels && !defaultChannelUpdated)
            {
                await Repository.Channels.Delete(defaultChannel).ConfigureAwait(false);
            }

            return(results);
        }
        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))
                    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, b) the name is misspelled, 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<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;
        }
        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"
                }
            });
        }
Exemple #35
0
        private void CreateNewProject(string groupId)
        {
            WriteVerbose(string.Format("Creating the project '{0}'...", Destination));

            _newProject = _octopus.Projects.Create(new ProjectResource
            {
                Name = Destination,
                Description = _oldProject.Description,
                ProjectGroupId = groupId,
                DefaultToSkipIfAlreadyInstalled = _oldProject.DefaultToSkipIfAlreadyInstalled,
                IncludedLibraryVariableSetIds = _oldProject.IncludedLibraryVariableSetIds,
                VersioningStrategy = _oldProject.VersioningStrategy,
                AutoCreateRelease = _oldProject.AutoCreateRelease,
                ReleaseCreationStrategy = _oldProject.ReleaseCreationStrategy,
                IsDisabled = _oldProject.IsDisabled,
                LifecycleId = _oldProject.LifecycleId
            });

            WriteVerbose(string.Format("Project '{0}' created.", Destination));
        }
        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, deploymentProcess, versionResolver);

            if (plan.UnresolvedSteps.Any())
            {
                log.Debug("The package version for some packageSteps 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.PackageSteps)
                {
                    // 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);
        }
Exemple #37
0
        public async Task <ReleasePlan> Build(IOctopusAsyncRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag, string versionPreReleaseTagFallBacks, string softDefaultPackageVersion, bool LatestByPublishDate)
        {
            if (repository == null)
            {
                throw new ArgumentNullException(nameof(repository));
            }
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            commandOutputProvider.Debug("Finding deployment process...");
            var deploymentProcess = await repository.DeploymentProcesses.Get(project.DeploymentProcessId).ConfigureAwait(false);

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

            var plan = new ReleasePlan(project, channel, releaseTemplate, deploymentProcess, versionResolver);

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


                    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.ActionName, unresolved.PackageFeedId));
                    }
                    var             packages = new System.Collections.Generic.List <Octopus.Client.Model.PackageResource>();
                    PackageResource latestPackage;
                    String          versionSource = "Latest available";

                    var filters = BuildChannelVersionFilters(unresolved.ActionName, unresolved.PackageReferenceName, channel);
                    filters["packageId"] = unresolved.PackageId;

                    commandOutputProvider.Debug("------------------------------------------\r\n");
                    commandOutputProvider.Debug("Step: '{StepName:l}', Package: '{PackageId:l}':\r\n", unresolved.ActionName, unresolved.PackageId);


                    //look for exact version of package specified softDefaultPackageVersion, bypass all further version-seeking heurstics if succeed
                    if (!string.IsNullOrWhiteSpace(softDefaultPackageVersion))
                    {
                        filters["versionRange"] = "[" + softDefaultPackageVersion + "]";
                        packages = await repository.Client.Get <List <PackageResource> >(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);

                        latestPackage = packages.FirstOrDefault();
                        if (latestPackage != null)
                        {
                            commandOutputProvider.Debug("Version '{Version:l}' was found using softDefaultPackageVersion specified. Any further version-seeking heurstics will be bypassed.", latestPackage.Version);
                            versionSource = "softDefaultPackageVersion";
                            unresolved.SetVersionFromLatest(latestPackage.Version, versionSource);
                            continue;
                        }
                        else
                        {
                            filters.Remove("versionRange");
                            commandOutputProvider.Debug("Could not find package with softDefaultPackageVersion: '{softDefaultPackageVersion:l}', falling back to search with another specified methods (versionPreReleaseTag,versionPreReleaseTagFallBacks)", softDefaultPackageVersion);
                        }
                    }



                    if (!string.IsNullOrWhiteSpace(versionPreReleaseTag))
                    {
                        filters["preReleaseTag"] = versionPreReleaseTag;
                        versionSource            = "versionPreReleaseTag";
                        commandOutputProvider.Debug("versionPreReleaseTag: '{Tag:l}' was specified. Looking for latest package with this tag.'", versionPreReleaseTag);
                    }



                    bool ResolverLooksForPreReleasePackage = !(string.IsNullOrWhiteSpace(versionPreReleaseTag) || versionPreReleaseTag == "^$");


                    //As we can't sort by publishing date on the server side, we have to take all packages and sort them on the client side
                    if (LatestByPublishDate && ResolverLooksForPreReleasePackage)
                    {
                        filters["take"] = 10000;
                    }
                    else
                    {
                        //AIR-1533. Speed-up package choosing
                        filters["take"] = 1;
                    }


                    packages = await repository.Client.Get <List <PackageResource> >(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);



                    //Get the latest published package for release instead of the package has the biggest SemVer
                    //Only for pre-release packages and only if LatestByPublishDate prop specified
                    //Using latest published package is inappropriate for release packages, because hotfix releases for old versions may be pushed after main major versions.
                    if (LatestByPublishDate && ResolverLooksForPreReleasePackage)
                    {
                        latestPackage = packages.OrderByDescending(o => o.Published).FirstOrDefault();
                        if (latestPackage != null)
                        {
                            commandOutputProvider.Debug("'--latestbypublishdate' flag was specified. Package resolver will choose version of package by the latest publishing date instead of the higest SemVer version.");
                        }
                    }
                    else
                    {
                        latestPackage = packages.FirstOrDefault();
                    }



                    if (latestPackage == null && !string.IsNullOrWhiteSpace(versionPreReleaseTag) && !string.IsNullOrWhiteSpace(versionPreReleaseTagFallBacks))
                    {
                        commandOutputProvider.Debug("Could not find latest package with pre-release '{Tag:l}', falling back to search with pre-release tags '{FallBackTags:l}' ", versionPreReleaseTag, versionPreReleaseTagFallBacks);
                        //trim values and remove empty ones
                        List <string> versionPreReleaseTagFallBacksList = versionPreReleaseTagFallBacks.Split(',').ToList().Select(s => s.Trim()).ToList();
                        versionPreReleaseTagFallBacksList = versionPreReleaseTagFallBacksList.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();

                        foreach (string versionPreReleaseTagFallBack in versionPreReleaseTagFallBacksList)
                        {
                            //similar beahaviour as for general versionPreReleaseTag
                            //Get the latest published package for release instead of the package has the biggest SemVer
                            filters.Remove("take");

                            filters["preReleaseTag"] = versionPreReleaseTagFallBack;

                            ResolverLooksForPreReleasePackage = !(versionPreReleaseTagFallBack == "^$");


                            //As we can't sort by publishing date on the server side, we have to take all packages and sort them on the client side
                            if (LatestByPublishDate && ResolverLooksForPreReleasePackage)
                            {
                                filters["take"] = 10000;
                            }
                            else
                            {
                                //AIR-1533. Speed-up package choosing
                                filters["take"] = 1;
                            }

                            packages = await repository.Client.Get <List <PackageResource> >(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);

                            if (LatestByPublishDate && ResolverLooksForPreReleasePackage)
                            {
                                latestPackage = packages.OrderByDescending(o => o.Published).FirstOrDefault();
                                if (latestPackage != null)
                                {
                                    commandOutputProvider.Debug("'--latestbypublishdate' flag was specified. Package resolver will choose version by the latest publishing date instead of the higest SemVer version.");
                                }
                            }
                            else
                            {
                                latestPackage = packages.FirstOrDefault();
                            }

                            if (latestPackage != null)
                            {
                                versionSource = "versionPreReleaseTagFallBacks";
                                break;
                            }
                        }
                    }


                    if (latestPackage == null)
                    {
                        commandOutputProvider.Error("Could not find any packages with this ID in the feed '{FeedUri:l}'", feed.Name);
                    }
                    else
                    {
                        commandOutputProvider.Debug("Selected version '{Version:l}'", latestPackage.Version);
                        unresolved.SetVersionFromLatest(latestPackage.Version, versionSource);
                    }
                }
            }

            // Test each step in this plan satisfies the channel version rules
            if (channel != null)
            {
                foreach (var step in plan.PackageSteps)
                {
                    // Note the rule can be null, meaning: anything goes
                    var rule   = channel.Rules.SingleOrDefault(r => r.ActionPackages.Any(pkg => pkg.DeploymentActionNameMatches(step.ActionName) && pkg.PackageReferenceNameMatches(step.PackageReferenceName)));
                    var result = await versionRuleTester.Test(repository, rule, step.Version).ConfigureAwait(false);

                    step.SetChannelVersionRuleTestResult(result);
                }
            }

            return(plan);
        }
        public static DeploymentProcessResource UpdateWith(this DeploymentProcessResource resource, DeploymentProcess model, ProjectResource projectResource, IOctopusRepository repository)
        {
            resource.Steps.Clear();
            foreach (var step in model.DeploymentSteps.Select(s => new DeploymentStepResource().UpdateWith(s, projectResource, repository)))
            {
                resource.Steps.Add(step);
            }


            return(resource);
        }
        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);
        }
        public async Task Request()
        {
            if (!Repository.SupportsChannels())
            {
                throw new CommandException("Your Octopus server does not support channels, which was introduced in Octopus 3.2. Please upgrade your Octopus server to start using channels.");
            }
            if (string.IsNullOrWhiteSpace(projectName))
            {
                throw new CommandException("Please specify a project using the parameter: --project=ProjectXYZ");
            }
            if (string.IsNullOrWhiteSpace(channelName))
            {
                throw new CommandException("Please specify a channel name using the parameter: --channel=ChannelXYZ");
            }

            commandOutputProvider.Debug("Loading project {Project:l}...", projectName);

            project = await Repository.Projects.FindByName(projectName).ConfigureAwait(false);

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

            lifecycle = null;
            if (string.IsNullOrWhiteSpace(lifecycleName))
            {
                commandOutputProvider.Debug("No lifecycle specified. Going to inherit the project lifecycle...");
            }
            else
            {
                commandOutputProvider.Debug("Loading lifecycle {Lifecycle:l}...", lifecycleName);
                lifecycle = await Repository.Lifecycles.FindOne(l => string.Compare(l.Name, lifecycleName, StringComparison.OrdinalIgnoreCase) == 0).ConfigureAwait(false);

                if (lifecycle == null)
                {
                    throw new CouldNotFindException("lifecycle named", lifecycleName);
                }
            }

            var channels = await Repository.Projects.GetChannels(project).ConfigureAwait(false);

            channel = await channels
                      .FindOne(Repository, ch => string.Equals(ch.Name, channelName, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false);

            if (channel == null)
            {
                createdNewChannel = true;
                channel           = new ChannelResource
                {
                    ProjectId   = project.Id,
                    Name        = channelName,
                    IsDefault   = makeDefaultChannel ?? false,
                    Description = channelDescription ?? string.Empty,
                    LifecycleId = lifecycle?.Id, // Allow for the default lifeycle by propagating null
                    Rules       = new List <ChannelVersionRuleResource>(),
                };

                commandOutputProvider.Debug("Creating channel {Channel:l}", channelName);
                await Repository.Channels.Create(channel).ConfigureAwait(false);

                commandOutputProvider.Information("Channel {Channel:l} created", channelName);
                return;
            }

            if (!updateExisting)
            {
                throw new CommandException("This channel already exists. If you would like to update it, please use the parameter: --update-existing");
            }

            channelUpdateRequired = false;
            if (channel.LifecycleId != lifecycle?.Id)
            {
                if (lifecycle == null)
                {
                    commandOutputProvider.Information("Updating this channel to inherit the project lifecycle for promoting releases");
                }
                else
                {
                    commandOutputProvider.Information("Updating this channel to use lifecycle {Lifecycle:l} for promoting releases", lifecycle.Name);
                }

                channel.LifecycleId   = lifecycle?.Id;
                channelUpdateRequired = true;
            }

            if (!channel.IsDefault && makeDefaultChannel == true)
            {
                commandOutputProvider.Information("Making this the default channel for {Project:l}", project.Name);
                channel.IsDefault     = makeDefaultChannel ?? channel.IsDefault;
                channelUpdateRequired = true;
            }

            if (!string.IsNullOrWhiteSpace(channelDescription) && channel.Description != channelDescription)
            {
                commandOutputProvider.Information("Updating channel description to '{Description:l}'", channelDescription);
                channel.Description   = channelDescription ?? channel.Description;
                channelUpdateRequired = true;
            }

            if (!channelUpdateRequired)
            {
                commandOutputProvider.Information("The channel already looks exactly the way it should, no need to update it.");
                return;
            }

            commandOutputProvider.Debug("Updating channel {Channel:l}", channelName);
            await Repository.Channels.Modify(channel).ConfigureAwait(false);

            commandOutputProvider.Information("Channel {Channel:l} updated", channelName);
        }
        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);

                Log.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, is misspelled or the casing is not the same, 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);
        }
        public void DeployRelease(ProjectResource project, ReleaseResource release, List<string> environments)
        {
            if (environments.Count == 0)
                return;

            var deployments = new List<DeploymentResource>();
            var deploymentTasks = new List<TaskResource>();

            var releaseTemplate = Repository.Releases.GetTemplate(release);

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

            var unknownEnvironments = promotingEnvironments.Where(p => p.Promote == 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, b) the name is misspelled, 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"
                        ));
            }

            var specificMachineIds = new ReferenceCollection();
            if (SpecificMachineNames.Any())
            {
                var machines = Repository.Machines.FindByNames(SpecificMachineNames);
                var missing = SpecificMachineNames.Except(machines.Select(m => m.Name), StringComparer.OrdinalIgnoreCase).ToList();
                if (missing.Any())
                {
                    throw new CommandException("The following specific machines could not be found: " + missing.ReadableJoin());
                }

                specificMachineIds.AddRange(machines.Select(m => m.Id));
            }

            if (DeployAt != null)
            {
                var now = DateTimeOffset.UtcNow;
                Log.InfoFormat("Deployment will be scheduled to start in: {0}", (DeployAt.Value - now).FriendlyDuration());
            }

            foreach (var environment in promotingEnvironments)
            {
                var promote = environment.Promote;
                var preview = Repository.Releases.GetPreview(promote);

                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.WarnFormat("No step/action named '{0}' could be found when deploying to environment '{1}', so the step cannot be skipped.", step, environment);
                    }
                    else
                    {
                        Log.DebugFormat("Skipping step: {0}", stepToExecute.ActionName);
                        skip.Add(stepToExecute.ActionId);
                    }
                }

                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;
                    }
                }

                var deployment = Repository.Deployments.Create(new DeploymentResource
                {
                    EnvironmentId = promote.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
                });

                Log.InfoFormat("Deploying {0} {1} to: {2} (Guided Failure: {3})", project.Name, release.Version, environment.Name, deployment.UseGuidedFailure ? "Enabled" : "Not Enabled");

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

                deployments.Add(deployment);
                deploymentTasks.Add(Repository.Tasks.Get(deployment.TaskId));
            }

            if (WaitForDeployment)
            {
                WaitForDeploymentToComplete(deploymentTasks, deployments, project, release);
            }
        }
Exemple #43
0
 public virtual void OnAfterExportResource(ProjectBuildProcess process, ProjectResource resource)
 {
 }
Exemple #44
0
 public OctoProject(ProjectResource project)
 {
     Curr        = project;
     ProjectName = Curr.Name;
 }
        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, DeploymentTimeout, 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);
            }
        }
Exemple #46
0
 public OctoProject(string projectName)
 {
     Curr        = WebClient.GetWebClientRef().GetProjectByName(projectName);
     ProjectName = Curr.Name;
 }
 protected async Task DeployRelease(ProjectResource project, ReleaseResource release)
 {
     var deploymentsTask = IsTenantedDeployment ?
         DeployTenantedRelease(project, release) : 
         DeployToEnvironments(project, release);
     var deployments = await deploymentsTask.ConfigureAwait(false);
     if (deployments.Any() && WaitForDeployment)
     {
         await WaitForDeploymentToComplete(deployments, project, release).ConfigureAwait(false);
     }
 }
Exemple #48
0
        public void WaitForDeploymentToComplete(List <TaskResource> deploymentTasks, List <DeploymentResource> deployments, ProjectResource project, ReleaseResource release)
        {
            if (showProgress && deploymentTasks.Count > 1)
            {
                Log.InfoFormat("Only progress of the first task ({0}) will be shown", deploymentTasks.First().Description);
            }

            try
            {
                Log.InfoFormat("Waiting for {0} deployment(s) to complete....", deploymentTasks.Count);
                Repository.Tasks.WaitForCompletion(deploymentTasks.ToArray(), DeploymentStatusCheckSleepCycle.Seconds, (int)DeploymentTimeout.TotalMinutes, PrintTaskOutput);
                var failed = false;
                foreach (var deploymentTask in deploymentTasks)
                {
                    var updated = Repository.Tasks.Get(deploymentTask.Id);
                    if (updated.FinishedSuccessfully)
                    {
                        Log.InfoFormat("{0}: {1}", updated.Description, updated.State);
                    }
                    else
                    {
                        Log.ErrorFormat("{0}: {1}, {2}", updated.Description, updated.State, updated.ErrorMessage);
                        failed = true;

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

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

                CancelDeploymentOnTimeoutIfRequested(deploymentTasks);

                var guidedFailureDeployments =
                    from d in deployments
                    where d.UseGuidedFailure
                    select d;
                if (guidedFailureDeployments.Any())
                {
                    Log.Warn("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 = Repository.Environments.Get(guidedFailureDeployment.Link("Environment"));
                        Log.WarnFormat("  - {0}: {1}", environment.Name, GetPortalUrl(string.Format("/app#/projects/{0}/releases/{1}/deployments/{2}", project.Slug, release.Version, guidedFailureDeployment.Id)));
                    }
                }
                throw new CommandException(e.Message);
            }
        }
        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);

                Log.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 lifecycle has not reached this phase, b) the environment does not exist, b) the environment name is misspelled, 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;
        }
Exemple #50
0
        public void DeployRelease(ProjectResource project, ReleaseResource release, List <string> environments)
        {
            if (environments.Count == 0)
            {
                return;
            }

            var deployments     = new List <DeploymentResource>();
            var deploymentTasks = new List <TaskResource>();

            var releaseTemplate = Repository.Releases.GetTemplate(release);

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

            var unknownEnvironments = promotingEnvironments.Where(p => p.Promote == 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, b) the name is misspelled, 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"
                                        ));
            }

            var specificMachineIds = new ReferenceCollection();

            if (SpecificMachineNames.Any())
            {
                var machines = Repository.Machines.FindByNames(SpecificMachineNames);
                var missing  = SpecificMachineNames.Except(machines.Select(m => m.Name), StringComparer.OrdinalIgnoreCase).ToList();
                if (missing.Any())
                {
                    throw new CommandException("The following specific machines could not be found: " + missing.ReadableJoin());
                }

                specificMachineIds.AddRange(machines.Select(m => m.Id));
            }

            if (DeployAt != null)
            {
                var now = DateTimeOffset.UtcNow;
                Log.InfoFormat("Deployment will be scheduled to start in: {0}", (DeployAt.Value - now).FriendlyDuration());
            }

            foreach (var environment in promotingEnvironments)
            {
                var promote = environment.Promote;
                var preview = Repository.Releases.GetPreview(promote);

                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.WarnFormat("No step/action named '{0}' could be found when deploying to environment '{1}', so the step cannot be skipped.", step, environment);
                    }
                    else
                    {
                        Log.DebugFormat("Skipping step: {0}", stepToExecute.ActionName);
                        skip.Add(stepToExecute.ActionId);
                    }
                }

                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;
                    }
                }

                var deployment = Repository.Deployments.Create(new DeploymentResource
                {
                    EnvironmentId            = promote.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
                });

                Log.InfoFormat("Deploying {0} {1} to: {2} (Guided Failure: {3})", project.Name, release.Version, environment.Name, deployment.UseGuidedFailure ? "Enabled" : "Not Enabled");

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

                deployments.Add(deployment);
                deploymentTasks.Add(Repository.Tasks.Get(deployment.TaskId));
            }

            if (WaitForDeployment)
            {
                WaitForDeploymentToComplete(deploymentTasks, deployments, project, release);
            }
        }
        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);
            }
        }
Exemple #52
0
 public Task <RunbookEditor> CreateOrModify(ProjectResource project, string name, string description)
 {
     return(new RunbookEditor(this, new RunbookProcessRepository(Repository)).CreateOrModify(project, name, description));
 }
Exemple #53
0
        /// <summary>
        /// ProcessRecord
        /// </summary>
        protected override void ProcessRecord()
        {
            _oldProject = _octopus.Projects.FindByName(Name);

            if (_oldProject == null)
                throw new Exception(string.Format("Project '{0}' was not found.", Name));

            var group = _octopus.ProjectGroups.FindByName(ProjectGroup);

            if (group == null)
                throw new Exception(string.Format("Project Group '{0}' was not found.", ProjectGroup));

            CreateNewProject(group.Id);

            _oldProcess = _octopus.DeploymentProcesses.Get(_oldProject.DeploymentProcessId);
            _newProcess = _octopus.DeploymentProcesses.Get(_newProject.DeploymentProcessId);

            CopyProcess();
            CopyVariables();
        }
Exemple #54
0
 public Task <RunbookResource> FindByName(ProjectResource project, string name)
 {
     return(FindByName(name, path: project.Link("Runbooks")));
 }
 public static VariableCollection GetProjectVariables(this List<ResourceVariableSetPair> variableSets, ProjectResource project)
 {
     return GetProjectVariables(variableSets, project, null);
 }
        private static void ConfigureDynamics(IServiceCollection services, ProjectConfiguration project, ProjectResource projectResource, Serilog.ILogger logger)
        {
            Debug.Assert(services != null, "Required ServiceCollection is null");
            Debug.Assert(project != null, "Required ProjectConfiguration is null");
            Debug.Assert(projectResource != null, "Required ProjectResource is null");
            Debug.Assert(projectResource.Type == ProjectType.Dynamics, "Project type must be Dynamics");

            // the projectResourceKey convention is repeated also in OAuthClientFactory which gets the HttpClient using the same convention,
            //
            // {Id}-dynamics-authorization
            //
            string projectResourceKey = project.Id + "-dynamics";

            // add authorization HttpClient
            services.AddHttpClient(projectResourceKey + "-authorization", configure => configure.BaseAddress = projectResource.AuthorizationUri)
            ;

            // add odata HttpClient
            // note: I do not like this IoC anti-pattern where we are using the service locator directly, however,
            //       there are many named dependencies. There may be an opportunity to address this in the future

            var builder = services.AddHttpClient(projectResourceKey, configure =>
            {
                configure.BaseAddress = projectResource.Resource;
            })
                          .AddHttpMessageHandler(serviceProvider =>
            {
                // build the token service that talk to the OAuth endpoint
                IOAuthClientFactory oauthClientFactory = serviceProvider.GetRequiredService <IOAuthClientFactory>();
                IOAuthClient client = oauthClientFactory.Create(project);
                ITokenCache <OAuthOptions, Token> tokenCache = serviceProvider.GetRequiredService <ITokenCache <OAuthOptions, Token> >();

                ITokenService tokenService = new OAuthTokenService(client, tokenCache);
                var handler = new TokenAuthorizationHandler(tokenService, CreateOAuthOptions(projectResource));
                return(handler);
            });

            var apiGatewayHost   = projectResource.ApiGatewayHost;
            var apiGatewayPolicy = projectResource.ApiGatewayPolicy;

            if (!string.IsNullOrEmpty(apiGatewayHost) && !string.IsNullOrEmpty(apiGatewayPolicy))
            {
                // add the ApiGatewayHandler
                logger.Information("Using {@ApiGateway} for {Resource}", new { Host = apiGatewayHost, Policy = apiGatewayPolicy }, projectResource.Resource);
                builder.AddHttpMessageHandler(() => new ApiGatewayHandler(apiGatewayHost, apiGatewayPolicy));
            }
        }
Exemple #57
0
        IEnumerable <KeyValuePair <string, ChannelResource> > ImportProjectChannels(List <ChannelResource> channels, ProjectResource importedProject, IDictionary <string, LifecycleResource> channelLifecycles)
        {
            Log.Debug("Importing the channels for the project");
            var projectChannels       = Repository.Projects.GetChannels(importedProject).Items;
            var defaultChannel        = projectChannels.FirstOrDefault(c => c.IsDefault);
            var newDefaultChannel     = channels.FirstOrDefault(nc => nc.IsDefault);
            var defaultChannelUpdated = false;

            foreach (var channel in channels)
            {
                var existingChannel =
                    projectChannels.FirstOrDefault(c => c.Name.Equals(channel.Name, StringComparison.OrdinalIgnoreCase));

                if (existingChannel != null)
                {
                    Log.Debug("Channel already exists, channel will be updated with new settings");
                    existingChannel.Name        = channel.Name;
                    existingChannel.Description = channel.Description;
                    existingChannel.IsDefault   = channel.IsDefault;
                    if (channel.LifecycleId != null)
                    {
                        existingChannel.LifecycleId = channelLifecycles[channel.LifecycleId].Id;
                    }
                    if (existingChannel.IsDefault && !existingChannel.Name.Equals(newDefaultChannel?.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        existingChannel.IsDefault = false;
                    }
                    existingChannel.Rules.Clear();
                    existingChannel.Rules.AddRange(channel.Rules);
                    if (existingChannel.Name.Equals(defaultChannel?.Name))
                    {
                        defaultChannelUpdated = true;
                    }
                    yield return
                        (new KeyValuePair <string, ChannelResource>(channel.Id, Repository.Channels.Modify(existingChannel)));
                }
                else
                {
                    Log.Debug("Channel does not exist, a new channel will be created");
                    channel.ProjectId = importedProject.Id;
                    if (channel.LifecycleId != null)
                    {
                        channel.LifecycleId = channelLifecycles[channel.LifecycleId].Id;
                    }

                    yield return
                        (new KeyValuePair <string, ChannelResource>(channel.Id, Repository.Channels.Create(channel)));
                }
            }

            if (!KeepExistingProjectChannels && !defaultChannelUpdated)
            {
                Repository.Channels.Delete(defaultChannel);
            }
        }
Exemple #58
0
        public static void OctoImportVariables(this ICakeContext context,
                                               string octopusServerEndpoint,
                                               string octopusProjectName,
                                               string octopusApiKey,
                                               IEnumerable <OctoVariable> variables,
                                               bool clearAllNonSensitiveExistingVariables = false)
        {
            try
            {
                IOctopusAsyncClient client = new OctopusClientFactory().CreateAsyncClient(new OctopusServerEndpoint(octopusServerEndpoint, octopusApiKey)).Result;
                var octopus = new OctopusAsyncRepository(client);

                ProjectResource project = octopus.Projects.FindByName(octopusProjectName).Result;

                VariableSetResource variableSet = octopus.VariableSets.Get(project.Link("Variables")).Result;

                if (clearAllNonSensitiveExistingVariables)
                {
                    context.Log.Information($"Deleting all nonsensitive variables...");

                    List <VariableResource> sensitiveVariables = variableSet.Variables.Where(variable => variable.IsSensitive).ToList();

                    variableSet.Variables.Clear();

                    sensitiveVariables.ForEach(sensitiveVariable => { variableSet.Variables.Add(sensitiveVariable); });

                    context.Log.Information($"Deleting operation finished.");
                }

                foreach (OctoVariable variable in variables)
                {
                    var newVariable = new VariableResource
                    {
                        Name        = variable.Name,
                        Value       = variable.Value,
                        IsSensitive = variable.IsSensitive,
                        Type        = variable.IsSensitive ? VariableType.Sensitive : VariableType.String,
                        IsEditable  = variable.IsEditable,
                        Scope       = CreateScopeSpesification(variable, variableSet)
                    };

                    string scopeNames = CreateScopeInformationsForLogging(variable);

                    VariableResource existingVariable = variableSet.Variables.FirstOrDefault(x => x.Name == variable.Name && x.Scope.Equals(newVariable.Scope));
                    if (existingVariable != null)
                    {
                        context.Log.Information($"Variable: ({variable.Name}), Scopes:({scopeNames}) already exists in octopus, trying to update...");

                        variableSet.AddOrUpdateVariableValue(existingVariable.Name, newVariable.Value, newVariable.Scope, newVariable.IsSensitive);

                        context.Log.Information($"Variable: ({variable.Name}), Scopes:({scopeNames}) updated successfully...");
                    }
                    else
                    {
                        context.Log.Information($"New Variable: ({variable.Name}), Scopes:({scopeNames}) detected, trying to add...");

                        variableSet.Variables.Add(newVariable);

                        context.Log.Information($"New Variable: ({variable.Name}), Scopes:({scopeNames}) added successfully...");
                    }
                }

                octopus.VariableSets.Modify(variableSet).Wait();
                octopus.VariableSets.Refresh(variableSet).Wait();

                context.Log.Information($"Variables are all successfully set.");
            }
            catch (Exception exception)
            {
                throw new CakeException(exception.Message, exception.InnerException);
            }
        }
        public void WaitForDeploymentToComplete(List<TaskResource> deploymentTasks, List<DeploymentResource> deployments, ProjectResource project, ReleaseResource release)
        {
            if (showProgress && deploymentTasks.Count > 1)
            {
                Log.InfoFormat("Only progress of the first task ({0}) will be shown", deploymentTasks.First().Description);
            }

            try
            {
                Log.InfoFormat("Waiting for {0} deployment(s) to complete....", deploymentTasks.Count);
                Repository.Tasks.WaitForCompletion(deploymentTasks.ToArray(), DeploymentStatusCheckSleepCycle.Seconds, (int)DeploymentTimeout.TotalMinutes, PrintTaskOutput);
                var failed = false;
                foreach (var deploymentTask in deploymentTasks)
                {
                    var updated = Repository.Tasks.Get(deploymentTask.Id);
                    if (updated.FinishedSuccessfully)
                    {
                        Log.InfoFormat("{0}: {1}", updated.Description, updated.State);
                    }
                    else
                    {
                        Log.ErrorFormat("{0}: {1}, {2}", updated.Description, updated.State, updated.ErrorMessage);
                        failed = true;

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

                Log.Info("Done!");
            }
            catch (TimeoutException e)
            {
                Log.Error(e.Message);
                var guidedFailureDeployments =
                    from d in deployments
                    where d.UseGuidedFailure
                    select d;
                if (guidedFailureDeployments.Any())
                {
                    Log.Warn("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 = Repository.Environments.Get(guidedFailureDeployment.Link("Environment"));
                        Log.WarnFormat("  - {0}: {1}", environment.Name, GetPortalUrl(string.Format("/app#/projects/{0}/releases/{1}/deployments/{2}", project.Slug, release.Version, guidedFailureDeployment.Id)));
                    }
                }
                throw new CommandException(e.Message);
            }
        }
        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(),
                    VersionControlReference = new VersionControlReferenceResource
                    {
                        GitRef = GitReference
                    }
                }, ignoreChannelRules : IgnoreChannelRules)
                          .ConfigureAwait(false);

                commandOutputProvider.Information("Release {Version:l} created successfully!", release.Version);
                if (!string.IsNullOrEmpty(release.VersionControlReference?.GitCommit))
                {
                    commandOutputProvider.Information("Release created from commit {Commit:l} of git reference {GitRef:l}.", release.VersionControlReference.GitCommit, release.VersionControlReference.GitRef);
                }
                commandOutputProvider.ServiceMessage("setParameter", new { name = "octo.releaseNumber", value = release.Version });
                commandOutputProvider.TfsServiceMessage(ServerBaseUrl, project, release);

                await DeployRelease(project, release).ConfigureAwait(false);
            }
        }