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
1name: CI 2 3trigger: 4 - main 5pr: 6 - main 7 8variables: 9 CI: 'true' 10 ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: 11 NX_BRANCH: $(System.PullRequest.PullRequestNumber) 12 TARGET_BRANCH: $[replace(variables['System.PullRequest.TargetBranch'],'refs/heads/','origin/')] 13 BASE_SHA: $(git merge-base $(TARGET_BRANCH) HEAD) 14 ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: 15 NX_BRANCH: $(Build.SourceBranchName) 16 BASE_SHA: $(git rev-parse HEAD~1) 17 HEAD_SHA: $(git rev-parse HEAD) 18 19jobs: 20 - job: main 21 pool: 22 vmImage: 'ubuntu-latest' 23 steps: 24 - checkout: self 25 fetchDepth: 0 26 fetchFilter: tree:0 27 # Set Azure Devops CLI default settings 28 - bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) 29 displayName: 'Set default Azure DevOps organization and project' 30 # Get last successfull commit from Azure Devops CLI 31 - bash: | 32 LAST_SHA=$(az pipelines build list --branch $(Build.SourceBranchName) --definition-ids $(System.DefinitionId) --result succeeded --top 1 --query "[0].triggerInfo.\"ci.sourceSha\"") 33 if [ -z "$LAST_SHA" ] 34 then 35 echo "Last successful commit not found. Using fallback 'HEAD~1': $BASE_SHA" 36 else 37 echo "Last successful commit SHA: $LAST_SHA" 38 echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA" 39 fi 40 displayName: 'Get last successful commit SHA' 41 condition: ne(variables['Build.Reason'], 'PullRequest') 42 env: 43 AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) 44 45 # This enables task distribution via Nx Cloud 46 # Run this command as early as possible, before dependencies are installed 47 # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun 48 # Connect your workspace by running "nx connect" and uncomment this line to enable task distribution 49 # - script: npx nx start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="build" 50 51 - script: npm ci --legacy-peer-deps 52 - script: git branch --track main origin/main 53 condition: eq(variables['Build.Reason'], 'PullRequest') 54 55 # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud 56 # - script: npx nx-cloud record -- echo Hello World 57 - script: npx nx affected --base=$(BASE_SHA) --head=$(HEAD_SHA) -t lint test build 58 # Nx Cloud recommends fixes for failures to help you get CI green faster. Learn more: https://nx.dev/ci/features/self-healing-ci 59 - script: npx nx fix-ci 60 condition: always() 61

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 CLI default settings 2- bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) 3 displayName: 'Set default Azure DevOps organization and project' 4

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

1# Get last successfull commit from Azure Devops CLI 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 if [ -z "$LAST_SHA" ] 5 then 6 echo "Last successful commit not found. Using fallback 'HEAD~1': $BASE_SHA" 7 else 8 echo "Last successful commit SHA: $LAST_SHA" 9 echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA" 10 fi 11 displayName: 'Get last successful commit SHA' 12 condition: ne(variables['Build.Reason'], 'PullRequest') 13 env: 14 AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) 15

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

  • The branch (--branch)
  • 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.