How can I deploy different packages per environment in Octopus Deploy?

When a release is created in Octopus Deploy it snapshots the process, the variables, and the package versions. That same release works its way through the various environments, Development -> Testing -> Staging -> Production.

However, when leveraging a branching strategy such as GitFlow, I want to be able to push my feature branches up to Dev only. Any builds from the development branch up to Testing, and any builds from a release branch up to Staging -> Production. That seems to run counter to how Octopus Deploy operates, is that possible?

Yes, it is possible to accomplish that in Octopus Deploy leveraging lifecycles, channels, and channel version rules.

To solve the scenario in the above question, we will need to create multiple lifecycles.

  • FeatureBranch: Development Environment Only
  • QA: Testing Environment Only
  • Release: Staging -> Production

After the lifecycles have been created then we can move onto the projects. In the project, create three different channels.

Typically we see users add pre-release tags onto their packages. IE OctoFx.2.1.0.1-Development.zip.

That, in turn, leads to the following rules:

  • Packages without pre-release tags can only be deployed to Production.
  • Packages with the development pre-release tag can only be deployed to Testing.
  • Packages with any other pre-release tag can only be deployed to Dev.

Octopus can help enforce those rules by using a version rule on the channel.

The Design Rule interface will allow you to test out the rule to ensure it meets your specific needs. You can edit/add/remove examples from the sample versions section.

Another nice thing about channels is variables can be bound to them.

Along with steps in the process.

This does mean the build server needs to have a little bit of smarts. When it sees a build come from a specific feature branch it will need to tell Octopus to create the release for a specific channel. At the top of the build a small script will need to be added.

Param(    
    [string]$currentBranch,
    [string]$buildNumber,
    [string]$defaultMajorVersion,
    [string]$featureBranchVersion
)

Write-Host "BuildNumber: $buildNumber"
Write-Host "DefaultMajorVersion: $defaultMajorVersion"
Write-Host "FeatureBranchVersion: $featureBranchVersion"

$channelName = "Default"
$releaseVersion = "$defaultMajorVersion.$buildNumber"

Write-Host "This is the branch that is building: $currentBranch"

if ($currentBranch -ne "refs/heads/master"){
    Write-Host "Non-master branch detected, using feature branches instead"
    $channelName = "Feature Branch Channel"
    $replacementBranchName = $currentBranch.replace("refs/heads/", "").replace(" ", "")
    $releaseVersion = "$featureBranchVersion.$buildNumber-$replacementBranchName"
}

Most build servers allow you to set output variables from script steps.

Azure DevOps/TFS

Write-Host "##vso[task.setvariable variable=octopusChannel;issecret=true]$channelName"
Write-Host "##vso[task.setvariable variable=octopusVersion;issecret=true]$releaseVersion"

TeamCity

"##teamcity[setParameter name='env.octopusChannel' value='$channelName']"
"##teamcity[setParameter name='env.octopusVersion' value='$releaseVersion']"

In the package creation step the version number will need to be supplied from that script.

In the create release step the version number and channel name will need to be supplied from that script.

When manually creating the release in the Octopus UI you would need to select the channel. The channel cannot be change on a release after it has been created.