> ## Documentation Index
> Fetch the complete documentation index at: https://docs.codeant.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# CircleCI

> Set up CircleCI Pipeline for coverage reporting.

## CircleCI Pipeline

Add the following job to your `.circleci/config.yml`. It triggers on pushes to the configured branches:

```yaml theme={null}
version: 2.1

jobs:
  test-coverage:
    docker:
      - image: cimg/python:3.11
    
    environment:
      API_BASE: https://api.codeant.ai
    
    steps:
      - checkout
      
      - run:
          name: Extract repository information
          command: |
            # CircleCI provides these automatically
            echo "Repository: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}"
            echo "Branch: ${CIRCLE_BRANCH}"
            echo "Commit: ${CIRCLE_SHA1}"
      
      - run:
          name: Run tests and generate coverage
          command: |
            # Activate virtual environment if exists
            if [ -f .venv/bin/activate ]; then
              source .venv/bin/activate
            fi
            
            # Install coverage tools
            pip install coverage pytest
            
            # Run tests with coverage
            coverage run -m pytest tests/
            coverage xml -o coverage.xml
            
            # Display coverage report
            cat coverage.xml
      
      - run:
          name: Fetch coverage-upload script
          command: |
            curl -sS -X GET "${API_BASE}/pr/analysis/coverage/script/get" \
              --output upload_coverage.sh.b64
      
      - run:
          name: Make script executable
          command: |
            base64 -d upload_coverage.sh.b64 > upload_coverage.sh
            chmod +x upload_coverage.sh
      
      - run:
          name: Upload coverage and set status
          command: |
            bash upload_coverage.sh \
              -t "${CODEANT_TOKEN}" \
              -r "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
              -c "${CIRCLE_SHA1}" \
              -f coverage.xml \
              -p github \
              -b "${CIRCLE_BRANCH}"
      
      - run:
          name: Clean up
          when: always
          command: |
            rm -f upload_coverage.sh upload_coverage.sh.b64
      
      - store_artifacts:
          path: coverage.xml
          destination: coverage-reports

workflows:
  version: 2
  build:
    jobs:
      - test-coverage:
          context: codeant-context
```

