3

I have a solution where a git branch is directly related to an environment (this has to be this way, so please do not discuss whether this is good or bad, I know it is not best practice).

We have the option to run a verification deployment (including automatic tests) towards an environment, without actually deploying the solution to the environment. Because of this, I would like to set up a pipeline that runs this verification for an environment, whenever a pull request is opened towards that environment's branch. Moreover, I am using a template for the majority of the pipeline. The actual pipeline in the main repository is just a tiny solution that points towards the template pipeline in another repository. This template, in turn, has stages for each respective environment.

I have, in the main pipeline, successfully added a solution that identifies the current branch, which for pull requests should be the target branch:

variables:
  - name: currentBranch
    ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
      value: $(System.PullRequest.TargetBranch)
    ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
      value: $(Build.SourceBranch)

I would like to send this variable currentBranch down to the template through a parameter, as my template pipeline has different stages depending on the branch. My solution was to use the pipeline like this:

extends:
  template: <template-reference>
  parameters:
    branch: $(currentBranch)

...and then for a stage in my pipeline do this:

- stage: TestAndDeployBranchName
    condition: eq('${{ parameters.branch }}', 'refs/heads/branchName')
    jobs:
      - job1... etc.

Basically, the stage should run if the current branch is either "branchName", or (for pull requests) when the target branch is "branchName", which comes from the "branch" parameters that is sent to the template.

However, I see here that System.PullRequest.TargetBranch is not available for templates and further here that the parameters are not available for templates (the variable is empty) when the template is expanded. Thus my pipeline does not work as expected (the condition does not trigger when it should, ie. when there is a match on the branch name).

Is there any way that I can use System.PullRequest.TargetBranch in a condition within a template, or should I look for another solution?

Bast
  • 373
  • 3
  • 10

2 Answers2

3

After investigating this further I concluded that what I am trying to do is not possible.

In short, System.PullRequest.TargetBranch (and I assume at least some other variables within System.PullRequest are not available in compile time for template, which is when conditions are evaluated. Thus, using these variables in a condition in a template is not possible.

As my goal was to have certain steps run for pull requests only, based on the target branch of the pull request, I solved this by creating duplicate pipelines. Each pipeline is the same and references the same template, except for that the input parameter for the template is different. I then added each "PR pipelines" to run as part of the branch policy each respective branch this was applicable.

This works great, however it requires me to create a new pipeline if I have the same requirement for another branch. Moreover, I have to maintain each PR pipeline separately (which can be both good and bad).

Not an ideal solution, but it works.

Reference PR pipeline:

trigger: none # no trigger as PR triggers are set by branch policies

#This references the template repository to reuse the basic pipeline
resources:
  repositories:
  - repository: <template repo>
    type: git # "git" means azure devops repository
    name: <template name> # Syntax: <project>/<repo>
    ref: refs/heads/master # Grab latest pipeline template from the master branch

stages:
  - stage: VerifyPullRequest
    condition: |
      and(
        not(failed()), 
        not(canceled()), 
        eq(variables['Build.Reason'], 'PullRequest')
      )
    displayName: 'Verify Pull Request'
    jobs:
      - template: <template reference> # Template reference
        parameters:
          image: <image>
          targetBranch: <targetBranch> # Adjust this to match each respective relevant branch

The targetBranch parameter is the used in relevant places in the template to run PR verification.

Example of branch policy: (Set this up for each relevant branch) Picture of branch policy set up

Bast
  • 373
  • 3
  • 10
1

After checking your script, we find we can not use the

  variables:
  - name: currentBranch
    ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
      value: $(System.PullRequest.TargetBranch)
    ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
      value: $(Build.SourceBranch)

in the variables. The variables will duplicate the second value to first one. This will cause your issue. So, on my side, I create a work around and hope this will help you. Here is my main yaml:

parameters:
  - name: custom_agent
    displayName: Use Custom Agent
    type: boolean
    default: true
  - name: image
    type: string
    default: default

resources:
  repositories:
    - repository: templates
      type: git
      name: Tech-Talk/template

trigger: none

    
pool:
  vmImage: windows-latest
  # vmImage: ubuntu-20.04

stages:
- stage: A
  jobs:
  - job: A1
    steps:
     - task: PowerShell@2
       name: printvar 
       inputs:
         targetType: 'inline'
         script: |
            If("$(Build.Reason)" -eq "PullRequest"){
                Write-Host "##vso[task.setvariable variable=currentBranch;isOutput=true]$(System.PullRequest.TargetBranch)"
            }
            else{
                Write-Host "##vso[task.setvariable variable=currentBranch;isOutput=true]$(Build.SourceBranch)"
            }    
    
- stage: B
  condition: eq(dependencies.A.outputs['A1.printvar.currentBranch'], 'refs/heads/master')
  dependsOn: A
  jobs:
  - job: B1
    variables:
      varFromA: $[ stageDependencies.A.A1.outputs['printvar.currentBranch'] ]
    steps:
    - task: PowerShell@2
      inputs:
        targetType: 'inline'
        script: |
          # Write your PowerShell commands here.
          
          Write-Host "$(varFromA)"
    - template:  temp.yaml@templates
      parameters:
        branchName: $(varFromA)
        agent_pool_name: ''
        db_resource_path: $(System.DefaultWorkingDirectory)

Please Note: If we use this, we need to modified your temp yaml. We need to move the condition to the main yaml and make the temp yaml only steps is left.

Felix
  • 1,104
  • 3
  • 6
  • Actually the way I set the variables works, see for example this thread here: https://stackoverflow.com/questions/57532138/can-conditional-variable-assignment-be-done-in-azure-pipelines. Moreover I verified that the branch is passed on as a parameter. My issue is rather that the predefined variable System.PullRequest.TargetBranch is not defined at compile time (it is only available at runtime). Apparently the conditions in pipelines evaluate at compile time and thus I cannot evaluate System.PullRequest.TargetBranch. My question is if there is a workaround for this. – Bast Mar 23 '21 at 10:38
  • Hi @Bast, In this situation, We can not use other branch's pr to trigger master pipeline. Here: We need to create a new pipeline based on the other branch not based on the master. Then the PR will find the new pipeline. If we just set the branch policy, then the pipeline will not run and show the error: 'An error occurred while loading the YAML build pipeline. Object reference not set to an instance of an object.' – Felix Mar 29 '21 at 09:47
  • Thanks, I figured it worked like that. My solution ended up being: I created a separate pipeline for each branch I want PR validation for. The pipelines are all the same except a parameter that specifies the branch. It is very unfortunate that Azure DevOps do not know the PullRequest-information such as target branch during compliation of the pipeline. – Bast Apr 06 '21 at 15:40
  • Hi @Bast, I am glad to know you have solved your issue. Could you please edit your solution as an answer and mark it? This will help our other productor solve their similar issue. – Felix Apr 07 '21 at 01:55