Pipeline runs:

pull requests can require (via branch policy: Build Validation) builds to happen before they can be merged.

Normal runs are happening after something is merged into a branch.

variables

secret variables

You need to map the secret variables first to get its content. For example:

  - script: jmeter -n -t $(Build.SourcesDirectory)/.azure/load-test-preference-service.jmx -l reports/results.jtl -e -o reports
    env:
      CND_CUSTOMER_PREFERENCE_SERVICE_HOST: $(LOAD_TEST_HOST)
      LOAD_TEST_PASSWORD: $(LOAD_TEST_PASSWORD)
      LOAD_TEST_SYSTEM_OF_RECORD_ID : $(LOAD_TEST_SYSTEM_OF_RECORD_ID)

predefined variables

Build.Reason

  • IndividualCI -> Triggered when a branch is updated
  • PullRequest -> Triggered by a branch policy
  • Manual -> Triggered manually

Create PR comments with Powershell

Make a conditional task within a pipeline

- task: PowerShell@2
  condition: eq(variables['Build.Reason'], 'PullRequest')
  displayName: Post Message to PR
  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)  
  inputs:
      targetType: filePath
      filePath: PostToPR.ps1

Trigger Pipeline run on Pull request

Option 1 - Via Build Validation policy

azure-devops-build-validation

Option 2 - Via yml pipeline file

# trigger this pipeline if there's a PR to any of these branches
pr:
- master
- main
- staging
- releases/*

Scheduled trigger

By default every pipeline is enabled for IndividualCI trigger. As soon as there are changes to the branch, the pipeline would run. Thats why you need to disable this. You can also define schedules via ADO ui and it will override whats defined in the yaml definition.

trigger: none

schedules:
- cron: '0 0 1 * *' # check: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/scheduled-triggers?view=azure-devops&tabs=yaml#cron-syntax
  displayName: Every first day of a month
  branches:
  include:
    - main

Using PAT basic authorization

Generate a new personal access token on Azure Devops. You can use the token in the Basic Authorization header. Just keep the username empty and the PAT token is the password. --header 'Authorization: Basic {toBase64(:$PAT-token)}'

Infos here

Create PR comments

Make this REST call according to the MS docu, but omit the pullRequestThreadContext attribute, as ADO would then ignore the filePath attribute.

curl --location --request POST 'https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo-name}/pullRequests/95973/threads?api-version=7.0' \
--header 'Authorization: Basic {PAT}' \
--header 'Content-Type: application/json' \
--data-raw ' {
      "comments": [
        {
          "parentCommentId": 0,
          "content": "Thats my comment",
          "commentType": 1
        }
      ],
      "status": 1,
      "threadContext": {
        "filePath": "/Allora.Core/Services/BlobStorageService.cs",
        "leftFileEnd": null,
        "leftFileStart": null,
        "rightFileEnd": {
          "line": 92,
          "offset": 100
        },
        "rightFileStart": {
          "line": 92,
          "offset": 1
        }
      }
    }'

Checkout the sample pipeline

And its powershell script

Use emojis

[Emoji in Azure Devops()]https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#emoji)

SonarQube integration

Create a sonarQube project and configure it to integrate with your ADO repository. Only with this setting, SonarQube will be able to publish a state back to the PR. azure-devops-build-validation

Then you need to create a pipeline with these steps in it:

  - job: SonarQubeAnalysis
    displayName: "SonarQube Analysis"
    dependsOn: BuildTest
    steps:
      - task: DownloadPipelineArtifact@2
        displayName: 'Download Pipeline Artifact'
        inputs:
          artifact: artifactForSQ
          path: target/
      - task: SonarQubePrepare@5
        displayName: 'Prepare SonarQube'
        inputs:
          SonarQube: 'service-connection'
          scannerMode: 'CLI'
          configMode: 'manual'
          cliProjectKey: SonarQubeprojectKey
          extraProperties: |
            sonar.coverage.exclusions=**/test/**
            sonar.java.binaries=target/
            sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
            sonar.exclusions=src/main/resources/sql/**, src/main/resources/templates/**
      - task: SonarQubeAnalyze@5
        displayName: 'Analyze SonarQube'
      - task: SonarQubePublish@5
        displayName: 'Publish SonarQube'
        inputs:
          pollingTimeoutSec: '300'

Then define this pipeline as Build Validation step.

After the first run you should be able to set a Status Check on SonarQube quality gate: azure-devops-build-validation

Paths on ADO pipeline

$(Pipeline.Workspace) equals to $(Agent.BuildDirectory)

-> $(Build.SourcesDirectory) -> $(Pipeline.Workspace)/s

Debug on Pipelines

    steps:
      - task: DownloadPipelineArtifact@2
        displayName: 'Download Pipeline Artifact'
        inputs:
          artifact: artifactForSQ
          targetPath: '$(Pipeline.Workspace)/s'
      - script: |
          echo "ls $(System.DefaultWorkingDirectory)/"
          ls $(System.DefaultWorkingDirectory)/
          
          echo "ls $(Pipeline.Workspace)"
          ls $(Pipeline.Workspace)
          
          echo "ls $(Pipeline.Workspace)/s"
          ls $(Pipeline.Workspace)/s

Tree

This will output the content of the defined workingDirectory in a nice tree. Its including folder and files

- task: CmdLine@2
  displayName: 'tree command in $(Build.ArtifactStagingDirectory)'
  inputs:
    workingDirectory: $(Build.ArtifactStagingDirectory)
    script: 'tree /F'

If else

Following example show how to use createSandBox and sanboxName attributes only if the if-condition is met.

  - task: Veracode@3
    displayName: 'Upload to VeraCode and run static scan'
    inputs:
      ConnectionDetailsSelection: Credentials
      apiId: '$(veracode-api-id)'
      apiKey: '$(veracode-api-secret)'
      veracodeAppProfile: 'blalba' # Veracode application profile to scan
      version: '$(build.buildNumber)-$(Build.BuildId)' # name of the scan to run
      filepath: '$(Build.ArtifactStagingDirectory)/publish_output' # filepath or folderpath of files to upload to Veracode
      $:
        createSandBox: true # true to scan of new development sandbox
        sandboxName: 'PullRequest-Sandbox'
      createProfile: false # false to enforce using existing profiles
      failBuildIfUploadAndScanBuildStepFails: true # true to fail build if Upload and Scan task fails to start
      importResults: true # required to view Veracode results in Azure DevOps
      failBuildOnPolicyFail: true # true to fail the build if application fails policy
      maximumWaitTime: '360' # wait time, in minutes, to fail the build if no scan results available

Updated: