apex-code-coverage-transformer
v2.16.1
Published
Transform Salesforce Apex code coverage JSONs into other formats accepted by SonarQube, GitHub, GitLab, Azure, Bitbucket, etc.
Downloads
12,331
Maintainers
Readme
apex-code-coverage-transformer
A Salesforce CLI plugin that converts Apex code coverage JSON (from deploy or test runs) into formats used by SonarQube, Codecov, GitHub, GitLab, Azure DevOps, Bitbucket, and other tools. Use it to keep coverage in sync with your CI/CD and code quality pipelines.
Missing an output format via
--format? Open an issue or submit a pull request.
- Prerequisites
- Install
- Quick Start
- Usage
- What This Plugin Fixes and Adds
- Command Reference
- Coverage Report Formats
- CI/CD Integration
- Automatic Transformation (Hook)
- Troubleshooting
- Contributing
- License
Prerequisites
- Salesforce CLI (
sf) installed - Node.js 20.x or later
- A Salesforce DX project with
sfdx-project.jsonand package directories - Use only the json coverage formatter from the Salesforce CLI; other formatters are not supported
Install
sf plugins install [email protected]Quick Start
Generate Apex code coverage (JSON)
From tests:sf apex run test --code-coverage --output-dir "coverage"Or from deploy/validate:
sf project deploy start --coverage-formatters json --results-dir "coverage" # or: sf project deploy validate --coverage-formatters json --results-dir "coverage"Transform to your target format
Test output →coverage/test-result-codecoverage.json. Deploy output →coverage/coverage/coverage.json.# SonarQube sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar" # Codecov (Cobertura) sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura" # Multiple formats sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -f "sonar" -f "cobertura" -f "jacoco"Upload to your tool
See CI/CD Integration for Codecov, SonarQube, GitHub Actions, and GitLab.
Usage
This plugin is for Salesforce DX projects (sfdx-project.json). It maps Apex names in the CLI coverage JSON to file paths in your package directories and only includes files that exist in those directories. Apex from managed or unlocked packages (not in your repo) is excluded and reported with a warning.
To run transformation automatically after deploy or test commands, use the Hook.
Salesforce CLI
Deploy/validate — coverage path: coverage/coverage/coverage.json
sf project deploy [start|validate|report|resume] --coverage-formatters json --results-dir "coverage"Run tests — coverage path: coverage/test-result-codecoverage.json
sf apex run test --code-coverage --output-dir "coverage"
sf apex get test --test-run-id <id> --code-coverage --output-dir "coverage"SFDX Hardis
Works with sfdx-hardis:
sf hardis project deploy smart(whenCOVERAGE_FORMATTER_JSON=true)sf hardis org test apex
Coverage file: hardis-report/apex-coverage-results.json.
What This Plugin Fixes and Adds
- File mapping — Maps names like
no-map/AccountTriggerHandlerto paths likeforce-app/main/default/classes/AccountTriggerHandler.cls. - Normalization — Aligns deploy and test coverage structures so external tools can consume them.
- Extra formats — Outputs Sonar, Cobertura, JaCoCo, LCOV, Clover, and more (see Coverage Report Formats).
- Deploy-coverage fixes — Corrects known CLI issues (e.g. out-of-range covered lines, wrong line counts) by re-numbering covered lines in deploy reports. Uncovered lines are already correct. This workaround will be removed in a future breaking release once Salesforce fixes the API; see forcedotcom/salesforcedx-vscode#5511 and forcedotcom/cli#1568. Test-command coverage is unaffected.
Command Reference
Single command: sf acc-transformer transform.
sf acc-transformer transform
USAGE
$ sf acc-transformer transform -j <value> [-r <value>] [-f <value>] [-i <value>] [--json]
FLAGS
-j, --coverage-json=<value> Path to the code coverage JSON from deploy or test.
-r, --output-report=<value> Output path (e.g. coverage.xml). Default: coverage.[xml|info] by format.
-f, --format=<value> Output format (repeat for multiple). Default: sonar.
Multiple formats append to filename, e.g. coverage-sonar.xml.
-i, --ignore-package-directory=<value> Package directory to ignore (as in sfdx-project.json). Repeatable.
GLOBAL FLAGS
--json Output as JSON.Coverage Report Formats
Use -f / --format to choose the output format. Multiple -f values produce multiple files with the format in the name (e.g. coverage-sonar.xml, coverage-cobertura.xml).
| Format | Description | Typical use | Example |
| ------------ | -------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------- |
| sonar | SonarQube generic coverage | SonarQube, SonarCloud | sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "sonar" |
| cobertura | Cobertura XML | Codecov, Azure, Jenkins, GitLab, GitHub | sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "cobertura" |
| jacoco | JaCoCo XML | Codecov, Jenkins, Maven, Gradle | sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "jacoco" |
| lcovonly | LCOV | Codecov, Coveralls, GitHub | sf acc-transformer transform -j "coverage.json" -r "coverage.info" -f "lcovonly" |
| clover | Clover XML | Bamboo, Bitbucket, Jenkins | sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "clover" |
| json | Istanbul JSON | Istanbul/NYC, Codecov | sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "json" |
| json-summary | JSON summary | Badges, PR comments | sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "json-summary" |
| simplecov | SimpleCov JSON | Codecov, Ruby tools | sf acc-transformer transform -j "coverage.json" -r "coverage.json" -f "simplecov" |
| opencover | OpenCover XML | Azure DevOps, VS, Codecov | sf acc-transformer transform -j "coverage.json" -r "coverage.xml" -f "opencover" |
| html | HTML report | Browsers, CI artifacts | sf acc-transformer transform -j "coverage.json" -r "coverage.html" -f "html" |
CI/CD Integration
Codecov
Cobertura is a good default. CLI upload:
sf apex run test --code-coverage --output-dir "coverage"
sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
codecovcli upload-process --file coverage.xmlGitHub Action:
name: Salesforce CI with Codecov
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli
- name: Install Coverage Transformer Plugin
run: sf plugins install apex-code-coverage-transformer
- name: Authenticate to Salesforce
run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
- name: Run Apex Tests
run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
- name: Transform Coverage to Cobertura
run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
files: ./coverage.xml
flags: apex
token: ${{ secrets.CODECOV_TOKEN }}SonarQube
Use the sonar format and upload using SonarQube's generic test coverage report formatter, sonar.coverageReportPaths.
Scanner:
sf apex run test --code-coverage --output-dir "coverage"
sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar"
sonar-scanner \
-Dsonar.projectKey=your-project-key \
-Dsonar.sources=force-app \
-Dsonar.tests=force-app \
-Dsonar.test.inclusions=**/*Test.cls \
-Dsonar.coverageReportPaths=coverage.xml \
-Dsonar.host.url=https://sonarqube.example.com \
-Dsonar.login=$SONAR_TOKENSonarCloud GitHub Action:
name: SonarCloud Analysis
on: [push, pull_request]
jobs:
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli
- name: Install Coverage Transformer Plugin
run: sf plugins install apex-code-coverage-transformer
- name: Authenticate to Salesforce
run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
- name: Run Apex Tests
run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
- name: Transform Coverage to Sonar Format
run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "sonar"
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.projectKey=your-project-key
-Dsonar.organization=your-org
-Dsonar.sources=force-app
-Dsonar.tests=force-app
-Dsonar.test.inclusions=**/*Test.cls
-Dsonar.coverageReportPaths=coverage.xmlGitHub Actions
Use Cobertura (or LCOV) with a coverage summary action:
name: Salesforce CI with Coverage Report
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli
- name: Install Coverage Transformer Plugin
run: sf plugins install apex-code-coverage-transformer
- name: Authenticate to Salesforce
run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
- name: Run Apex Tests
run: sf apex run test --code-coverage --output-dir coverage --target-org ci-org
- name: Transform Coverage to Cobertura
run: sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
- name: Code Coverage Report
uses: irongut/[email protected]
with:
filename: coverage.xml
badge: true
format: markdown
output: both
- name: Add Coverage PR Comment
uses: marocchino/sticky-pull-request-comment@v2
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.mdGitLab CI
Cobertura for coverage in the UI:
stages:
- test
apex-tests:
stage: test
image: node:20
before_script:
- npm install -g @salesforce/cli
- sf plugins install apex-code-coverage-transformer
- echo $SFDX_AUTH_URL | sf org login sfdx-url --sfdx-url-stdin --alias ci-org
script:
- sf apex run test --code-coverage --output-dir coverage --target-org ci-org
- sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -r "coverage.xml" -f "cobertura"
coverage: '/TOTAL.*\s+(\d+%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
paths:
- coverage/
expire_in: 30 daysAutomatic Transformation (Hook)
Create .apexcodecovtransformer.config.json in the project root to transform coverage automatically after:
sf project deploy [start|validate|report|resume]sf apex run testsf apex get testsf hardis project deploy smart(if sfdx-hardis installed andCOVERAGE_FORMATTER_JSON=true)sf hardis org test apex(if sfdx-hardis installed)
Sample configs: Salesforce CLI, SFDX Hardis.
| Key | Required | Description |
| -------------------------- | ---------- | -------------------------------------------------------- |
| deployCoverageJsonPath | For deploy | Path to deploy coverage JSON. |
| testCoverageJsonPath | For test | Path to test coverage JSON. |
| outputReportPath | No | Output path (default: coverage.[xml/info/json] by format). |
| format | No | Format(s), comma-separated (default: sonar). |
| ignorePackageDirectories | No | Comma-separated package directories to ignore. |
Troubleshooting
File not in package directory — File is omitted from the report and a warning is shown:
Warning: The file name AccountTrigger was not found in any package directory.No files matched — Report will be empty:
Warning: None of the files listed in the coverage JSON were processed. The coverage report will be empty.Unknown JSON structure — Input is not from deploy or test coverage:
Error (1): The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.Missing project config — Run from a directory that has (or has a parent with) sfdx-project.json:
Error (1): sfdx-project.json not found in any parent directory.Missing package directory — A path in sfdx-project.json does not exist:
Error (1): ENOENT: no such file or directory: {packageDir}Contributing
Contributions are welcome. See CONTRIBUTING.md for setup, testing, and how to add new coverage formats.
License
MIT. See LICENSE.
