public void ShouldCreateReleaseTemplateResourceFromCreatorConfig()
        {
            // arrange
            ReleaseTemplateCreator releaseTemplateCreator = new ReleaseTemplateCreator();
            CreatorConfig          creatorConfig          = new CreatorConfig()
            {
                apis = new List <APIConfig>()
            };
            APIConfig api = new APIConfig()
            {
                name                 = "name",
                apiRevision          = "2",
                isCurrent            = true,
                suffix               = "suffix",
                subscriptionRequired = true,
                openApiSpec          = "https://petstore.swagger.io/v2/swagger.json",
            };

            creatorConfig.apis.Add(api);

            // act
            string[] dependsOn = new string[] { "dependsOn" };
            ReleaseTemplateResource releaseTemplateResource = releaseTemplateCreator.CreateAPIReleaseTemplateResource(api, dependsOn);

            // assert
            string releaseName = $"";

            Assert.Equal($"[concat(parameters('apimServiceName'), '/{api.name}/release-revision-{api.apiRevision}')]", releaseTemplateResource.name);
            Assert.Equal(dependsOn, releaseTemplateResource.dependsOn);
            Assert.Equal($"Release created to make revision {api.apiRevision} current.", releaseTemplateResource.properties.notes);
            Assert.Equal($"[resourceId('Microsoft.ApiManagement/service/apis', parameters('apimServiceName'), '{api.name}')]", releaseTemplateResource.properties.apiId);
        }
Example #2
0
        public ReleasePlan(ProjectResource project, ChannelResource channel, ReleaseTemplateResource releaseTemplate, DeploymentProcessResource deploymentProcess, IPackageVersionResolver versionResolver)
        {
            Project         = project;
            Channel         = channel;
            ReleaseTemplate = releaseTemplate;
            scriptSteps     = deploymentProcess.Steps
                              .SelectMany(s => s.Actions)

                              .Select(a => new
            {
                StepName  = a.Name,
                PackageId = a.Properties.ContainsKey("Octopus.Action.Package.PackageId")
                        ? a.Properties["Octopus.Action.Package.PackageId"].Value
                        : string.Empty,
                FeedId = a.Properties.ContainsKey("Octopus.Action.Package.FeedId")
                        ? a.Properties["Octopus.Action.Package.FeedId"].Value
                        : string.Empty,
                a.IsDisabled,
                a.Channels,
            })
                              .Where(x => string.IsNullOrEmpty(x.PackageId) && x.IsDisabled == false) // only consider enabled script steps
                              .Where(a => !a.Channels.Any() || a.Channels.Contains(channel.Id))       // only include actions without channel scope or with a matchign channel scope
                              .Select(x =>
                                      new ReleasePlanItem(x.StepName, null, null, true, null)
            {
                IsDisabled = x.IsDisabled
            }).ToArray();
            packageSteps = releaseTemplate.Packages.Select(
                p => new ReleasePlanItem(
                    p.StepName,
                    p.PackageId,
                    p.FeedId,
                    p.IsResolvable,
                    versionResolver.ResolveVersion(p.StepName, p.PackageId))).ToArray();
        }
Example #3
0
 public ReleasePlan(ReleaseTemplateResource releaseTemplate, IPackageVersionResolver versionResolver)
 {
     steps.AddRange(
         releaseTemplate.Packages.Select(p => new ReleasePlanItem(
                                             p.StepName,
                                             p.NuGetPackageId,
                                             p.NuGetFeedId,
                                             p.IsResolvable,
                                             versionResolver.ResolveVersion(p.StepName) ?? versionResolver.ResolveVersion(p.NuGetPackageId)
                                             ))
         );
 }
 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, p.PackageId)))
                       .ToArray();
 }
