跳转至

第六章:CI/CD 集成

集成概述

将 SonarQube 集成到 CI/CD 流水线中,可以在代码合并前自动进行质量检查,确保代码质量。

Jenkins 集成

1. 安装插件

在 Jenkins 中安装 SonarQube 插件:

Manage Jenkins → Plugins → Available → SonarQube Scanner for Jenkins

2. 配置 SonarQube Server

Manage Jenkins → Configure System → SonarQube servers
# 配置项
Name: SonarQube
Server URL: http://sonarqube-server:9000
Server authentication token: squ_xxxxxxxxxxxx

3. 配置 SonarScanner

Manage Jenkins → Global Tool Configuration → SonarQube Scanner

4. Pipeline 示例

// Jenkinsfile
pipeline {
    agent any

    tools {
        maven 'Maven 3.9'
        jdk 'JDK 17'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                sh 'mvn clean compile'
            }
        }

        stage('Test') {
            steps {
                sh 'mvn test'
            }
        }

        stage('SonarQube Analysis') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh '''
                        mvn sonar:sonar \
                          -Dsonar.projectKey=${PROJECT_KEY} \
                          -Dsonar.projectName="${PROJECT_NAME}"
                    '''
                }
            }
        }

        stage('Quality Gate') {
            steps {
                timeout(time: 5, unit: 'MINUTES') {
                    waitForQualityGate abortPipeline: true
                }
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh 'mvn deploy'
            }
        }
    }
}

5. 多分支 Pipeline

// Jenkinsfile (多分支)
pipeline {
    agent any

    stages {
        stage('SonarQube') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    script {
                        if (env.CHANGE_ID) {
                            // PR 分析
                            sh """
                                mvn sonar:sonar \
                                  -Dsonar.pullrequest.key=${env.CHANGE_ID} \
                                  -Dsonar.pullrequest.branch=${env.CHANGE_TARGET} \
                                  -Dsonar.pullrequest.base=${env.CHANGE_TARGET}
                            """
                        } else {
                            // 分支分析
                            sh """
                                mvn sonar:sonar \
                                  -Dsonar.branch.name=${env.BRANCH_NAME}
                            """
                        }
                    }
                }
            }
        }
    }
}

GitLab CI 集成

1. 配置变量

在 GitLab 项目中配置 CI/CD 变量:

Settings → CI/CD → Variables

SONAR_HOST_URL: http://sonarqube-server:9000
SONAR_TOKEN: squ_xxxxxxxxxxxx

2. 基本配置

# .gitlab-ci.yml
stages:
  - test
  - quality

sonarqube-check:
  stage: quality
  image: maven:3.9-eclipse-temurin-17
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
    GIT_DEPTH: "0"
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - mvn sonar:sonar
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.token=${SONAR_TOKEN}
      -Dsonar.projectKey=${CI_PROJECT_NAME}
  only:
    - merge_requests
    - main
    - develop

3. PR 分析配置

# .gitlab-ci.yml (PR 分析)
sonarqube-mr:
  stage: quality
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn sonar:sonar
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.token=${SONAR_TOKEN}
      -Dsonar.projectKey=${CI_PROJECT_NAME}
      -Dsonar.pullrequest.key=${CI_MERGE_REQUEST_IID}
      -Dsonar.pullrequest.branch=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}
      -Dsonar.pullrequest.base=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
  only:
    - merge_requests

4. 质量门禁检查

sonarqube-check:
  stage: quality
  image: sonarsource/sonar-scanner-cli
  script:
    - sonar-scanner
      -Dsonar.host.url=${SONAR_HOST_URL}
      -Dsonar.token=${SONAR_TOKEN}
      -Dsonar.projectKey=${CI_PROJECT_NAME}
      -Dsonar.qualitygate.wait=true
      -Dsonar.qualitygate.timeout=300
  only:
    - merge_requests
    - main

GitHub Actions 集成

1. 配置 Secrets

在 GitHub 仓库中配置 Secrets:

Settings → Secrets and variables → Actions

SONAR_HOST_URL: http://sonarqube-server:9000
SONAR_TOKEN: squ_xxxxxxxxxxxx

2. 基本工作流

# .github/workflows/sonarqube.yml
name: SonarQube Analysis

on:
  push:
    branches:
      - main
      - develop
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  sonarqube:
    name: SonarQube Scan
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache SonarQube packages
        uses: actions/cache@v4
        with:
          path: ~/.sonar/cache
          key: ${{ runner.os }}-sonar
          restore-keys: ${{ runner.os }}-sonar

      - name: Cache Maven packages
        uses: actions/cache@v4
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2

      - name: Build and analyze
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        run: |
          mvn -B verify sonar:sonar \
            -Dsonar.projectKey=${{ github.event.repository.name }} \
            -Dsonar.host.url=${SONAR_HOST_URL} \
            -Dsonar.token=${SONAR_TOKEN}

