Configure SonarQube quality gates and custom rules for automated code quality enforcement

Intermediate 45 min Apr 20, 2026 107 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up SonarQube quality gates with custom conditions, create language-specific rules, and integrate automated quality enforcement into CI/CD pipelines for continuous code quality monitoring.

Prerequisites

  • SonarQube server running
  • Administrative access to SonarQube
  • CI/CD pipeline access
  • Basic understanding of code quality metrics

What this solves

SonarQube quality gates enforce code quality standards by blocking deployments when code doesn't meet defined criteria. This tutorial shows you how to configure custom quality gates with specific conditions, create custom rules for different programming languages, and integrate quality enforcement into CI/CD pipelines. You'll also set up monitoring and alerting for code quality metrics.

Step-by-step configuration

Install SonarQube scanner CLI tools

Install the SonarQube scanner on your development and CI/CD machines to analyze code and send results to your SonarQube server.

wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
sudo unzip sonar-scanner-cli-5.0.1.3006-linux.zip -d /opt/
sudo mv /opt/sonar-scanner-5.0.1.3006-linux /opt/sonar-scanner
sudo ln -s /opt/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
sudo unzip sonar-scanner-cli-5.0.1.3006-linux.zip -d /opt/
sudo mv /opt/sonar-scanner-5.0.1.3006-linux /opt/sonar-scanner
sudo ln -s /opt/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner

Configure SonarQube scanner properties

Set up the scanner configuration to connect to your SonarQube server and define project settings.

# SonarQube server configuration
sonar.host.url=https://sonarqube.example.com
sonar.login=your-auth-token

Global analysis properties

sonar.sourceEncoding=UTF-8 sonar.exclusions=/test/,/*.spec.js,/node_modules/,/vendor/** sonar.coverage.exclusions=/test/,**/*.spec.js

Language-specific settings

sonar.java.binaries=target/classes sonar.javascript.lcov.reportPaths=coverage/lcov.info sonar.python.coverage.reportPaths=coverage.xml

Create custom quality gate

Access your SonarQube web interface and create a custom quality gate with specific conditions for your projects.

Note: Log into SonarQube as an administrator to access quality gate configuration.

Navigate to Quality Gates > Create and configure the following conditions:

# Coverage conditions
Coverage on New Code: is less than 80%
Line Coverage on New Code: is less than 80%
Branch Coverage on New Code: is less than 70%

Reliability conditions

Reliability Rating on New Code: is worse than A Bugs on New Code: is greater than 0

Security conditions

Security Rating on New Code: is worse than A Security Hotspots Reviewed on New Code: is less than 100% Vulnerabilities on New Code: is greater than 0

Maintainability conditions

Maintainability Rating on New Code: is worse than A Code Smells on New Code: is greater than 5 Technical Debt on New Code: is greater than 1h

Duplications

Duplicated Lines (%) on New Code: is greater than 3%

Configure custom rules for Java

Create custom rules specific to Java development standards in your organization.

# Create custom rule profile

Navigate to Rules > Create Custom Rule

Select Java language and template

Example: Method complexity rule

Rule Key: custom-java-method-complexity Name: Method Cyclomatic Complexity Description: Methods should not be too complex Type: Code Smell Severity: Major Template: Avoid too complex method Parameters: - Complexity Threshold: 10 - Message: Method complexity is {0}, max allowed is {1}

Example: Class naming convention

Rule Key: custom-java-class-naming Name: Class Naming Convention Description: Classes must follow naming standards Type: Code Smell Severity: Minor Template: Track usage of a class Parameters: - Pattern: ^[A-Z][a-zA-Z0-9]*$ - Message: Class name should be PascalCase

Configure custom rules for JavaScript/TypeScript

Set up JavaScript and TypeScript specific rules for modern development practices.

# ESLint integration rules

Navigate to Rules > JavaScript/TypeScript

Console usage rule

Rule Key: custom-js-no-console Name: No Console Statements Description: Console statements should not be used in production Type: Code Smell Severity: Minor ESLint Rule: no-console

Function complexity rule

Rule Key: custom-js-function-complexity Name: Function Complexity Limit Description: Functions should not exceed complexity threshold Type: Code Smell Severity: Major ESLint Rule: complexity Parameters: - max: 8

Unused variables rule

Rule Key: custom-js-no-unused-vars Name: No Unused Variables Description: Variables should be used once declared Type: Bug Severity: Major ESLint Rule: no-unused-vars Parameters: - vars: all - args: after-used

Configure custom rules for Python

Create Python-specific rules for code quality and security best practices.

# Python custom rules using Pylint integration

Navigate to Rules > Python

Function length rule

Rule Key: custom-python-function-length Name: Function Length Limit Description: Functions should not exceed line limit Type: Code Smell Severity: Major Pylint Rule: too-many-lines Parameters: - max-lines: 50

Import organization rule

Rule Key: custom-python-import-order Name: Import Order Standard Description: Imports should follow PEP8 conventions Type: Code Smell Severity: Minor Pylint Rule: wrong-import-order

Security rule for hardcoded passwords

Rule Key: custom-python-hardcoded-password Name: No Hardcoded Passwords Description: Passwords should not be hardcoded Type: Vulnerability Severity: Blocker Bandit Rule: B105

Create quality profile with custom rules

Combine built-in and custom rules into a quality profile that applies to your projects.

# Create new quality profile

Navigate to Quality Profiles > Create

Profile Name: Enterprise Standards Language: Java Parent Profile: Sonar way

Activate custom rules

Activated Rules: - All Sonar way rules (inherited) - custom-java-method-complexity (Major) - custom-java-class-naming (Minor) - Unused private method (Major) - Magic numbers should not be used (Minor) - Methods should not have too many parameters (Major)

Severity adjustments

Rule Modifications: - Cognitive Complexity: Blocker (was Major) - Public classes should have package info: Info (was Minor) - Missing JavaDoc: Minor (was Major)

Configure project-specific analysis settings

Set up project configuration file for automated analysis with your custom rules and quality gate.

# Project identification
sonar.projectKey=my-application
sonar.projectName=My Application
sonar.projectVersion=1.0

Source configuration

sonar.sources=src/main sonar.tests=src/test sonar.java.source=17 sonar.java.target=17

Quality profile assignment

sonar.profile=Enterprise Standards

Quality gate assignment

sonar.qualitygate=Enterprise Quality Gate

Coverage settings

sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml sonar.junit.reportPaths=target/surefire-reports

Analysis parameters

sonar.analysis.mode=publish sonar.scm.provider=git sonar.links.homepage=https://github.com/company/my-application sonar.links.ci=https://jenkins.company.com/job/my-application

Set up GitLab CI integration

Configure GitLab CI pipeline to run SonarQube analysis and enforce quality gate status.

stages:
  - test
  - quality-check
  - deploy

variables:
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
  GIT_DEPTH: "0"

sonarqube-check:
  stage: quality-check
  image: sonarsource/sonar-scanner-cli:latest
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - sonar-scanner
      -Dsonar.projectKey=${CI_PROJECT_NAME}
      -Dsonar.sources=.
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.login=${SONAR_TOKEN}
      -Dsonar.gitlab.project_id=${CI_PROJECT_ID}
      -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA}
      -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME}
  only:
    - merge_requests
    - main
    - develop

quality-gate-check:
  stage: quality-check
  image: curlimages/curl:latest
  script:
    - |
      # Wait for quality gate result
      sleep 30
      TASK_ID=$(curl -s -u ${SONAR_TOKEN}: "${SONAR_HOST_URL}/api/ce/component?component=${CI_PROJECT_NAME}" | jq -r '.queue[0].id // .current.id')
      
      # Check task status
      while true; do
        STATUS=$(curl -s -u ${SONAR_TOKEN}: "${SONAR_HOST_URL}/api/ce/task?id=${TASK_ID}" | jq -r '.task.status')
        if [ "$STATUS" = "SUCCESS" ]; then
          break
        elif [ "$STATUS" = "FAILED" ]; then
          echo "SonarQube analysis failed"
          exit 1
        fi
        sleep 10
      done
      
      # Check quality gate status
      QG_STATUS=$(curl -s -u ${SONAR_TOKEN}: "${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=${CI_PROJECT_NAME}" | jq -r '.projectStatus.status')
      if [ "$QG_STATUS" != "OK" ]; then
        echo "Quality gate failed: $QG_STATUS"
        exit 1
      fi
      echo "Quality gate passed"
  dependencies:
    - sonarqube-check
  only:
    - merge_requests
    - main
    - develop

Configure Jenkins integration

Set up Jenkins pipeline for SonarQube analysis with quality gate enforcement.

pipeline {
    agent any
    
    tools {
        maven 'Maven-3.9'
        jdk 'JDK-17'
    }
    
    environment {
        SONAR_TOKEN = credentials('sonar-token')
        SONAR_HOST_URL = 'https://sonarqube.example.com'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Build and Test') {
            steps {
                sh 'mvn clean compile test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                    publishCoverage adapters: [jacocoAdapter('target/site/jacoco/jacoco.xml')]
                }
            }
        }
        
        stage('SonarQube Analysis') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh '''
                        mvn sonar:sonar \
                          -Dsonar.projectKey=${JOB_NAME} \
                          -Dsonar.host.url=${SONAR_HOST_URL} \
                          -Dsonar.login=${SONAR_TOKEN} \
                          -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
                    '''
                }
            }
        }
        
        stage('Quality Gate') {
            steps {
                timeout(time: 5, unit: 'MINUTES') {
                    waitForQualityGate abortPipeline: true
                }
            }
        }
        
        stage('Deploy') {
            when {
                anyOf {
                    branch 'main'
                    branch 'develop'
                }
            }
            steps {
                echo 'Deploying application...'
                // Add deployment steps here
            }
        }
    }
    
    post {
        failure {
            emailext (
                subject: "Quality Gate Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
                body: "Quality gate failed for ${env.BUILD_URL}",
                to: "${env.CHANGE_AUTHOR_EMAIL}"
            )
        }
    }
}