Example #5
0
        public List <TemplateResource> CreateChildResourceTemplates(APIConfig api)
        {
            List <TemplateResource> resources = new List <TemplateResource>();

            // all child resources will depend on the api
            string[] dependsOn = new string[] { $"[resourceId('Microsoft.ApiManagement/service/apis', parameters('{ParameterNames.ApimServiceName}'), '{api.name}')]" };

            PolicyTemplateResource apiPolicyResource = api.policy != null?this.policyTemplateCreator.CreateAPIPolicyTemplateResource(api, dependsOn) : null;

            List <PolicyTemplateResource> operationPolicyResources = api.operations != null?this.policyTemplateCreator.CreateOperationPolicyTemplateResources(api, dependsOn) : null;

            List <ProductAPITemplateResource> productAPIResources = api.products != null?this.productAPITemplateCreator.CreateProductAPITemplateResources(api, dependsOn) : null;

            List <TagAPITemplateResource> tagAPIResources = api.tags != null?this.tagAPITemplateCreator.CreateTagAPITemplateResources(api, dependsOn) : null;

            DiagnosticTemplateResource diagnosticTemplateResource = api.diagnostic != null?this.diagnosticTemplateCreator.CreateAPIDiagnosticTemplateResource(api, dependsOn) : null;

            // add release resource if the name has been appended with ;rev{revisionNumber}
            ReleaseTemplateResource releaseTemplateResource = api.name.Contains(";rev") == true?this.releaseTemplateCreator.CreateAPIReleaseTemplateResource(api, dependsOn) : null;

            // add resources if not null
            if (apiPolicyResource != null)
            {
                resources.Add(apiPolicyResource);
            }
            if (operationPolicyResources != null)
            {
                resources.AddRange(operationPolicyResources);
            }
            if (productAPIResources != null)
            {
                resources.AddRange(productAPIResources);
            }
            if (tagAPIResources != null)
            {
                resources.AddRange(tagAPIResources);
            }
            if (diagnosticTemplateResource != null)
            {
                resources.Add(diagnosticTemplateResource);
            }
            if (releaseTemplateResource != null)
            {
                resources.Add(releaseTemplateResource);
            }

            return(resources);
        }
        public ReleaseTemplateResource CreateAPIReleaseTemplateResource(ApiDeploymentDefinition api, string[] dependsOn)
        {
            string releaseName = $"release-revision-{api.ApiRevision}";
            // create release resource with properties
            ReleaseTemplateResource releaseTemplateResource = new ReleaseTemplateResource()
            {
                Name       = $"[concat(parameters('ApimServiceName'), '/{api.Name}/{releaseName}')]",
                Properties = new ReleaseTemplateProperties()
                {
                    Notes = $"Release created to make revision {api.ApiRevision} current.",
                    ApiId = $"[resourceId('{ResourceType.Api}', parameters('ApimServiceName'), '{api.Name}')]"
                },
                DependsOn = dependsOn
            };

            return(releaseTemplateResource);
        }
Example #7
0
        public ReleaseTemplateResource CreateAPIReleaseTemplateResource(APIConfig api, string[] dependsOn)
        {
            string releaseName = $"release-revision-{api.apiRevision}";
            // create release resource with properties
            ReleaseTemplateResource releaseTemplateResource = new ReleaseTemplateResource()
            {
                Name       = $"[concat(parameters('{ParameterNames.ApimServiceName}'), '/{api.name}/{releaseName}')]",
                Type       = ResourceTypeConstants.APIRelease,
                ApiVersion = GlobalConstants.ApiVersion,
                Properties = new ReleaseTemplateProperties()
                {
                    notes = $"Release created to make revision {api.apiRevision} current.",
                    apiId = $"[resourceId('Microsoft.ApiManagement/service/apis', parameters('{ParameterNames.ApimServiceName}'), '{api.name}')]"
                },
                DependsOn = dependsOn
            };

            return(releaseTemplateResource);
        }