For monorepo projects, add the module name parameter `-m module_name` to the upload script. To upload coverage for multiple modules from a single commit, invoke `upload_coverage.sh` once per module — each invocation with its own `-f`, `-m`, and `-d`. A single invocation with multiple `-m` flags will only honor the last value and attribute every file to that one module. See [Multiple Coverage Files (Monorepo)](#multiple-coverage-files-monorepo) below for the recommended setup.

## Multiple Coverage Files (Monorepo)

When a single commit produces several coverage reports — for example one per service in a monorepo — give each upload its own `-m module_name` and `-d module_path`. CodeAnt AI keeps the reports separate so each module is tracked, displayed, and gated independently. Without a module name, every upload writes to the same key and later jobs overwrite earlier ones.

### Recommended: a parameterized job invoked per module

Define the upload job once with [job parameters](https://circleci.com/docs/reusing-config/#using-parameters-in-executors) and invoke it from the workflow once per module. Each invocation becomes its own parallel job; adding a new module is one new entry in `workflows.build.jobs`.

```yaml theme={null}
version: 2.1

jobs:
  upload-coverage:
    parameters:
      module:
        type: string
      module_path:
        type: string
      coverage_file:
        type: string
    docker:
      - image: cimg/python:3.11
    environment:
      API_BASE: https://api.codeant.ai
    steps:
      - checkout

      - run:
          name: Run tests and generate coverage for << parameters.module >>
          command: |
            cd << parameters.module_path >>
            pip install coverage pytest
            coverage run -m pytest tests/
            coverage xml -o coverage.xml

      - run:
          name: Fetch coverage-upload script
          command: |
            curl -sS -X GET "${API_BASE}/pr/analysis/coverage/script/get" \
              --output upload_coverage.sh.b64
            base64 -d upload_coverage.sh.b64 > upload_coverage.sh
            chmod +x upload_coverage.sh

      - run:
          name: Upload coverage and set status
          command: |
            bash upload_coverage.sh \
              -t "${CODEANT_TOKEN}" \
              -r "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
              -c "${CIRCLE_SHA1}" \
              -f "<< parameters.coverage_file >>" \
              -p github \
              -b "${CIRCLE_BRANCH}" \
              -m "<< parameters.module >>" \
              -d "<< parameters.module_path >>"

workflows:
  build:
    jobs:
      - upload-coverage:
          name: upload-backend
          context: codeant-context
          module: backend
          module_path: services/backend
          coverage_file: services/backend/coverage.xml
      - upload-coverage:
          name: upload-frontend
          context: codeant-context
          module: frontend
          module_path: services/frontend
          coverage_file: services/frontend/coverage/cobertura-coverage.xml
      - upload-coverage:
          name: upload-api
          context: codeant-context
          module: api
          module_path: services/api
          coverage_file: services/api/coverage.xml
```

CircleCI runs each invocation as its own job (`upload-backend`, `upload-frontend`, `upload-api`) in parallel. Adding a new module is one extra block under `workflows.build.jobs`.

> CircleCI's [`matrix`](https://circleci.com/docs/using-matrix-jobs/) directive can also fan a job out across parameter combinations, but it requires **every** required parameter to be supplied via the matrix. It's a fit only when `module_path` and `coverage_file` follow a strict convention you can express as lists — otherwise stick with the explicit per-module entries above.

### Alternative: sequential uploads in a single job

If you don't need parallel uploads, keep the original single-job layout from the top of this page and call the upload script once per module — each invocation with its own `-f`, `-m`, and `-d`:

```yaml theme={null}
- run:
    name: Upload coverage for all modules
    command: |
      bash upload_coverage.sh -t "${CODEANT_TOKEN}" \
        -r "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
        -c "${CIRCLE_SHA1}" -p github -b "${CIRCLE_BRANCH}" \
        -f services/backend/coverage.xml -m backend -d services/backend

      bash upload_coverage.sh -t "${CODEANT_TOKEN}" \
        -r "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
        -c "${CIRCLE_SHA1}" -p github -b "${CIRCLE_BRANCH}" \
        -f services/frontend/coverage/cobertura-coverage.xml -m frontend -d services/frontend
```

## Environment Variables Configuration

Create a CodeAnt token in CodeAnt AI under **API Tokens** in the user menu (your email at the bottom-left) — see [API Tokens](/settings/api-tokens), then add it to CircleCI:

1. Go to **Project Settings -> Environment Variables**
2. Click **Add Environment Variable**
3. Add variable name: `CODEANT_TOKEN`
4. Paste your CodeAnt token (`cdt_…`) as the value
5. Click **Add Environment Variable**

Alternatively, use a context for organization-wide settings:

1. Go to **Organization Settings -> Contexts**
2. Create a context named `codeant-context`
3. Add the `CODEANT_TOKEN` variable with your CodeAnt token

## 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:

```yaml theme={null}
# 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.

## Troubleshooting

### Coverage file not found

If the coverage file is not generated:

* Verify tests are running successfully
* Check that coverage is installed: `pip install coverage`
* Ensure the correct test command is used
* Check the working directory

### Upload fails with authentication error

If you see "Access token invalid":

* Verify the `CODEANT_TOKEN` environment variable holds a valid CodeAnt token (`cdt_…`) that hasn't been revoked
* Ensure the token belongs to the same organization as the repository
* Check that you're using the correct context or project environment variables

### Coverage percentage is 0%

If coverage shows 0%:

* Check your `.coveragerc` configuration
* Verify the source paths are correct
* Ensure tests are actually exercising the code
* Check omit patterns aren't excluding too much

### Branch name extraction issues

CircleCI automatically provides:

* `CIRCLE_BRANCH`: The branch name
* `CIRCLE_SHA1`: The commit SHA
* `CIRCLE_PROJECT_USERNAME`: The organization/username
* `CIRCLE_PROJECT_REPONAME`: The repository name
