As a part of supporting Docker deployments we realised that we needed a way to access the JSON formatted information that is returned as the output of a container inspection. Rather than recursively walk through the JSON object and convert all the properties into Octopus variables after running a Docker step, just in case some subsequent step needed it, we decided it might be useful to update Octostache (our variable substitution library) to support parsing JSON when the variable is required. While getting our hands dirty in our variable parsing library, we figured it might be a good excuse to add a few other useful features to 3.5!
JSON Parsing
If you set a project or output variable to a JSON value, for example:
Variables:
Custom.Json = "{Name: 't-shirt', Sizes: [{size: 'small', price: 15.00}, {size: 'large', price: 20.00}]}"
Expressions:
#{Custom.Json.Name}
#{Custom.Json.Sizes[0].price}
#{Custom.Json.Sizes[1]}
Resolves to:
"t-shirt"
"15.00"
"{size: "large", price: 20.00}"
Note that if you have explicitly supplied a variable that matches a value that would resolve to a JSON path, for example if you explicitly set a project variable
Custom.Json.Name = "pants"
then the explicit variable pants
will be returned instead. This new parsing supports either the dot-notation as shown above or index notation, so that #{Custom.Json.[Sizes][0][price]}
also resolves to '15.00'
. This last point brings me to the next update...
Index Replacement
Not long ago we added support to perform variable substitution inside an index.
Variables:
Server[Asia] = "Beijing"
Server[Europe] = "London"
Continent = "Asia"
Expression:
#{Server[#{Continent}]}
Resolves To:
"Beijing"
You can now resolve the appropriate Server
variable dynamically as a result of a variable replacement itself. Incidentally it also comes in handy for the Docker steps, whereby you may want to access a variable from the container JSON output indexed by some property output from another step that can only be known at deployment time.
Conditionals
Up until recently, Conditional statements in variable substitution required a Truthy comparison. That is to say, they would only resolve the conditional as true
if the variable had a value like "True"
. This is no longer the case, and comparisons can now check for either direct string equality or using an inner variable replacement.
Variables:
City = "London"
Capital = "London"
Expressions:
#{if City == "London"}'Ello Guvna#{/if}
#{if City != "Paris"}'Ello Guvna#{/if}
#{if City == Capital}'Ello Guvna#{/if}
Resolve To:
'Ello Guvna
'Ello Guvna
'Ello Guvna
Formatting
An issue that some of our users have faced is that when we save dates in project variables to the database, the serializer converts them into a different format. We have introduced a new built-in Octostache function that allows you to format dates or number variables, into any of the custom formats supported by .NET. This new format function takes the form of
#{<VariableName> | Format <DataType> <Format>}
Where the <DataType>
can be one of "DateTime", "DateTimeOffset", "Double", "Decimal" or "Int" (case insensitive). Octostache will then try to parse the variable resolved at <VariableName>
to the specified type, and then cast back to a string with the C# .ToString()
method, passing in the <Format>
argument provided.
Variables:
Cash = "12.1"
MyDate = "2030/05/22 09:05:00"
CustomFormat = "MMM dd, yyyy"
Expressions:
#{Cash | Format double C}
#{MyDate | Format DateTime \"HH dd-MM-yyyy\"}
#{MyDate | Format DateTime #{CustomFormat}}
Resolve To:
$12.1
09 22-May-2030
May 22, 2030
Note that the formatting will use the current culture of the machine where the conversion is taking place. Also since these arguments are space delimited, if your format includes a space, as with the date format above, you will need to include enclosing quotes. If the <DataType>
argument is missing the formatter will first attempt to parse the variable as a decimal, and then a DateTimeOffset.
Along with a new NowDate
and NowDateUtc
function (that takes no variable input), you can also get the current timestamp and chain it together with the formatting function.
Expression:
#{ | NowDate | Format yyyy}
Resolves to
"2016"
Conclusion
We hope that you will find some of these new variable substitution features useful. Octostache, our variable substitution library is open source and available on GitHub already, so feel free to take a look and contribute your own enhancement suggestions or learn more about using these new expressions in your deployments from our online docs. These additions available from Octopus 3.5 allow for much richer and complex relationship between variables and scopes. Let us know how how they might (or might not) come in handy for your deployments!