|
| 1 | +--- |
| 2 | +applyTo: ".pipelines/**/*.{yml,yaml}" |
| 3 | +--- |
| 4 | + |
| 5 | +# OneBranch Pipeline Condition Syntax |
| 6 | + |
| 7 | +## Overview |
| 8 | +Azure Pipelines (OneBranch) uses specific syntax for referencing variables and parameters in condition expressions. Using the wrong syntax will cause conditions to fail silently or behave unexpectedly. |
| 9 | + |
| 10 | +## Variable Reference Patterns |
| 11 | + |
| 12 | +### In Condition Expressions |
| 13 | + |
| 14 | +**✅ Correct Pattern:** |
| 15 | +```yaml |
| 16 | +condition: eq(variables['VariableName'], 'value') |
| 17 | +condition: or(eq(variables['VAR1'], 'true'), eq(variables['VAR2'], 'true')) |
| 18 | +condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) |
| 19 | +``` |
| 20 | +
|
| 21 | +**❌ Incorrect Patterns:** |
| 22 | +```yaml |
| 23 | +# Don't use $(VAR) string expansion in conditions |
| 24 | +condition: eq('$(VariableName)', 'value') |
| 25 | + |
| 26 | +# Don't use direct variable references |
| 27 | +condition: eq($VariableName, 'value') |
| 28 | +``` |
| 29 | +
|
| 30 | +### In Script Content (pwsh, bash, etc.) |
| 31 | +
|
| 32 | +**✅ Correct Pattern:** |
| 33 | +```yaml |
| 34 | +- pwsh: | |
| 35 | + $value = '$(VariableName)' |
| 36 | + Write-Host "Value: $(VariableName)" |
| 37 | +``` |
| 38 | +
|
| 39 | +### In Input Fields |
| 40 | +
|
| 41 | +**✅ Correct Pattern:** |
| 42 | +```yaml |
| 43 | +inputs: |
| 44 | + serviceEndpoint: '$(ServiceEndpoint)' |
| 45 | + sbConfigPath: '$(SBConfigPath)' |
| 46 | +``` |
| 47 | +
|
| 48 | +## Parameter References |
| 49 | +
|
| 50 | +### Template Parameters (Compile-Time) |
| 51 | +
|
| 52 | +**✅ Correct Pattern:** |
| 53 | +```yaml |
| 54 | +parameters: |
| 55 | + - name: OfficialBuild |
| 56 | + type: boolean |
| 57 | + default: false |
| 58 | + |
| 59 | +steps: |
| 60 | + - task: SomeTask@1 |
| 61 | + condition: eq('${{ parameters.OfficialBuild }}', 'true') |
| 62 | +``` |
| 63 | +
|
| 64 | +Note: Parameters use `${{ parameters.Name }}` because they're evaluated at template compile-time. |
| 65 | + |
| 66 | +### Runtime Variables (Execution-Time) |
| 67 | + |
| 68 | +**✅ Correct Pattern:** |
| 69 | +```yaml |
| 70 | +steps: |
| 71 | + - pwsh: | |
| 72 | + Write-Host "##vso[task.setvariable variable=MyVar]somevalue" |
| 73 | + displayName: Set Variable |
| 74 | +
|
| 75 | + - task: SomeTask@1 |
| 76 | + condition: eq(variables['MyVar'], 'somevalue') |
| 77 | +``` |
| 78 | + |
| 79 | +## Common Scenarios |
| 80 | + |
| 81 | +### Scenario 1: Check if Variable Equals Value |
| 82 | + |
| 83 | +```yaml |
| 84 | +- task: DoSomething@1 |
| 85 | + condition: eq(variables['PREVIEW'], 'true') |
| 86 | +``` |
| 87 | + |
| 88 | +### Scenario 2: Multiple Variable Conditions (OR) |
| 89 | + |
| 90 | +```yaml |
| 91 | +- task: DoSomething@1 |
| 92 | + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) |
| 93 | +``` |
| 94 | + |
| 95 | +### Scenario 3: Multiple Variable Conditions (AND) |
| 96 | + |
| 97 | +```yaml |
| 98 | +- task: DoSomething@1 |
| 99 | + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) |
| 100 | +``` |
| 101 | + |
| 102 | +### Scenario 4: Complex Conditions |
| 103 | + |
| 104 | +```yaml |
| 105 | +- task: DoSomething@1 |
| 106 | + condition: and( |
| 107 | + succeededOrFailed(), |
| 108 | + ne(variables['UseAzDevOpsFeed'], ''), |
| 109 | + eq(variables['Build.SourceBranch'], 'refs/heads/master') |
| 110 | + ) |
| 111 | +``` |
| 112 | + |
| 113 | +### Scenario 5: Built-in Variables |
| 114 | + |
| 115 | +```yaml |
| 116 | +- task: CodeQL3000Init@0 |
| 117 | + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') |
| 118 | +
|
| 119 | +- step: finalize |
| 120 | + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') |
| 121 | +``` |
| 122 | + |
| 123 | +### Scenario 6: Parameter vs Variable |
| 124 | + |
| 125 | +```yaml |
| 126 | +parameters: |
| 127 | + - name: OfficialBuild |
| 128 | + type: boolean |
| 129 | +
|
| 130 | +steps: |
| 131 | + # Parameter condition (compile-time) |
| 132 | + - task: SignFiles@1 |
| 133 | + condition: eq('${{ parameters.OfficialBuild }}', 'true') |
| 134 | +
|
| 135 | + # Variable condition (runtime) |
| 136 | + - task: PublishArtifact@1 |
| 137 | + condition: eq(variables['PUBLISH_ENABLED'], 'true') |
| 138 | +``` |
| 139 | + |
| 140 | +## Why This Matters |
| 141 | + |
| 142 | +**String Expansion `$(VAR)` in Conditions:** |
| 143 | +- When you use `'$(VAR)'` in a condition, Azure Pipelines attempts to expand it as a string |
| 144 | +- If the variable is undefined or empty, it becomes an empty string `''` |
| 145 | +- The condition `eq('', 'true')` will always be false |
| 146 | +- This makes debugging difficult because there's no error message |
| 147 | + |
| 148 | +**Variables Array Syntax `variables['VAR']`:** |
| 149 | +- This is the proper way to reference runtime variables in conditions |
| 150 | +- Azure Pipelines correctly evaluates the variable's value |
| 151 | +- Undefined variables are handled properly by the condition evaluator |
| 152 | +- This is the standard pattern used throughout Azure Pipelines |
| 153 | + |
| 154 | +## Reference Examples |
| 155 | + |
| 156 | +Working examples can be found in: |
| 157 | +- `.pipelines/templates/linux.yml` - Build.SourceBranch conditions |
| 158 | +- `.pipelines/templates/windows-hosted-build.yml` - Architecture conditions |
| 159 | +- `.pipelines/templates/compliance/apiscan.yml` - CODEQL_ENABLED conditions |
| 160 | +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Complex AND/OR conditions |
| 161 | + |
| 162 | +## Quick Reference Table |
| 163 | + |
| 164 | +| Context | Syntax | Example | |
| 165 | +|---------|--------|---------| |
| 166 | +| Condition expression | `variables['Name']` | `condition: eq(variables['PREVIEW'], 'true')` | |
| 167 | +| Script content | `$(Name)` | `pwsh: Write-Host "$(PREVIEW)"` | |
| 168 | +| Task input | `$(Name)` | `inputs: path: '$(Build.SourcesDirectory)'` | |
| 169 | +| Template parameter | `${{ parameters.Name }}` | `condition: eq('${{ parameters.Official }}', 'true')` | |
| 170 | + |
| 171 | +## Troubleshooting |
| 172 | + |
| 173 | +### Condition Always False |
| 174 | +If your condition is always evaluating to false: |
| 175 | +1. Check if you're using `'$(VAR)'` instead of `variables['VAR']` |
| 176 | +2. Verify the variable is actually set (add a debug step to print the variable) |
| 177 | +3. Check the variable value is exactly what you expect (case-sensitive) |
| 178 | + |
| 179 | +### Variable Not Found |
| 180 | +If you get errors about variables not being found: |
| 181 | +1. Ensure the variable is set before the condition is evaluated |
| 182 | +2. Check that the variable name is spelled correctly |
| 183 | +3. Verify the variable is in scope (job vs. stage vs. pipeline level) |
| 184 | + |
| 185 | +## Best Practices |
| 186 | + |
| 187 | +1. **Always use `variables['Name']` in conditions** - This is the correct Azure Pipelines pattern |
| 188 | +2. **Use `$(Name)` for string expansion** in scripts and inputs |
| 189 | +3. **Use `${{ parameters.Name }}` for template parameters** (compile-time) |
| 190 | +4. **Add debug steps** to verify variable values when troubleshooting conditions |
| 191 | +5. **Follow existing patterns** in the repository - grep for `condition:` to see examples |
| 192 | + |
| 193 | +## Common Mistakes |
| 194 | + |
| 195 | +❌ **Mistake 1: String expansion in condition** |
| 196 | +```yaml |
| 197 | +condition: eq('$(PREVIEW)', 'true') # WRONG |
| 198 | +``` |
| 199 | + |
| 200 | +✅ **Fix:** |
| 201 | +```yaml |
| 202 | +condition: eq(variables['PREVIEW'], 'true') # CORRECT |
| 203 | +``` |
| 204 | + |
| 205 | +❌ **Mistake 2: Missing quotes around parameter** |
| 206 | +```yaml |
| 207 | +condition: eq(${{ parameters.Official }}, true) # WRONG |
| 208 | +``` |
| 209 | + |
| 210 | +✅ **Fix:** |
| 211 | +```yaml |
| 212 | +condition: eq('${{ parameters.Official }}', 'true') # CORRECT |
| 213 | +``` |
| 214 | + |
| 215 | +❌ **Mistake 3: Mixing syntax** |
| 216 | +```yaml |
| 217 | +condition: or(eq('$(STABLE)', 'true'), eq(variables['LTS'], 'true')) # INCONSISTENT |
| 218 | +``` |
| 219 | + |
| 220 | +✅ **Fix:** |
| 221 | +```yaml |
| 222 | +condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) # CORRECT |
| 223 | +``` |
0 commit comments