Run SonarQube/SonarCloud against production code to surface Code Smells, Bugs, and Maintainability ratings - the maintainability lens rather than the security lens. Production-only scope via sonar.exclusions; test code is reviewed separately. Use when a team wants maintainability and technical-debt ratings gating PRs, or when an existing SonarQube project reports numbers nobody has tied to a quality gate.
Installs into .claude/skills of the current project.
Are you the author of Sonarqube Maintainability Gate?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/testland-sonarqube-maintainability-gate)
---
name: sonarqube-maintainability-gate
description: "Run SonarQube/SonarCloud against production code to surface Code Smells, Bugs, and Maintainability ratings - the maintainability lens rather than the security lens. Production-only scope via sonar.exclusions; test code is reviewed separately. Use when a team wants maintainability and technical-debt ratings gating PRs, or when an existing SonarQube project reports numbers nobody has tied to a quality gate."
metadata:
keywords: "sonarqube, sonarcloud, code-smell, maintainability, quality-gate"
version: "1.1.6"
---
# sonarqube-maintainability-gate
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-security-scanning'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
| Stack | Scanner |
|---|---|
| Maven | `sonar-maven-plugin` (`mvn sonar:sonar`) |
| Gradle | `org.sonarqube` plugin (`./gradlew sonar`) |
| .NET | `dotnet-sonarscanner` |
| Anything else | `sonar-scanner` CLI |
See the [SonarQube docs sitemap] for per-build-tool installation.
## Step 2 - Scope to production code
Add to `sonar-project.properties`:
```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 separately.
## Step 3 - Run scan
```bash
# 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
| Metric | What it means | Sonar Way default |
|---|---|---|
| New Bugs | Reliability issues introduced in PR | 0 |
| New Code Smells | Maintainability issues introduced in PR | 0 |
| New Coverage | % new lines covered by tests | ≥ 80% |
| New Duplication | % new lines duplicated | ≤ 3% |
| Maintainability Rating (new code) | A - E based on debt ratio | A |
| Reliability Rating (new code) | A - E based on bug density | A |
Per [Sonar Way QG]: any condition fail blocks merge.
## Step 5 - Quality Gate as CI gate
```yaml
# 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-pattern | Why it fails | Fix |
|---|---|---|
| Scan whole repo without `sonar.tests` separation | Test conventions flagged as smells; team disables Sonar | Split `sonar.sources` / `sonar.tests` (Step 2) |
| Apply gate to overall code, not new code | Legacy debt blocks all PRs forever | Use new-code-period gate (Sonar Way default) |
| Mix this with the `sonarqube-rules` security settings | Two skills mutating same `sonar-project.properties` | This skill owns Reliability+Maintainability; `sonarqube-rules` owns the Security profile |
| Lower gate to merge pre-existing failures | Gate becomes meaningless | Use "Wont Fix" / "Accepted" issue resolution + scope-exclusion comment instead |
| Run after merge only | No PR decoration; hard to review | Run 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
- [Issues introduction] - Clean Code attributes, software qualities,
Sonar Way Quality Gate defaults
- [SonarQube docs sitemap] - per-build-tool scanner setup, current
config options
[Issues introduction]: https://docs.sonarsource.com/sonarqube-server/user-guide/issues/introduction.md
[Sonar Way QG]: https://docs.sonarsource.com/sonarqube-server/user-guide/issues/introduction.md
[SonarQube docs sitemap]: https://docs.sonarsource.com/sitemap.md