第六章:CI/CD 集成¶
集成概述¶
将 SonarQube 集成到 CI/CD 流水线中,可以在代码合并前自动进行质量检查,确保代码质量。
Jenkins 集成¶
1. 安装插件¶
在 Jenkins 中安装 SonarQube 插件:
2. 配置 SonarQube Server¶
# 配置项
Name: SonarQube
Server URL: http://sonarqube-server:9000
Server authentication token: squ_xxxxxxxxxxxx
3. 配置 SonarScanner¶
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. 配置服务连接¶
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 参数¶
方式二: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. 分阶段集成¶
2. 缓存优化¶
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 集成
- 质量门禁等待机制
下一章将介绍安全分析功能。