Appearance
代码质量门禁
将代码质量检查集成到构建流程,不达标则构建失败。
完整质量门禁配置
kotlin
// buildSrc/src/main/kotlin/quality-conventions.gradle.kts
plugins {
java
checkstyle
jacoco
id("com.github.spotbugs")
}
// Checkstyle:代码风格
checkstyle {
toolVersion = "10.12.5"
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
maxWarnings = 0
isIgnoreFailures = false
}
// SpotBugs:静态 Bug 分析
spotbugs {
toolVersion.set("4.8.3")
excludeFilter.set(rootProject.file("config/spotbugs/exclude.xml"))
effort.set(com.github.spotbugs.snom.Effort.DEFAULT)
reportLevel.set(com.github.spotbugs.snom.Confidence.MEDIUM)
isIgnoreFailures = false
}
// JaCoCo:测试覆盖率
jacoco {
toolVersion = "0.8.11"
}
tasks.named<JacocoReport>("jacocoTestReport") {
dependsOn(tasks.named("test"))
reports {
xml.required.set(true)
html.required.set(true)
}
// 排除不需要统计的类
classDirectories.setFrom(
sourceSets.main.get().output.asFileTree.matching {
exclude(
"**/config/**",
"**/*Application*",
"**/*Exception*",
"**/dto/**",
"**/entity/**"
)
}
)
}
tasks.named<JacocoCoverageVerification>("jacocoTestCoverageVerification") {
dependsOn(tasks.named("jacocoTestReport"))
violationRules {
rule {
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = "0.80".toBigDecimal() // 80% 行覆盖率
}
}
rule {
limit {
counter = "BRANCH"
value = "COVEREDRATIO"
minimum = "0.70".toBigDecimal() // 70% 分支覆盖率
}
}
}
}
// 将所有质量检查加入 check 任务
tasks.named("check") {
dependsOn(
tasks.named("checkstyleMain"),
tasks.named("spotbugsMain"),
tasks.named("jacocoTestCoverageVerification")
)
}SonarQube 集成
kotlin
// 根项目 build.gradle.kts
plugins {
id("org.sonarqube") version "4.4.1.3373"
}
sonar {
properties {
property("sonar.projectKey", "my-project")
property("sonar.projectName", "My Project")
property("sonar.host.url", "https://sonarqube.example.com")
property("sonar.token", System.getenv("SONAR_TOKEN"))
// JaCoCo 报告路径
property("sonar.coverage.jacoco.xmlReportPaths",
subprojects.map { "${it.buildDir}/reports/jacoco/test/jacocoTestReport.xml" }.joinToString(","))
// 测试报告路径
property("sonar.junit.reportPaths",
subprojects.map { "${it.buildDir}/test-results/test" }.joinToString(","))
// 排除文件
property("sonar.exclusions", "**/generated/**,**/*Exception.java,**/*Dto.java")
// 质量门
property("sonar.qualitygate.wait", "true")
}
}CI 流水线集成
yaml
# .github/workflows/quality.yml
name: Quality Gate
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # SonarQube 需要完整历史
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- uses: gradle/actions/setup-gradle@v3
# 1. 构建+测试+质量检查
- name: Build and Quality Check
run: ./gradlew build checkstyleMain spotbugsMain jacocoTestReport
# 2. SonarQube 分析
- name: SonarQube Scan
run: ./gradlew sonar
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}质量报告汇总
kotlin
// 生成汇总报告
tasks.register("qualityReport") {
group = "reporting"
dependsOn("jacocoTestReport", "checkstyleMain", "spotbugsMain")
doLast {
println("========== 质量检查报告 ==========")
println("测试覆盖率:build/reports/jacoco/test/html/index.html")
println("代码风格:build/reports/checkstyle/main.html")
println("Bug 检测:build/reports/spotbugs/main.html")
println("===================================")
}
}