sf-cat
v1.4.0
Published
Transform Salesforce Code Analyzer reports into external code quality formats (SonarQube, SARIF, CodeClimate / GitLab Code Quality, JUnit XML, GitHub Actions workflow commands).
Maintainers
Readme
sf-cat
A Salesforce CLI plugin that converts Salesforce Code Analyzer output into formats consumable by external code quality platforms — SonarQube, GitHub Code Scanning, Azure DevOps, GitLab, and any other SARIF-aware tool.
- Install
- How It Works
- Quick Start
- Failing the Build on High-Severity Findings
- Path Normalization
- Column Data Handling
- Command Reference
- Issues
- License
Install
sf plugins install sf-cat@latestRequires Salesforce CLI with Code Analyzer v5 (sf code-analyzer).
How It Works
Salesforce Code Analyzer scans Apex, Visualforce, Flows, and Lightning components using PMD, ESLint, RetireJS, and Salesforce Graph Engine. Its JSON output isn't directly compatible with any external code quality platform.
sf-cat is a single conversion step between Code Analyzer and your platform of choice:
sf code-analyzer run → JSON → sf cat transform → SonarQube / SARIF / CodeClimate / JUnit / GitHubSupported output formats:
| Format | Use with |
| ------------- | ---------------------------------------------------------------------------- |
| sonar | SonarQube / SonarCloud generic issue data |
| sarif | GitHub Code Scanning, Azure DevOps, GitLab, Qodana |
| codeclimate | GitLab Code Quality, CodeClimate engines |
| junit | Jenkins, GitHub Actions, GitLab, Azure DevOps, CircleCI, Bitbucket Pipelines |
| github | GitHub PR inline annotations (no GHAS required) |
Quick Start
Step 1 — Run Code Analyzer and save JSON output:
sf code-analyzer run --workspace "./force-app/main/default/" --rule-selector Recommended --output-file "analyzer.json"Note:
sf code-analyzer runuses--output-file(not-f) for the output path. sf-cat uses-ffor output format — these are different flags on different commands.
Step 2 — Convert with sf-cat:
sf cat transform -i "analyzer.json" -f <format> -o "results.<ext>"Platform-specific examples below.
SonarQube
sf cat transform -i "analyzer.json" -o "sonar.json"sonar is the default format, so -f sonar is optional.
In sonar-project.properties:
sonar.externalIssuesReportPaths=sonar.jsonOr via CLI:
sonar-scanner -Dsonar.externalIssuesReportPaths=sonar.jsonSARIF (GitHub Code Scanning, Azure DevOps, GitLab, ...)
sf cat transform -i "analyzer.json" -f sarif -o "results.sarif"Each Code Analyzer engine (PMD, ESLint, RetireJS, SFGE, ...) is emitted as a separate SARIF run, so consumers display them as distinct tools.
Upload to GitHub Code Scanning:
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifThe same SARIF file works with Azure DevOps' SARIF extension, GitLab sast artifacts, Qodana, and any other SARIF v2.1.0–compatible tool.
CodeClimate / GitLab Code Quality
sf cat transform -i "analyzer.json" -f codeclimateDefault output path is gl-code-quality-report.json — the conventional filename for GitLab Code Quality reports. Each issue gets a stable fingerprint so GitLab deduplicates findings across pipeline runs.
GitLab CI (gitlab-ci.yml):
sf-cat:
script:
- sf code-analyzer run --workspace ./force-app/main/default/ --rule-selector Recommended --output-file analyzer.json
- sf cat transform -i analyzer.json -f codeclimate
artifacts:
reports:
codequality: gl-code-quality-report.jsonJUnit XML (Jenkins, GitHub Actions, GitLab, Azure DevOps, ...)
Use JUnit when your CI doesn't support SARIF (no GHAS, GitLab Free tier, etc.) or you want violations to appear in the standard CI test results panel.
sf cat transform -i "analyzer.json" -f junitEach Code Analyzer engine becomes a <testsuite>; each violation becomes a failing <testcase>. Default output path is junit.xml.
Jenkins:
junit 'junit.xml'GitHub Actions (via dorny/test-reporter):
- uses: dorny/test-reporter@v2
if: always()
with:
name: Salesforce Code Analyzer
path: junit.xml
reporter: java-junitGitLab CI:
artifacts:
reports:
junit: junit.xmlAzure DevOps:
- task: PublishTestResults@2
inputs:
testResultsFormat: JUnit
testResultsFiles: junit.xmlGitHub Actions workflow commands (inline PR annotations, no GHAS)
Use this when you want inline PR annotations on GitHub but don't have GitHub Advanced Security (which upload-sarif requires on private repos). The plugin prints ::error file=...,line=...::message lines to stdout; the GitHub Actions runner renders them as annotations on the PR Files Changed view automatically.
jobs:
code-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm i -g @salesforce/cli && sf plugins install sf-cat
- run: sf code-analyzer run --workspace ./force-app/main/default/ --rule-selector Recommended --output-file analyzer.json
- run: sf cat transform -i analyzer.json -f githubNo upload-sarif, no Code Scanning configuration needed — works on every GitHub plan including free private repos and self-hosted runners.
Severity → annotation level: Critical / High → error, Moderate → warning, Low / Info → notice.
Note: GitHub caps annotations at 10 errors / 10 warnings / 10 notices per workflow step and silently drops the rest. sf-cat enforces a default cap of 50 and prints a warning when violations exceed it. Use
--max-annotationsto adjust. For full results, also produce a SARIF or JUnit artifact in the same job.
Failing the Build on High-Severity Findings
--fail-on <severity> lets sf cat transform act as a CI gate. The output file is written first (so artifact uploads in later steps still see it), then the process exits with code 1 if any violation meets or exceeds the threshold.
# Fail the job if any High or Critical violations exist; still write the SARIF artifact
sf cat transform -i analyzer.json -f sarif -o results.sarif --fail-on highSeverity ranking (highest → lowest): critical → high → moderate → low → info. Default is never (no failure).
Path Normalization
Code Analyzer on CI runners often emits absolute file paths (e.g. /home/runner/work/myrepo/myrepo/force-app/main/default/classes/MyClass.cls). Most external tools — GitHub Code Scanning anchors, CodeClimate fingerprints, JUnit classname attributes — expect repo-relative paths and will silently fail to link annotations or generate inconsistent fingerprints across runs when given absolute paths.
Two flags normalize paths for every output format simultaneously:
# Strip a literal prefix
sf cat transform -i analyzer.json -f sarif --strip-prefix "/home/runner/work/myrepo/myrepo/"
# Auto-detect from sfdx-project.json (walks up from current directory)
sf cat transform -i analyzer.json -f sarif --project-relative--strip-prefix and --project-relative are mutually exclusive — use whichever matches your CI setup.
Column Data Handling
Code Analyzer sometimes reports startColumn/endColumn values that exceed the actual line length. Some external tools reject these values and fail the entire scan.
sf-cat strips all column values before output. Line-level highlighting is preserved; column data is dropped so out-of-bounds values don't cause downstream failures.
Command Reference
sf cat transform
| Flag | Short | Description |
| -------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| --input-file | -i | Path to the JSON file from Salesforce Code Analyzer (required) |
| --format | -f | Output format: sonar (default), sarif, codeclimate, junit, or github |
| --output-file | -o | Path for converted output. Defaults: output.json (sonar), output.sarif (sarif), gl-code-quality-report.json (codeclimate), junit.xml (junit), stdout (github) |
| --fail-on | | Exit non-zero when any violation is at this severity or higher: critical, high, moderate, low, info, or never (default) |
| --strip-prefix | | Strip a leading path prefix from every violation file path before formatting |
| --project-relative | | Make every violation file path relative to the SFDX project root (sfdx-project.json location) |
| --max-annotations | | Maximum annotations to emit for --format github. Default: 50. Prints a warning and truncates when total exceeds this limit. |
Examples:
sf cat transform -i "analyzer.json" -o "sonar.json"
sf cat transform -i "analyzer.json" -f sarif
sf cat transform -i "analyzer.json" -f sarif -o "results.sarif"
sf cat transform -i "analyzer.json" -f codeclimate
sf cat transform -i "analyzer.json" -f junit
sf cat transform -i "analyzer.json" -f github
sf cat transform -i "analyzer.json" --fail-on high
sf cat transform -i "analyzer.json" -f sarif --project-relative
sf cat transform -i "analyzer.json" -f sarif --strip-prefix "/home/runner/work/myrepo/myrepo/"Issues
Found a bug or have an idea? Open an issue.
