Azure DevOps Pipelines Workflow

This pipeline triggers on pushes to the specified branch (e.g., pr_coverage or main) and performs the following steps:

  1. Runs tests and generates a coverage report.
  2. Fetches the CodeAnt AI upload script.
  3. Uploads the coverage XML to CodeAnt AI.
trigger:
  branches:
    include:
      - main

jobs:
  - job: Coverage
    displayName: Run tests, generate coverage report and upload to CodeAnt AI
    container: python:3.11

    variables:
      API_BASE:     https://ved6vc7dkvz3veaigrllnasa4y0kmqbw.lambda-url.ap-south-1.on.aws
      ACCESS_TOKEN: <YOUR_ACCESS_TOKEN>

    steps:
      - checkout: self

      - script: |
          python -m venv .venv
          source .venv/bin/activate
          pip install --upgrade pip
          pip install coverage pytest uv

          coverage run -m pytest tests/
          coverage xml -o coverage.xml
          cat coverage.xml
        displayName: 'Run tests & generate coverage'

      - script: |
          curl -sS -X GET "${API_BASE}/pr/analysis/coverage/script/get" \
               --output upload_coverage.sh
          chmod +x upload_coverage.sh
        displayName: 'Fetch upload script'

      - script: |
          source .venv/bin/activate

          # Build full Azure DevOps slug: org/project/repo
          ORG=$(echo "$SYSTEM_COLLECTIONURI" | sed -E 's|https://dev.azure.com/([^/]+)/|\1|')
          PROJECT="$SYSTEM_TEAMPROJECT"
          REPO="$BUILD_REPOSITORY_NAME"
          FULL_REPO="${ORG}/${PROJECT}/${REPO}"

          bash upload_coverage.sh \
            -t "${ACCESS_TOKEN}" \
            -r "${FULL_REPO}" \
            -c "${BUILD_SOURCEVERSION}" \
            -f coverage.xml \
            -p azuredevops \
            -m <module_name>
        displayName: 'Upload coverage'

Don’t forget to add your access token. The access token should have write access to the repo.

The <module_name> is optional. It is used to specify modules in the case of monorepo structure.

Coverage config file

You have to create a .coveragerc file in the project’s root folder to include all the source files in the test coverage calculation.

Example:

# include every Python file under the repo root
source = .

# exclude tests, virtualenvs, build artifacts, etc.
omit =
    */tests/*
    */.venv/*
    */build/*
    */dist/*

When you assign source to ”.” , It checks for every python file in the root folder and its sub directories. You can omit some directories by placing them in the omit section of the file.

How it works

With the above configuration:

  1. coverage run -m pytest tests/ will count every .py under the workspace as “valid” lines except for those in the omitted directories.
  2. Lines actually executed by your tests are marked “covered.”
  3. coverage xml -o coverage.xml produces a Cobertura-style report reflecting true coverage over the entire codebase.
  4. Using this coverage xml, we calculate the coverage percentage and the status check will be done on every new push to the branch.