DEV Community

Mintu Ghosh
Mintu Ghosh

Posted on

Azure DevOps stage output variables - three things that silently do not work

I needed one stage to compute something and later stages to condition on it.
Azure DevOps supports this. It also fails silently in three specific ways, and
none of them produce an error message that points at the cause.

Nothing Fabric-specific here. This applies to any multi-stage pipeline.

Setting the variable

- stage: DetectChanges
  jobs:
    - job: Detect
      steps:
        - script: python scripts/detect_changes.py
          name: detect          # <- required
Enter fullscreen mode Exit fullscreen mode

The script writes:

##vso[task.setvariable variable=ved;isOutput=true]true
Enter fullscreen mode Exit fullscreen mode

Reading it

- stage: Deploy_ved
  dependsOn: DetectChanges
  condition: >-
    eq(dependencies.DetectChanges.outputs['Detect.detect.ved'], 'true')
Enter fullscreen mode Exit fullscreen mode

Gotcha 1: the values are strings

eq(dependencies.DetectChanges.outputs['Detect.detect.ved'], true)    # never matches
eq(dependencies.DetectChanges.outputs['Detect.detect.ved'], 'true')  # correct
Enter fullscreen mode Exit fullscreen mode

The first one is valid YAML, valid expression syntax, and always false. Your
stage skips every time and the pipeline goes green because a skipped stage is
not a failed stage.

Quote the value.

Gotcha 2: the reference has three parts, not one

dependencies.<Stage>.outputs['<Job>.<StepName>.<Variable>']
                              ^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
Enter fullscreen mode Exit fullscreen mode

The job name and the step name both appear in the string. Miss either and you
get an empty value rather than an error.

The step name is not displayName. If your step only has a displayName, it
has no addressable name and the variable is unreachable.

Gotcha 3: the consuming stage must declare the dependency

- stage: Deploy_ved
  dependsOn: DetectChanges      # without this the variable cannot resolve
Enter fullscreen mode Exit fullscreen mode

dependencies.X only sees stages this stage actually depends on. Without
dependsOn, the expression resolves to nothing. No error, no warning, and the
condition evaluates false.

Why all three fail the same way

Every one of these produces an empty string, which compares false, which skips
the stage, which is a legitimate outcome that Azure DevOps reports as success.

You get a green pipeline that did nothing. That is worse than a red one, because
nothing prompts you to look.

Debugging it

Print what you set, in the producing job:

- script: echo "ved=$(detect.ved)"
Enter fullscreen mode Exit fullscreen mode

And publish the decision as a build artifact. I write a JSON file from the
detection script and publish it, so every run has a durable record of what it
decided rather than a log line that ages out.

- publish: $(Build.ArtifactStagingDirectory)/change-detection.json
  artifact: change-detection
Enter fullscreen mode Exit fullscreen mode

The one that bit hardest

Not in the list above. A stage skipping is indistinguishable, in the UI, from a
stage that was correctly filtered out.

So when you are looking at a run and thinking "good, the unrelated stages were
skipped", check why they skipped. Branch condition and output-variable
condition look identical in the stage view and mean completely different things.

I nearly used a screenshot as evidence for the wrong claim on exactly that
basis.


Full context: [https://www.linkedin.com/pulse/enterprise-microsoft-fabric-cicd-selective-one-azure-devops-ghosh-uxzsf]
Code: [https://github.com/VEDAFORGE/fabric-cicd-reference/tree/v2.0.0]

Top comments (0)