In Octopus 2.4 we’ve added the ability for variables in one step to be available in another step. For example, you might have a standalone PowerShell step called StepA that does something like this:
Set-OctopusVariable -name "TestResult" -value "Passed"
You can then use it in a subsequent deployment step (in the same deployment) like this:
$TestResult = $OctopusParameters["Octopus.Action[StepA].Output.TestResult"]
Built-in output variables
After a step runs, Octopus captures the output variables, and keeps them for use in subsequent steps. In addition to variables that you create yourself using Set-OctopusVariable
, Octopus also makes a number of built-in variables available:
- For NuGet package steps:
Octopus.Action[StepName].Output.Package.InstallationDirectoryPath
: the path that the package was deployed to.
- For manual intervention steps:
Octopus.Action[StepName].Output.Manual.Notes
: notes entered in response to the manual step.Octopus.Action[StepName].Output.Manual.ResponsibleUser.Id
Octopus.Action[StepName].Output.Manual.ResponsibleUser.Username
Octopus.Action[StepName].Output.Manual.ResponsibleUser.DisplayName
Octopus.Action[StepName].Output.Manual.ResponsibleUser.EmailAddress
Scoping and indexing of output variables
It’s important to remember that, unlike a build server, Octopus runs steps across many machines in parallel. This means that each machine might produce a different value for the same output variable.
For example, imagine we have two machines, App01 and App02, and we run this script on both of them:
Set-OctopusVariable -name "MyMachineName" -value [System.Environment]::MachineName
Obviously, we’re going to have two different values available, since both machines have a different hostname. To handle this, Octopus creates the variables and scopes them to a machine. In this example, Octopus would store two variables:
Octopus.Action[StepA].Output.MyMachineName = App01 (Scope: App01) # Value from App01 machine
Octopus.Action[StepA].Output.MyMachineName = App02 (Scope: App02) # Value from App02 machine
From now on, any step in the deployment that runs on either of these machines will get the applicable output variable from that machine. This means you can do:
$name = $OctopusParameters["Octopus.Action[StepA].Output.MyMachineName"]
Sometimes you might need to access variables from one machine that are produced by a different machine. For this situation, Octopus also stores non-scoped variables that are instead indexed by the machine:
Octopus.Action[StepA].Output[App01].MyMachineName = App01 # Value from App01 machine
Octopus.Action[StepA].Output[App02].MyMachineName = App02 # Value from App02 machine
This means that in a subsequent step running on App03 for example, you could do:
$app01Name = $OctopusParameters["Octopus.Action[StepA].Output[App01].MyMachineName"]
$app02Name = $OctopusParameters["Octopus.Action[StepA].Output[App02].MyMachineName"]
# Do something with $app01Name and $app02Name
Keep in mind that $OctopusParameters
is a just a Dictionary<string,string>
. This means you can do things like this:
$MatchRegex = "Octopus\.Action\[StepA\]\.Output\[(.*?)\]\.MyMachineName"
Write-Host "Machine names:"
$OctopusParameters.GetEnumerator() | Where-Object { $_.Key -match $MatchRegex } | % {
Write-Host "$_.Value"
}
Here, we’re iterating all the key/value pairs in the dictionary, and finding the ones that match our regex, which has a wildcard on the machine name component of the variable key.
Finding where a previous package was installed
This is such a common use-case for output variables that I want to call it out explicitly.
By default, to avoid various issues around broken deployments and file locks, Tentacles automatically extracts packages to a new, clean directory. If you deploy the exact same package multiple times, you’ll end up with something like:
C:\Octopus\Applications\Production\MyApp\1.0.0
C:\Octopus\Applications\Production\MyApp\1.0.0_1
C:\Octopus\Applications\Production\MyApp\1.0.0_2
C:\Octopus\Applications\Production\MyApp\1.0.0_3
Suppose you deploy a NuGet package, but then want to write a standalone PowerShell script that runs on the same server in the directory the package was extracted to, but isn’t part of the NuGet package. You can use this:
$packageDir = $OctopusParameters["Octopus.Action[MyApp].Output.Package.InstallationDirectoryPath"]
cd $packageDir
# Do your custom logic
Summary
Application deployments often involve running deploying packages and executing code on many different machines. Output variables in Octopus provide a very powerful way to share these values between different steps, and different machines. I hope you’ll find this feature useful!
Learn more
- Documentation: Custom Scripts
- Documentation: Octopus Variables
- Redesigning the variable editor from the ground upfor a better overall user experience