Set up webhook notifications

Configure SonarQube webhooks to send quality gate results to external systems like Slack or Microsoft Teams.

# Navigate to Administration > Configuration > Webhooks

Create webhook for Slack integration

Name: Slack Quality Gate Notifications URL: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK Secret: your-webhook-secret

Webhook payload template (JSON)

{ "text": "Quality Gate Status: {{status}}", "attachments": [ { "color": "{{#eq status 'OK'}}good{{else}}danger{{/eq}}", "fields": [ { "title": "Project", "value": "{{project.name}}", "short": true }, { "title": "Branch", "value": "{{branch.name}}", "short": true }, { "title": "Quality Gate", "value": "{{qualityGate.name}}", "short": true }, { "title": "Analysis", "value": "<{{serverUrl}}/dashboard?id={{project.key}}|View Details>", "short": true } ] } ] }

Configure quality gate metrics monitoring

Set up monitoring dashboards and alerts for code quality metrics across projects.

# Install SonarQube Prometheus exporter
wget https://github.com/dmeiners88/sonarqube-prometheus-exporter/releases/download/v1.3.0/sonar-exporter-1.3.0.jar

Create systemd service

sudo tee /etc/systemd/system/sonar-exporter.service << EOF [Unit] Description=SonarQube Prometheus Exporter After=network.target [Service] Type=simple User=sonar-exporter Group=sonar-exporter ExecStart=/usr/bin/java -jar /opt/sonar-exporter/sonar-exporter-1.3.0.jar \ --sonar.host.url=https://sonarqube.example.com \ --sonar.login=your-monitoring-token \ --web.listen-address=:9765 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF

Create user and directories

sudo useradd -r -s /bin/false sonar-exporter sudo mkdir -p /opt/sonar-exporter sudo mv sonar-exporter-1.3.0.jar /opt/sonar-exporter/ sudo chown -R sonar-exporter:sonar-exporter /opt/sonar-exporter

Start service

sudo systemctl enable --now sonar-exporter

Create Grafana dashboard for code quality

Build comprehensive dashboards to visualize code quality trends and quality gate status across projects.

{
  "dashboard": {
    "id": null,
    "title": "SonarQube Code Quality Dashboard",
    "tags": ["sonarqube", "quality"],
    "timezone": "browser",
    "panels": [
      {
        "title": "Quality Gate Status",
        "type": "stat",
        "targets": [
          {
            "expr": "sonar_quality_gate_status",
            "legendFormat": "{{project_name}}"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "mappings": [
              {"options": {"0": {"text": "ERROR", "color": "red"}}},
              {"options": {"1": {"text": "OK", "color": "green"}}}
            ]
          }
        }
      },
      {
        "title": "Code Coverage Trend",
        "type": "graph",
        "targets": [
          {
            "expr": "sonar_coverage_line_coverage",
            "legendFormat": "{{project_name}}"
          }
        ]
      },
      {
        "title": "Technical Debt",
        "type": "graph",
        "targets": [
          {
            "expr": "sonar_technical_debt_minutes",
            "legendFormat": "{{project_name}}"
          }
        ]
      },
      {
        "title": "Security Vulnerabilities",
        "type": "table",
        "targets": [
          {
            "expr": "sonar_vulnerabilities{severity=~\"BLOCKER|CRITICAL|MAJOR\"}",
            "format": "table",
            "instant": true
          }
        ]
      }
    ]
  }
}

Verify your setup

# Test SonarQube scanner
sonar-scanner --version

Run analysis on sample project

cd /path/to/your/project sonar-scanner

Check quality gate API

curl -u your-token: "https://sonarqube.example.com/api/qualitygates/project_status?projectKey=your-project"

Verify webhook delivery

curl -X POST https://sonarqube.example.com/api/webhooks/deliveries \ -u your-token: \ -H "Content-Type: application/json"

Test Prometheus exporter

curl http://localhost:9765/metrics | grep sonar

Common issues

SymptomCauseFix
Quality gate always passesConditions not properly configuredCheck condition thresholds in Quality Gates > Your Gate > Conditions
Custom rules not appliedQuality profile not assigned to projectGo to Project Settings > Quality Profiles and assign custom profile
Analysis fails with permission errorScanner token lacks analysis permissionsGenerate new token with Execute Analysis permission in SonarQube
Coverage reports not foundIncorrect coverage file pathsVerify coverage report paths match actual file locations
Webhook not triggeredWebhook URL unreachable or invalidTest webhook URL manually and check SonarQube logs
CI pipeline hangs on quality gateQuality gate check timeoutIncrease timeout or check SonarQube background task queue

Next steps

Running this in production?

Want this handled for you? Setting up SonarQube quality gates once is straightforward. Keeping them tuned, monitored, and integrated across multiple environments and CI/CD pipelines is the harder part. See how we run infrastructure like this for European development teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.