Example #8
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
            {
                Links = new LinkCollection {
                    { "SearchTemplate", TestHelpers.GetId("searchUri") }
                }
            };

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

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

            releaseRepository = Substitute.For <IReleaseRepository>();
            feedRepository    = Substitute.For <IFeedRepository>();
            feedRepository.Get(Arg.Any <string>()).Returns(feedResource);

            repository = Substitute.For <IOctopusAsyncRepository>();
            repository.DeploymentProcesses.Returns(deploymentProcessRepository);
            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);
        }
        static void Main(string[] args)
        {
            var apiKey              = "API-XXXXXXXXXXXXXXXXXXXXXXXXXX";
            var octopusURL          = "https://octopus.url";
            var projectName         = "testproject2";
            var releaseVersion      = "";
            var channelName         = "Default";
            var environmentName     = "Dev";
            var fixedPackageVersion = "";

            var endpoint   = new OctopusServerEndpoint(octopusURL, apiKey);
            var repository = new OctopusRepository(endpoint);

            var project     = repository.Projects.FindByName(projectName);
            var environment = repository.Environments.FindByName(environmentName);

            var template = new ReleaseTemplateResource();
            var process  = new DeploymentProcessResource();

            process = repository.DeploymentProcesses.Get(project.DeploymentProcessId);
            var channel = repository.Channels.FindByName(project, channelName);

            template = repository.DeploymentProcesses.GetTemplate(process, channel);

            //if you dont pass a value to newReleaseVersion, It'll calculate it using the version template of your project. Just like when you hit the "Create Release" button from the web portal
            if (string.IsNullOrEmpty(releaseVersion))
            {
                releaseVersion = template.NextVersionIncrement;
            }

            //Creating the release object
            var newrelease = new ReleaseResource
            {
                ProjectId = project.Id,
                Version   = releaseVersion
            };

            foreach (var package in template.Packages)
            {
                var selectedPackage = new SelectedPackage
                {
                    ActionName           = package.ActionName,
                    PackageReferenceName = package.PackageReferenceName
                };

                //If you don't pass a value to FixedPackageVersion, Octopus will look for the latest one in the feed.
                if (string.IsNullOrEmpty(fixedPackageVersion))
                {
                    //Gettin the latest version of the package available in the feed.
                    //This is probably the most complicated line. The expression can get tricky, as a step(action) might be a parent and have many children(more nested actions)
                    var packageStep =
                        process.Steps.FirstOrDefault(s => s.Actions.Any(a => a.Name == selectedPackage.ActionName))?
                        .Actions.FirstOrDefault(a => a.Name == selectedPackage.ActionName);

                    var packageId = packageStep.Properties["Octopus.Action.Package.PackageId"].Value;
                    var feedId    = packageStep.Properties["Octopus.Action.Package.FeedId"].Value;

                    var feed = repository.Feeds.Get(feedId);

                    var latestPackageVersion = repository.Feeds.GetVersions(feed, new[] { packageId }).FirstOrDefault();

                    selectedPackage.Version = latestPackageVersion.Version;
                }
                else
                {
                    selectedPackage.Version = fixedPackageVersion;
                }

                newrelease.SelectedPackages.Add(selectedPackage);
            }

            //Creating the release in Octopus
            var release = repository.Releases.Create(newrelease);

            //creating the deployment object
            var deployment = new DeploymentResource
            {
                ReleaseId     = release.Id,
                ProjectId     = project.Id,
                EnvironmentId = environment.Id
            };

            //Deploying the release in Octopus
            repository.Deployments.Create(deployment);
        }
        private async Task <ReleasePlan> Build(IOctopusAsyncRepository repository, ProjectResource project, ChannelResource channel,
                                               string versionPreReleaseTag, ReleaseTemplateResource releaseTemplate, DeploymentProcessResource deploymentProcess)
        {
            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...");

                var allRelevantFeeds = await LoadFeedsForSteps(repository, project, plan.UnresolvedSteps);

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

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

                    if (!allRelevantFeeds.TryGetValue(unresolved.PackageFeedId, out var feed))
                    {
                        throw new CommandException(string.Format(
                                                       "Could not find a feed with ID {0}, which is used by step: " + unresolved.ActionName,
                                                       unresolved.PackageFeedId));
                    }

                    var filters = BuildChannelVersionFilters(unresolved.ActionName, unresolved.PackageReferenceName, 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)
                    {
                        commandOutputProvider.Error(
                            "Could not find any packages with ID '{PackageId:l}' in the feed '{FeedUri:l}'",
                            unresolved.PackageId, feed.Name);
                    }
                    else
                    {
                        commandOutputProvider.Debug("Selected '{PackageId:l}' version '{Version:l}' for '{StepName:l}'",
                                                    latestPackage.PackageId, latestPackage.Version, unresolved.ActionName);
                        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.ActionPackages.Any(pkg =>
                                                                                       pkg.DeploymentActionNameMatches(step.ActionName) &&
                                                                                       pkg.PackageReferenceNameMatches(step.PackageReferenceName)));
                    var result = await versionRuleTester.Test(repository, rule, step.Version, step.PackageFeedId).ConfigureAwait(false);

                    step.SetChannelVersionRuleTestResult(result);
                }
            }

            return(plan);
        }
        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;
        }