Testland
Browse all skills & agents

sonarqube-quality-perspective

Run SonarQube/SonarCloud against production code to surface Code Smells, Bugs, and Maintainability ratings - the quality lens (cross-ref qa-sast for the Vulnerability/Hotspot lens). Production-only scope via sonar.exclusions; test code is owned by qa-test-review.

sonarqube-quality-perspective

SonarQube classifies issues across three software qualities - Reliability, Maintainability, Security - and four Clean Code attributes (Consistent, Intentional, Adaptable, Responsible) per the SonarSource docs (see Issues introduction). qa-sast's sonarqube-rules skill covers the Security lens; this skill covers the Reliability + Maintainability lens for production code.

When to use

  • A pull request touches production code and you want Bug/Code-Smell metrics scoped to the diff (not test files).
  • Pre-merge Quality Gate enforcement on the Sonar Way default (no new issues; new-code coverage ≥80%; new-code duplication ≤3% - per Sonar Way QG).
  • Legacy codebase entering Sonar adoption - focus on new code only to avoid baseline-debt theater.

Step 1 - Install scanner

StackScanner
Mavensonar-maven-plugin (mvn sonar:sonar)
Gradleorg.sonarqube plugin (./gradlew sonar)
.NETdotnet-sonarscanner
Anything elsesonar-scanner CLI

See the SonarQube docs sitemap for per-build-tool installation.

Step 2 - Scope to production code

Add to sonar-project.properties:

sonar.projectKey=acme.platform
sonar.sources=src
sonar.tests=tests,src/**/*.test.ts
sonar.exclusions=**/*.generated.*,**/migrations/**,**/vendor/**
sonar.test.inclusions=**/*.test.ts,**/*.spec.ts,tests/**
sonar.coverage.exclusions=**/*.generated.*,**/main.ts

Why separate sonar.tests vs sonar.sources: test code has different quality expectations (long names, deliberate duplication for clarity, Arrange-Act-Assert patterns). Lumping them into one scope produces noise. Test code is reviewed by qa-test-review skills/agents instead.

Step 3 - Run scan

# Local development scan against a SonarQube server
sonar-scanner \
  -Dsonar.host.url=https://sonar.internal \
  -Dsonar.token=$SONAR_TOKEN

# CI scan with PR analysis (branch + PR decoration)
sonar-scanner \
  -Dsonar.pullrequest.key=$PR_NUMBER \
  -Dsonar.pullrequest.branch=$PR_BRANCH \
  -Dsonar.pullrequest.base=main

The scanner uploads to the configured server; results stream to the project dashboard.

Step 4 - Read the dashboard

MetricWhat it meansSonar Way default
New BugsReliability issues introduced in PR0
New Code SmellsMaintainability issues introduced in PR0
New Coverage% new lines covered by tests≥ 80%
New Duplication% new lines duplicated≤ 3%
Maintainability Rating (new code)A - E based on debt ratioA
Reliability Rating (new code)A - E based on bug densityA

Per Sonar Way QG: any condition fail blocks merge.

Step 5 - Quality Gate as CI gate

# GitHub Actions
- name: SonarQube Scan
  uses: SonarSource/sonarqube-scan-action@v3
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: SonarQube Quality Gate Check
  uses: SonarSource/sonarqube-quality-gate-action@v1
  timeout-minutes: 5
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

The quality-gate-action polls the server until the gate result lands and fails the build if it's RED.

Anti-patterns

Anti-patternWhy it failsFix
Scan whole repo without sonar.tests separationTest conventions flagged as smells; team disables SonarSplit sonar.sources / sonar.tests (Step 2)
Apply gate to overall code, not new codeLegacy debt blocks all PRs foreverUse new-code-period gate (Sonar Way default)
Mix this with qa-sast's sonarqube-rules settingsTwo skills mutating same sonar-project.propertiesThis skill owns Reliability+Maintainability; qa-sast/sonarqube-rules owns Security profile
Lower gate to merge pre-existing failuresGate becomes meaninglessUse "Wont Fix" / "Accepted" issue resolution + scope-exclusion comment instead
Run after merge onlyNo PR decoration; hard to reviewRun on PR with sonar.pullrequest.* flags (Step 3)

Limitations

  • Sonar Way thresholds are tuned for greenfield + healthy codebases. Brownfield rollout: keep gate but mark all pre-existing as "Accepted" with re-review date + waiver template (Reason: + Approved-by: + Re-review-date: + expires:).
  • Self-hosted SonarQube (Community) does not include MQR severity granularity; SonarCloud + Enterprise do.

References