8

I am trying to set Azure DevOps to skip a stage on a multi-stage pipeline if a message does not start with a given text.

From the examples documentation, I think it is just

  - stage: t1
    condition: not(startsWith(variables['Build.SourceVersionMessage'], '[maven-release-plugin]'))
    jobs:
      - job: ReleasePrepare
        displayName: Prepare release
        pool:
          vmImage: 'ubuntu-16.04'
        steps:
          - script: |
              env | sort

However, this gets executed regardless. Here's an example of where I expect the t1 task to not be run based on the commit message https://dev.azure.com/trajano/experiments/_build/results?buildId=110&view=results

The output of env shows that the message was passed in correctly

enter image description here

Just in case it is a bug I reported it here as well https://developercommunity.visualstudio.com/content/problem/697290/startswith-buildsourceversionmessage-variable-not.html

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265

2 Answers2

5

It appears that Build.SourceVersionMessage at the time of this post is only resolvable on the steps.

Here's a working example that stores the value in a variable in one step and use it in the next job (which can be a deployment)

trigger:
  batch: true
  branches:
    include:
      - master

stages:
  - stage: ci
    displayName: Continuous Integration
    jobs:
      - job: Build
        pool:
          vmImage: 'ubuntu-16.04'
        steps:
          - script: |
              env | sort
              echo "$(Build.SourceVersionMessage)"
  - stage: t1
    displayName: Release
    condition: eq(variables['Build.SourceBranch'],'refs/heads/master')
    jobs:
      - job: GetCommitMessage
        displayName: Get commit message
        steps:
          - bash: |
              echo "##vso[task.setvariable variable=commitMessage;isOutput=true]$(Build.SourceVersionMessage)"
              echo "Message is '$(Build.SourceVersionMessage)''"
            name: SetVarStep
            displayName: Store commit message in variable
      - job: ReleasePrepare
        displayName: Prepare release
        dependsOn: GetCommitMessage
        pool:
          vmImage: 'ubuntu-16.04'
        condition: not(startsWith(dependencies.GetCommitMessage.outputs['SetVarStep.commitMessage'], '[maven-release-plugin]'))
        steps:
          - script: |
              echo this would be a candidate for release
              env | sort
            displayName: Don't do it if maven release
      - job: NotReleasePrepare
        displayName: Don't Prepare Release
        dependsOn: GetCommitMessage
        pool:
          vmImage: 'ubuntu-16.04'
        condition: startsWith(dependencies.GetCommitMessage.outputs['SetVarStep.commitMessage'], '[maven-release-plugin]')
        steps:
          - script: |
              echo this not be a candidate for release because it was created by the plugin
              env | sort
            condition: startsWith(variables.commitMessage, '[maven-release-plugin]')
            displayName: Do it if maven release

The build can be found in https://dev.azure.com/trajano/experiments/_build/results?buildId=133&view=logs&s=6fc7e65a-555d-5fab-c78f-9502ae9436c4&j=b5187b8c-216e-5267-fcdb-c2c33d846e05

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265
  • Thx for the code. Works like a charm! Seems the documentation has been updated on [BuildSourceVersion](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml), it _now_ explicitly states, that it is _only available at the step level_ – Christian Ulbrich Feb 07 '21 at 00:24
1

I am trying to set Azure DevOps to skip a stage if a message does not start with a given text.

If I am not misunderstand, the condition you want is if the message match the start with maven-release-plugin, the current stage will be queued.

If this, the condition you write is not correct, I think you should specified it:

startsWith(variables['Build.SourceVersionMessage'], '[maven-release-plugin]')

As I tested on my pipeline:

enter image description here

And in fact, the value of this variable is Deleted 121321. Here is the result:

enter image description here

As you can see, that it is successful to skip the stage. My logic is, the value of Build.SourceVersionMessage should start with othermessage. But in fact, in my pipeline, it's value is Deleted 121321. Not match, so skip this stage.

(Delete 121321 is not only my PR name, I just set the commit message as the default PR name.)

Updated 2:

Though my test logic is not incorrect, but after I reproduced with YAML and many other method tested, such as use Build.SourceVersion which can only got after the source pulled.

Yes, you are right about that Build.SourceVersionMessage does not has value in Job level. As my tested, it indeed null in job level.

But, unfortunately, this is not a bug. This is as designed in fact.

We can think that the source repos be pulled locally only the stage job begin to execute, right? You can see the Checkout log, it record the process about pull source file down.

If the stage does not be executed, the source will not be pulled down. But also, if no source pulled, the server will also could not get the value of Build.SourceVersionMessage because of no source history. That's why I also tested with the variable Build.SourceVersion in the Job level.

enter image description here

We can not use these two variable at the agent job level because it hasn't pulled sources yet so Build.SourceVersionMessage is null. You'll need to copy it to each step in your pipeline. This is what confirmed by our Product Group team.

But, I still need to say sorry. Sorry about our doc is not too clear to announce that this could not used in agent job level.

Mengdi Liang
  • 17,577
  • 2
  • 28
  • 35
  • You misunderstood. I want it to SKIP if it **does not start** with a given text. Secondly I want it from the **commit message** not the PR title – Archimedes Trajano Aug 16 '19 at 12:58
  • 1
    To prove it is not only my pr name, I use powershell to print the variable value out. See my updated content. In addition, doesn't the **SKIP if it does not start with a given text** mean that **if it is start with a given text, it will not be skipped, the stage will be executed**? – Mengdi Liang Aug 16 '19 at 13:20
  • In the shell it's present. However, if you can provide an example public pipeline at least I can compare with mine. – Archimedes Trajano Aug 16 '19 at 13:40
  • I see `BUILD_SOURCEVERSIONMESSAGE` in the `env | sort` output on mine so at least I know it's present there but it's not on the stage level – Archimedes Trajano Aug 16 '19 at 13:41
  • also I'm using the multi-stage YAML pipeline from your screenshot it looks like you're using classic. – Archimedes Trajano Aug 16 '19 at 13:41
  • Hi, Archimedes. Very appreciated your report. Yes, you are right, it indeed null in stage level. But this is not a bug, just as designed. For explanation, you can check my updated content. I have help you report it to product group team, they will consider to mentioned that this variable does not exist in stage job level in doc. – Mengdi Liang Aug 16 '19 at 14:27
  • 1
    It is also null on the "Job" level not just on the "Stage" level. So just indicate that it is only on the "Step" level. – Archimedes Trajano Aug 16 '19 at 15:01
  • Apologize for my word used.( I mentioned is Stage job) Yes, for these variable which about the source, can only be used on the "Step" level. – Mengdi Liang Aug 16 '19 at 15:05
  • I'll continue this on the Azure one because this is not the place for extended discussion. – Archimedes Trajano Aug 16 '19 at 15:11
  • Can we talk in chat? The ticket you raised in DC does not belong to my team. I could not answer there. – Mengdi Liang Aug 16 '19 at 15:14
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/198055/discussion-between-merlin-liang-msft-and-archimedes-trajano). – Mengdi Liang Aug 16 '19 at 15:22