3. PR 分析

# .github/workflows/sonarqube-pr.yml
name: SonarQube PR Analysis

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: SonarQube Scan
        uses: sonarsource/sonarqube-scan-action@master
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        with:
          args: >
            -Dsonar.projectKey=${{ github.event.repository.name }}
            -Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
            -Dsonar.pullrequest.branch=${{ github.head_ref }}
            -Dsonar.pullrequest.base=${{ github.base_ref }}

      - name: SonarQube Quality Gate
        uses: sonarsource/sonarqube-quality-gate-action@master
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

Azure DevOps 集成

1. 安装扩展

在 Azure DevOps 市场安装 SonarQube 扩展。

2. 配置服务连接

Project Settings → Service connections → New service connection → SonarQube

3. Pipeline 配置

# azure-pipelines.yml
trigger:
  - main
  - develop

pr:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: SonarQubePrepare@5
    inputs:
      SonarQube: 'SonarQube Connection'
      scannerMode: 'CLI'
      configMode: 'manual'
      cliProjectKey: '$(Build.Repository.Name)'
      cliProjectName: '$(Build.Repository.Name)'
      cliSources: 'src'

  - task: Maven@4
    inputs:
      mavenPomFile: 'pom.xml'
      goals: 'verify'
      javaHomeOption: 'JDKVersion'
      jdkVersionOption: '1.17'

  - task: SonarQubeAnalyze@5

  - task: SonarQubePublish@5
    inputs:
      pollingTimeoutSec: '300'

CircleCI 集成

# .circleci/config.yml
version: 2.1

orbs:
  sonarqube: circleci/sonarqube@1.1.0

jobs:
  build-and-analyze:
    docker:
      - image: cimg/openjdk:17.0
    steps:
      - checkout

      - restore_cache:
          keys:
            - maven-{{ checksum "pom.xml" }}
            - maven-

      - run:
          name: Build
          command: mvn -B clean verify

      - sonarqube/scan:
          sonar_token_variable: SONAR_TOKEN
          sonar_host_url_variable: SONAR_HOST_URL
          sonar_project_key: ${CIRCLE_PROJECT_REPONAME}

      - save_cache:
          paths:
            - ~/.m2
          key: maven-{{ checksum "pom.xml" }}

workflows:
  main:
    jobs:
      - build-and-analyze:
          context: sonarqube

质量门禁等待

方式一:Scanner 参数

sonar-scanner \
  -Dsonar.qualitygate.wait=true \
  -Dsonar.qualitygate.timeout=300

方式二:API 轮询

#!/bin/bash
# wait-for-quality-gate.sh

SONAR_URL="http://localhost:9000"
PROJECT_KEY="my-project"
TOKEN="squ_xxxxxxxxxxxx"

# 获取分析 ID
ANALYSIS_ID=$(curl -s -u $TOKEN: \
  "$SONAR_URL/api/project_analyses/search?project=$PROJECT_KEY" | \
  jq -r '.analyses[0].key')

# 轮询质量门禁状态
while true; do
  STATUS=$(curl -s -u $TOKEN: \
    "$SONAR_URL/api/qualitygates/project_status?analysisId=$ANALYSIS_ID" | \
    jq -r '.projectStatus.status')

  if [ "$STATUS" != "PENDING" ]; then
    break
  fi

  sleep 5
done

if [ "$STATUS" == "OK" ]; then
  echo "Quality Gate passed"
  exit 0
else
  echo "Quality Gate failed"
  exit 1
fi

最佳实践

1. 分阶段集成

# 推荐集成阶段
阶段一:仅分析,不阻断
阶段二:PR 分析 + 质量门禁
阶段三:主分支保护 + 质量门禁

2. 缓存优化

# 缓存 SonarQube 分析结果
cache:
  paths:
    - .sonar/cache
    - ~/.m2/repository

3. 并行执行

# 与测试并行执行
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: mvn test

  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - run: mvn sonar:sonar

4. 失败通知

# 失败时发送通知
after_failure:
  - name: Notify on failure
    run: |
      curl -X POST $WEBHOOK_URL \
        -d '{"text": "SonarQube Quality Gate failed"}'

小结

本章介绍了 SonarQube 与主流 CI/CD 工具的集成:

  • Jenkins Pipeline 集成
  • GitLab CI 集成
  • GitHub Actions 集成
  • Azure DevOps 集成
  • CircleCI 集成
  • 质量门禁等待机制

下一章将介绍安全分析功能。