Opening a pull request from an Azure Pipeline

As we have mentioned before, part of keeping your main trunk clean is to protect it from unreviewed commits to it. This is done by requiring pull requests to merge changes into your protected branches. One of the main challenges we have seen to that has been when non-technical resources are regularly contributing to a repository. This may be the case when:

  • Non-technical experts (e.g. lawyers, accountants, etc.) are contributing to documentation stored in source control
  • Dynamics customizers who are unfamiliar with git workflows are making regular changes to a development environment

Most recently, we used this particular workflow to allow PowerApps customizers to periodically pull their customizations out of their development environment and into source control. From there, we are able to do nightly releases to staging, test, and production.

By the end of this post, you will have your own YAML-based Azure Pipeline creating a pull request in your repository.

Prerequisites

Getting the tool

For this pipeline, we will be using an open source third-party extension for Azure DevOps: Create Pull Request by Shayki Abramczyk. This tool will help us to create the pull request in Azure DevOps and assign it to the proper people. Make sure that this extension is installed before we begin the YAML pipeline.

Note that currently, the task only works on Windows machines, and that there’s some setup instructions and permissions to set to get them working.

Granting the build service permissions

Additionally, you will need to grant the project’s build service the following permissions:

  • Contribute
  • Contribute to pull requests
  • Create branch

Creating our pipeline

First, we will start off with our pipeline outline. This will get the basics out of the way.

name: $(Date:yyyyMMdd)-$(Build.BuildId)

trigger: none

pool:
  vmImage: 'windows-latest'

steps:
  # Our steps will go here

We will want to add some variables at the top for easy editing. Below are the variable names, and how we will be using them:

Variable NameDescription
BranchNameThe name of the temporary branch that we will be creating in order to begin the pull request.
name: $(Date:yyyyMMdd)-$(Build.BuildId)

trigger: none

pool:
  vmImage: 'windows-latest'

variables:
  BranchName: 'autogenerated/$(Build.RequestedForEmail)/$(Build.BuildNumber)'

steps:
  # Our steps will go here

We will be using the folder structure feature of Azure Repos to organize these exports. Note that automatically generated branches will be tucked away in a folder called autogenerated, then sorted by the email of the user that started the pipeline. This allows us to keep our branches clean and organized, as well as keep track of who owns each branch for maintenance and cleanup.

Our first actual step is to check out the repo that we will be using and committing to. Since we will be running git commands against it, we need to add a persistCredentials attribute. More details about that can be found here.

# Omitted for brevity

steps:
  - checkout: self
    persistCredentials: true

Next, we will make a random change to our files. For our purposes, we will create a new file with some text to check in. In your pipeline, you may want to achieve the following:

  • Query recently completed stories and publish them to a release notes file
  • Export and unpack the latest changes from a PowerApps environment
# Omitted for brevity

steps:
  - checkout: self
    persistCredentials: true

  - task: PowerShell@2
    displayName: 'Create file with text content'
    inputs:
      targetType: 'inline'
      script: 'New-Item -Path . -Name "testfile1.txt" -ItemType "file" -Value "This is a text string."'

Now, we are going to use PowerShell to execute our git commands. They will do the following:

  • Configure the git identity to use the requestor’s name ($(Build.RequestedFor)) and their email ($(Build.RequestedForEmail))
  • Checkout and create a new branch using the branch name we configured in the variables section.
  • Add all changes
  • Commit them with a commit message
  • Check those changes into the branch
# Omitted for brevity

steps:
  - checkout: self
    persistCredentials: true

  - task: PowerShell@2
    displayName: 'Create file with text content'
    inputs:
      targetType: 'inline'
      script: 'New-Item -Path . -Name "testfile1.txt" -ItemType "file" -Value "This is a text string."'

  - task: PowerShell@2
    displayName: 'Check in file changes'
    inputs:
      targetType: 'inline'
      script: |
        Write-Host "Commit all changes"

        git config --global user.email "$(Build.RequestedForEmail)"
        git config --global user.name "$(Build.RequestedFor)"

        git checkout -b $(BranchName)
        git add --all
        git commit -m "Auto commit: $(Build.BuildNumber)"

        Write-Host "Push code to new repo"
        git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push origin $(BranchName)

Finally, we are going to use the Create Pull Request tool we added at the beginning to create our pull request.

# Omitted for brevity

steps:
  - checkout: self
    persistCredentials: true

  - task: PowerShell@2
    displayName: 'Create file with text content'
    inputs:
      targetType: 'inline'
      script: 'New-Item -Path . -Name "testfile1.txt" -ItemType "file" -Value "This is a text string."'

  - task: PowerShell@2
    displayName: 'Check in file changes'
    inputs:
      targetType: 'inline'
      script: |
        Write-Host "Commit all changes"

        git config --global user.email "$(Build.RequestedForEmail)"
        git config --global user.name "$(Build.RequestedFor)"

        git checkout -b $(BranchName)
        git add --all
        git commit -m "Auto commit: $(Build.BuildNumber)"

        Write-Host "Push code to new repo"
        git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push origin $(BranchName)

  - task: CreatePullRequest@1
    displayName: 'Create Pull Request'
    inputs:
      repoType: 'Azure DevOps'
      repositorySelector: 'currentBuild'
      sourceBranch: '$(BranchName)'
      targetBranch: '$(Build.SourceBranch)'
      title: 'Autocreated PR $(Build.BuildNumber)'
    env:
      System_AccessToken: $(System.AccessToken)

One super important note is that the YAML assistant does not add that last line on (env: System_AccessToken: $(System.AccessToken)), but it is a crucial part of it.

With that, you should be able to run your YAML build!

Next steps

If you don’t already have them, you should definitely make sure to have some branch policies in place. These will automatically assign reviewers and builds to your freshly minted pull request, making sure that everything going into your main branch has been reviewed, built, and tested.

Let Us Help You Out!

f you have any questions or need any clarifications, feel free to contact us at contact@codevanguard.com.

Code Vanguard has worked with clients of all sizes, helping them to use DevOps practices to accelerate their time to delivery. If you’d like Code Vanguard to help your organization with your DevOps process, feel free to reach out to us!

James Stephens About the author

James is the founder of Code Vanguard and one of its developers. He is an applied mathematician turned computer programming. His focuses are on security, DevOps, automation, and Microsoft Azure.

No Comments

Post a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.