Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~15 min· topic 5 of 5

Topic 1.5

Code Quality Gates: Linting, Static Analysis & Coverage

In one line

Quality gates are automatic checks that a change must pass besides tests: formatting and linting (consistent style, simple mistakes), static analysis (bugs and code smells found without running the code, like SpotBugs, Error Prone, or SonarQube), and coverage thresholds on new code. Run fast ones on every pull request, fail on new problems rather than old ones, and keep the rules few and meaningful so the gate is respected rather than bypassed.

0/5 · 0%

Think of it like this

An editor checking a newspaper article before printing. Spelling and layout first (formatting and linting), then facts that look wrong (static analysis), and a rule that every new claim has a source (coverage on new code).

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Quality gate
An automatic pass/fail check on code quality that a change must meet.
Linter
A tool that checks code for style problems and simple mistakes.
Static analysis
Finding likely bugs and problems by examining code without running it.
Code coverage
The share of code lines or branches executed by tests.
New code period
The changes being reviewed, as opposed to the whole existing codebase.
SonarQube
A platform that analyses code quality, coverage, and security issues and enforces quality gates.

Step by step

01Formatting and static checks in the build

Tiffin adds Spotless (formatting) and SpotBugs (likely bugs) to the Maven build. spotless:check fails CI if code isn't formatted, and developers run spotless:apply locally to fix it.

pom.xml (plugins excerpt)whole filexml
<plugin>
  <groupId>com.diffplug.spotless</groupId>
  <artifactId>spotless-maven-plugin</artifactId>
  <version>2.44.0</version>
  <configuration>
    <java><palantirJavaFormat/></java>
  </configuration>
</plugin>
<plugin>
  <groupId>com.github.spotbugs</groupId>
  <artifactId>spotbugs-maven-plugin</artifactId>
  <version>4.8.6.6</version>
  <configuration><failOnError>true</failOnError></configuration>
</plugin>
<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.12</version>
  <executions>
    <execution><goals><goal>prepare-agent</goal><goal>report</goal></goals></execution>
  </executions>
</plugin>
terminal
$ ./mvnw -B -ntp spotless:check spotbugs:check
── expected output ──
[ERROR] Failed to execute goal com.diffplug.spotless:spotless-maven-plugin:2.44.0:check (default-cli) on project tiffin-web: The following files had format violations:
[ERROR] src/main/java/in/tiffin/coupons/CouponService.java
[ERROR] @@ -14,7 +14,7 @@
[ERROR] - if(coupon==null){return 0;}
[ERROR] + if (coupon == null) {
[ERROR] Run 'mvn spotless:apply' to fix these violations.

02A quality gate on new code

SonarCloud analyses each pull request and comments with the result. The gate fails only for problems in the PR's own changes, so a legacy class with old warnings doesn't block unrelated work.

.github/workflows/ci.yml (sonar job)whole fileyaml
sonar:
  needs: unit-tests
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with: { fetch-depth: 0 }          # full history for new-code detection
    - uses: actions/setup-java@v4
      with: { distribution: temurin, java-version: "21", cache: maven }
    - run: ./mvnw -B -ntp verify sonar:sonar -Dsonar.qualitygate.wait=true
      env:
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
A quality gate on new codediagram
Rendering diagram…

03Reading the gate result

Arjun's PR adds a method with a possible null dereference and no tests. The gate explains exactly what to fix.

terminal
$ gh pr view 223 --comments | grep -A5 'Quality Gate'
── expected output ──
Quality Gate failed
Failed conditions
1 New Bug (required ≤ 0)
48.0% Coverage on New Code (required ≥ 80%)
See analysis details on SonarCloud

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

A gate on the whole codebase

The team turns on a gate requiring 80% coverage overall, and the legacy codebase is at 52%.

terminal
$ gh pr list --state open --json number,title --jq 'length'
── what you'll see ──
41
# every PR fails the gate, people start adding @Generated annotations and trivial tests to pass it

Myth vs fact

Myth

High coverage means good tests.

Fact

Coverage shows lines that ran, not whether results were checked. A test with no assertions can reach 100%. Use coverage to find untested code, not to prove quality.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Add formatting to a pre-commit hook (Git course, Topic 4.4) and run the same check in CI. Developers fix style before pushing, and CI catches anyone who skipped the hook.

Remember this

  1. 1

    Formatting: tools like Spotless (google-java-format or Palantir) or Prettier make style automatic, so reviews stop discussing spaces and braces. CI checks, developers' IDEs or hooks fix.

  2. 2

    Linting and static analysis: Checkstyle (style rules), PMD, SpotBugs, and Error Prone (likely bugs: null dereferences, wrong equals, resource leaks) analyse code without running it.

  3. 3

    SonarQube / SonarCloud: combines analysis, coverage, duplication, and security hotspots, with a quality gate on new code (for example: no new bugs, coverage on new code at least 80%).

  4. 4

    Coverage (JaCoCo): shows which lines tests execute. Useful as a trend and as a floor for new code, misleading as a single target number for the whole codebase.

  5. 5

    Clean as you code: gate on new or changed code only, so legacy issues don't block every PR while new code stays clean.

  6. 6

    Keep gates fast and few. Every rule that produces noise trains people to ignore or suppress warnings.

Explain it without notes

01

Why gate on new code instead of the whole codebase?

02

What can static analysis find that tests miss?

Practice

01

Add a formatting check and a static analysis check to a project's CI.

02

Set up a coverage report and find the least-tested package.

Trade-offs

  • ↔

    Gates catch problems early and keep standards consistent, but noisy rules slow teams and get bypassed. A few high-signal checks beat many low-value ones.

Done when you can

  • CI checks formatting and static analysis on every PR.

  • Quality gates apply to new code.

  • I use coverage to find untested code, not as the goal.