Configuring CI Using Azure Pipelines and Nx

Below is an example of an Azure Pipelines setup building and testing only what is affected.

azure-pipelines.yml
1trigger: 2 - main 3pr: 4 - main 5 6variables: 7 CI: 'true' 8 ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: 9 NX_BRANCH: $(System.PullRequest.PullRequestId) # You can use $(System.PullRequest.PullRequestNumber if your pipeline is triggered by a PR from GitHub ONLY) 10 TARGET_BRANCH: $[replace(variables['System.PullRequest.TargetBranch'],'refs/heads/','origin/')] 11 BASE_SHA: $(git merge-base $(TARGET_BRANCH) HEAD) 12 ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: 13 NX_BRANCH: $(Build.SourceBranchName) 14 BASE_SHA: $(git rev-parse HEAD~1) 15 HEAD_SHA: $(git rev-parse HEAD) 16 17jobs: 18 - job: main 19 pool: 20 vmImage: 'ubuntu-latest' 21 steps: 22 - checkout: self 23 fetchDepth: 0 24 25 # Set Azure Devops CLI default settings 26 - bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) 27 displayName: 'Set default Azure DevOps organization and project' 28 # Get last successfull commit from Azure Devops CLI 29 - displayName: 'Get last successful commit SHA' 30 condition: ne(variables['Build.Reason'], 'PullRequest') 31 env: 32 AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) 33 bash: | 34 LAST_SHA=$(az pipelines build list --branch $(Build.SourceBranchName) --definition-ids $(System.DefinitionId) --result succeeded --top 1 --query "[0].triggerInfo.\"ci.sourceSha\"") 35 if [ -z "$LAST_SHA" ] 36 then 37 echo "Last successful commit not found. Using fallback 'HEAD~1': $BASE_SHA" 38 else 39 echo "Last successful commit SHA: $LAST_SHA" 40 echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA" 41 fi 42 43 # Required for nx affected if we're on a branch 44 - script: git branch --track main origin/main 45 # This line enables distribution 46 # The "--stop-agents-after" is optional, but allows idle agents to shut down once the "e2e-ci" targets have been requested 47 - script: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="e2e-ci" 48 - script: npm ci 49 50 - script: npx nx-cloud record -- nx format:check --base=$(BASE_SHA) 51 - script: npx nx affected --base=$(BASE_SHA) -t lint test build e2e-ci 52

Get the Commit of the Last Successful Build

In the example above, we ran a script to retrieve the commit of the last successful build. The idea is to use Azure Devops CLI directly in the Pipeline Yaml

First, we configure Devops CLI

1# Set Azure Devops default settings 2- bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) 3 displayName: 'Configure Azure DevOps organization and project' 4

Then we can query the pipelines API (providing the auth token)

1# Get last successfully commit infos from Azure Devops 2- bash: | 3 LAST_SHA=$(az pipelines build list --branch $(Build.SourceBranchName) --definition-ids $(System.DefinitionId) --result succeeded --top 1 --query "[0].triggerInfo.\"ci.sourceSha\"") 4 echo "Last successful commit SHA: $LAST_SHA" 5 echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA" 6 displayName: 'Get last successful commit SHA' 7 env: 8 AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) 9

We can target a specific build; in this example, we specified:

  • The branch (--branch)
  • The pipeline ID (--definition-ids)
  • The result type (--result)
  • The number of the result (-top)

The command returns an entire JSON object with all the information. But we can narrow it down to the desired result with the --query param that uses JMESPath format (more details)

Finally, we extract the result in a common custom variable named BASE_SHA used later by the nx format and nx affected commands.