SonarQube GitLab CI Integration

GitLab runs your build in a pipeline defined by a single file. Adding a SonarQube job to that file analyzes every push automatically. Developers see results without leaving their normal workflow, and weak code stops before it merges.

The Conveyor Belt Picture

 git push
    │
    ▼
 ┌────────┐   ┌────────┐   ┌─────────────┐   ┌────────┐
 │ build  │──►│  test  │──►│ sonar scan  │──►│ deploy │
 └────────┘   └────────┘   └──────┬──────┘   └────────┘
                                  │ report
                                  ▼
                          SonarQube Server
                          (pass or fail)

The scan job sits between testing and delivery like a checkpoint guard.

Preparation

  1. Create the project in SonarQube and note its project key.
  2. Generate an analysis token in SonarQube.
  3. Open the GitLab project and go to Settings, then CI/CD, then Variables.
  4. Add a variable named SONAR_TOKEN with the token value. Mark it as masked.
  5. Add a variable named SONAR_HOST_URL with the server address.

Variables keep secrets out of the repository.

The Pipeline File

Add this job to .gitlab-ci.yml.

stages:
  - test
  - quality

sonarqube-check:
  stage: quality
  image:
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
    GIT_DEPTH: "0"
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - sonar-scanner -Dsonar.projectKey=shop-backend -Dsonar.qualitygate.wait=true
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Line by Line

Image

The official scanner image brings the tool without any installation. The empty entrypoint lets GitLab run its own commands inside the container.

GIT_DEPTH

A value of 0 downloads the full history. SonarQube needs history to assign new code correctly and to blame the right authors.

Cache

Scanner downloads land in a cache folder, so later runs start faster.

Quality Gate Wait

The wait flag turns a failed gate into a failed job. A red job blocks the merge when you require passing pipelines.

Rules

The job runs on merge requests and on the default branch. Pipelines for other branches skip it and save minutes.

Passing Test Coverage

Run tests in an earlier job and share the report as an artifact. The scan job reads the file through a property.

test:
  stage: test
  script:
    - pytest --cov --cov-report=xml
  artifacts:
    paths:
      - coverage.xml

Add -Dsonar.python.coverage.reportPaths=coverage.xml to the scanner command for Python projects. Other languages use their own property names.

Maven Projects

Java teams can skip the scanner image and call Maven directly.

script:
  - mvn verify sonar:sonar -Dsonar.projectKey=shop-backend

Use a Maven image for the job and keep the same variables.

Merge Request Feedback

Branch and merge request analysis belongs to the Developer Edition and above. These editions comment results directly in the merge request after you configure the GitLab connection in the project settings. The Community Build analyzes the main branch only.

Troubleshooting

SymptomLikely Cause
Not authorizedWrong token or unmasked typo in the variable
Cannot reach serverThe runner cannot access SONAR_HOST_URL
Wrong blame dataShallow clone, so set GIT_DEPTH to 0
Pipeline passes but gate failsMissing wait flag

Good Habits

  • Store tokens in masked variables only.
  • Use protected variables for production branches.
  • Keep the scan job fast by caching and excluding generated files.
  • Check the Background Tasks page when a job waits too long.

A Walkthrough

A developer opens a merge request. GitLab starts the pipeline, and the build and test jobs finish in four minutes. The sonarqube-check job downloads the cached scanner, analyzes the code, and uploads the report. SonarQube processes the report and answers pass or fail. The job turns green or red accordingly, and the reviewer sees the result on the merge request page before reading a single line of code.

Self-Managed and Cloud Runners

Runners that live inside your company network reach a private SonarQube server easily. Cloud-hosted runners need a public address or a secure tunnel. Confirm the connection with a simple test job that calls the status endpoint before you add the full scan.

Quick Recap

Add two variables, add one job, fetch full history, and let the quality gate decide. Every merge request now meets the same quality bar.