diff --git a/src/pages/docs/projects/variables/variable-substitutions.mdx b/src/pages/docs/projects/variables/variable-substitutions.mdx index b8a3bd1279..2864be5b38 100644 --- a/src/pages/docs/projects/variables/variable-substitutions.mdx +++ b/src/pages/docs/projects/variables/variable-substitutions.mdx @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2024-08-29 +modDate: 2026-02-17 title: Variable substitutions icon: fa-solid fa-underline description: Variable substitutions are a flexible way to adjust configuration based on your variables and the context of your deployment. @@ -15,12 +15,12 @@ Variable substitutions are a flexible way to adjust configuration based on your You can use Octopus's special binding syntax to reference a variable from within the value of another variable. This is sometimes referred to as using **Composite variables**, because you compose a variable value with other Octopus variables. In the following example, the `ConnectionString` variable references the variables `{Server}` and `{Database}`. -| Name | Value | Scope | -| ------------------ | --------------------------- | ----------- | -| Server | SQL | Production, Test | -| Database | PDB001 | Production | -| Database | TDB001 | Test | -| ConnectionString | Server=#\{Server\}; Database=#\{Database\} | | +| Name | Value | Scope | +| ------------------ | ---------------------------------------------- | ----------------- | +| Server | SQL | Production, Test | +| Database | PDB001 | Production | +| Database | TDB001 | Test | +| ConnectionString | Server=#\{Server\}; Database=#\{Database\} | | In regular variable declarations, binding to a non-existent value will yield an empty string, so evaluating `ConnectionString` in the *Dev* environment will yield `Server=;` because no `Database` or `Server` are defined for that environment. @@ -30,6 +30,14 @@ If the file undergoing variable replacement includes a string that *shouldn't* b | --------------------- | -------------------- | | `##{NotToBeReplaced}` | `#{NotToBeReplaced}` | +Variable substitution within a hash-delimited string looks like the following. Given the variable: + +| Name | Value | +| -------- | ------- | +| `Name` | `title` | + +`###{Name}` would evaluate to `#title`. + :::div{.info} Also read about [common mistakes for variables](/docs/projects/variables/sensitive-variables/#avoiding-common-mistakes) for more information @@ -42,13 +50,13 @@ Binding syntax can be used to dynamically change the values of deployment step s Most text fields that support binding to variables will have a variable insert button: :::figure -![](/docs/img/projects/variables/images/3278296.png) +![Variable insert button on text fields that support variable binding](/docs/img/projects/variables/images/3278296.png) ::: For settings that support variables but aren't text (such as drop downs or check-boxes), a button is displayed to toggle custom expression modes: :::figure -![](/docs/img/projects/variables/images/3278297.png) +![Toggling custom expression modes for settings that support variables but aren't text](/docs/img/projects/variables/images/3278297.png) ::: ## Extended syntax \{#extended-syntax} @@ -96,7 +104,7 @@ Basic mathematical calculations are supported in Octopus using the `calc` statem :::div{.warning} When using a variable on the left-hand-side of a divide (`/`) or subtraction (`-`) operation, the variable name must be enclosed in braces (`{ ... }`) to ensure correct parsing, this ensures the operator symbol is recognized -as an operation, rather than part of the variable name. +as an operation, rather than part of the variable name. ::: Given the variables: @@ -112,7 +120,7 @@ Given the variables: - `192.168.0.#{calc IPOffset[Primary] + 1}` would evaluate to `192.168.0.1` - `192.168.0.#{calc IPOffset[Secondary] + 1}` would evaluate to `192.168.0.181` - `#{calc 22 * ScaleFactor}` would evaluate to `264` -- `#{each i in Numbers}#{calc i + 5}#{/each}` would evaluate to `15 25 35 45 55 ` +- `#{each i in Numbers}#{calc i + 5}#{/each}` would evaluate to `15 25 35 45 55` - `#{calc {My/Var} / 3}` would evaluate to `5` - `#{calc 2 * My/Var}` would evaluate to `30` - `#{calc {My/Var} - 4}` would evaluate to `11` @@ -176,7 +184,7 @@ Additional conditional statements are supported, including `==` and `!=`. Using complex syntax you can have expressions like `#{if Octopus.Environment.Name == "Production"}...#{/if}` and `#{if Octopus.Environment.Name != "Production"}...#{/if}`, or: -``` +```text #{if ATruthyVariable} Do this if ATruthyVariable evaluates to true #{else} @@ -184,11 +192,11 @@ Using complex syntax you can have expressions like `#{if Octopus.Environment.Nam #{/if} ``` -**OR Conditions** +#### OR Conditions It's common to want to check for more than one value in an Octopus variable. To achieve this, you can create an effective `OR` statement by combining an `if` with another `else` statement: -``` +```text #{if Octopus.Environment.Name == "Development"} Do this if it's Development #{else} @@ -202,37 +210,37 @@ It's common to want to check for more than one value in an Octopus variable. To This is the equivalent of checking the Environment name for Development or Test. -**Comparing one variable value with another** +### Comparing one variable value with another -Sometimes, you might want to compare one variable value with another. +Sometimes, you might want to compare one variable value with another. Given the variables: -| Name | Value | Scope | -| ----------- | ---------------------------------------- | ----- | -| `Base.MaxLogLevel` | `ERROR` | | -| `Environment.LogLevel` | `DEBUG` | `Dev` | -| `Environment.LogLevel` | `INFO` | `Test` | -| `Environment.LogLevel` | `ERROR` | `Staging` | -| `Environment.LogLevel` | `ERROR` | `Production` | +| Name | Value | Scope | +|-----------------------|----------|-------------| +| `Base.MaxLogLevel` | `ERROR` | | +| `Environment.LogLevel`| `DEBUG` | `Dev` | +| `Environment.LogLevel`| `INFO` | `Test` | +| `Environment.LogLevel`| `ERROR` | `Staging` | +| `Environment.LogLevel`| `ERROR` | `Production`| Using conditional syntax, you can compare the value in the `Base.MaxLogLevel` variable with the `Environment.LogLevel` variable value. Using the template: -``` +```text #{if Environment.LogLevel == Base.MaxLogLevel}We are at the MAX!#{else}We have room to grow!#{/if} ``` -The resulting text in both _Dev and Test_ will be: +The resulting text in both *Dev and Test* will be: -``` +```text We have room to grow! ``` -And in both _Staging and Production_ it will be: +And in both *Staging and Production* it will be: -``` +```text We are at the MAX! ``` @@ -286,20 +294,20 @@ Listening on: #### Complex syntax with sets of values -Sometimes, you might want to compare one variable value with another contained in a set of values. +Sometimes, you might want to compare one variable value with another contained in a set of values. Given the variables: -| Name | Value | -| ----------- | ---------------------------------------- | -| `WidgetIdSelector` | `Widget-2` | -| `MyWidgets` | `{"One":{"WidgetId":"Widget-1","Name":"Widget-One"},"Two":{"WidgetId":"Widget-2","Name":"Widget-Two"}}` | +| Name | Value | +|--------------------|---------------------------------------------------------------------------------------------------------| +| `WidgetIdSelector` | `Widget-2` | +| `MyWidgets` | `{"One":{"WidgetId":"Widget-1","Name":"Widget-One"},"Two":{"WidgetId":"Widget-2","Name":"Widget-Two"}}` | Using complex syntax, you can iterate over the values in the `MyWidgets` variable and find the entry with the value specified in the second variable `WidgetIdSelector`. Using the template: -``` +```text #{each w in MyWidgets} '#{w.Value.WidgetId}': #{if w.Value.WidgetId == WidgetIdSelector}This is my Widget!#{else}No widget matched :(#{/if} #{/each} @@ -307,24 +315,26 @@ Using the template: The resulting text will be: -``` +```text 'Widget-1': No widget matched :( 'Widget-2': This is my Widget! ``` :::div{.hint} **Tips:** + - Note both operands **don't** include the Octostache syntax denoting them as a variable e.g. `#{WidgetIdSelector}`. This is because within a conditional expression Octostache is already able to evaluate the operands as variable values. - The template references `.Value` which is a property available when using [JSON repetition](/docs/projects/variables/variable-filters/#repetition-over-json). + ::: #### Iterating over comma-separated values Given the variable: -| Name | Value | Scope | -| ----------- | ---------------------------------------- | ----- | -| `Endpoints` | `http://a.example.com,http://b.example.com` | | +| Name | Value | Scope | +| ----------- | --------------------------------------------- | ----- | +| `Endpoints` | `http://a.example.com,http://b.example.com` | | And the template: @@ -347,17 +357,17 @@ Listening on: Within the context of an iteration template, some special variables are available. -| Name | Description | -| ----------------------------- | ---------------------------------------- | -| `Octopus.Template.Each.Index` | Zero-based index of the iteration count | +| Name | Description | +| ----------------------------- | ------------------------------------------------------------------------- | +| `Octopus.Template.Each.Index` | Zero-based index of the iteration count | | `Octopus.Template.Each.First` | `"True" if the element is the first in the collection`, otherwise "False" | -| `Octopus.Template.Each.Last` | "True" if the element is the last in the collection, otherwise "False" | +| `Octopus.Template.Each.Last` | "True" if the element is the last in the collection, otherwise "False" | Given the variable created as an index (comma separated): | Name | Value | | ----------- | ---------------------------------------- | -| `Endpoints` | `SV1,SV2,SV3` | +| `Endpoints` | `SV1,SV2,SV3` | And the template: @@ -418,6 +428,7 @@ The filters can be invoked in the following way: For more information, see [Variable Filters](/docs/projects/variables/variable-filters). ## Older versions + The `calc` operator is available from Octopus Deploy **2023.2** onwards. ## Learn more