DevOps

Octopus Project Builder

In my last post I wrote about my plans to create the Octopus Project Builder, a tool allowing to configure Octopus Deploy projects from yaml files, like Jenkins Job Builder does for Jenkins.

Since last month, I managed to progress with this work and I would like to share the outcome.

The Octopus Project Builder allows to configure:

  • Project Groups,
  • Projects,
  • Lifecycles,
  • Library Variable Sets (including Script Modules).

As I mentioned previously, the Project definitions can be very verbose, especially in the deployment actions section, that is why OPB allows also to define templates for Projects, Deployment Steps as well as Deployment Step Actions. The templates can be parameterized as well as it is possible to override template values when template is used in resource definition.

So how does it look like?
Below there are example yaml files with sample configuration.

---
ProjectGroups:
- Name: Toolset
  Description: Generated. Please do not update manually
...
---
Lifecycles:
- Name: Toolset
  Description: Generated. Please do not update manually
  TentacleRetentionPolicy:
    QuantityToKeep: 1
    Unit: Items
  ReleaseRetentionPolicy: {}
...
---
LibraryVariableSets:
- Name: Toolset Variables
  Description: Generated. Please do not update manually.
  Variables:
  - Name: Toolset_installation_directory
    Value: c:\tools\
...
---
Projects:
- Name: OpenCover
  UseTemplate:
    Name: InstallTool
    Arguments:
      PackageName: OpenCover
      TargetRoles: build_agent
...

The Project Builder, Lifecycle and Library Variable Set definitions are self explanatory.

The Project definition yaml is very simplistic however. It is because it uses the parameterized template to install the nuget package on target boxes.

So how does the template look?

---
Templates:

  Projects:

  - TemplateName: InstallTool
    TemplateParameters:
    - PackageName
    - TargetRoles
    Description: Generated. Please do not update manually.
    LifecycleRef: Toolset
    ProjectGroupRef: Toolset
    IncludedLibraryVariableSetRefs:
    - Toolset Variables
    DeploymentProcess:
      Steps:
      - Name: ${PackageName}
        Actions:
        - Name: Install ${PackageName}
          UseTemplate:
            Name: InstallNugetPackage
            Arguments:
              PackageName: ${PackageName}
              InstallationDirectory: '#{Toolset_installation_directory}'
        Properties:
        - Key: Octopus.Action.TargetRoles
          Value: ${TargetRoles}


  DeploymentActions:

  - TemplateName: InstallNugetPackage
    TemplateParameters:
    - PackageName
    - InstallationDirectory
    ActionType: Octopus.TentaclePackage
    Properties:
    - Key: Octopus.Action.EnabledFeatures
      Value: Octopus.Features.CustomDirectory
    - Key: Octopus.Action.Package.DownloadOnTentacle
      Value: False
    - Key: Octopus.Action.Package.NuGetFeedId
      Value: feeds-nuget
    - Key: Octopus.Action.Package.NuGetPackageId
      Value: ${PackageName}
    - Key: Octopus.Action.Package.CustomInstallationDirectory
      Value: ${InstallationDirectory}\\${PackageName}
    - Key: Octopus.Action.Package.CustomInstallationDirectoryShouldBePurgedBeforeDeployment
      Value: True
...

The project template has specified the most common properties (so it is not needed to define them in each project). It has defined two template parameters as well, one to specify the package name to be installed and the other to specify on what machines the package will be installed. Further in the template definition, the template parameters are used with ${param_name} syntax. The template itself is also using an another template to define the deployment step action. This example shows that template parameters can be passed further to the inner templates.
Finally the deployment action definitions shows escaping sequences.
Normally, any existence of ${param_name} would be treated as the template parameter usage. If this behavior is not desired, then $ symbol has to be escaped with \. However in this example we want to compose the Octopus.Action.Package.CustomInstallationDirectory from installation directory and package name, that is why there is \\ that represents directory symbol.

Yaml configuration description

The yaml configuration offers much more options than ones presented in the example. The OctopusProjectBuilder project home page contains a configuration manual describing the full configuration model.

Finally, a nuget package is available as well: OctopusProjectBuilder.Console

Feel free to take a look at it and give it a go.
Also, any feedback is welcome.

Have fun!