代码质量门禁
源:Spotless | detekt | Android Lint
通过自动化工具强制执行代码规范,提升代码质量和团队协作效率。
代码质量工具
工具对比
| 工具 | 用途 | 语言 | 自动修复 |
|---|---|---|---|
| Spotless | 代码格式化 | Kotlin/Java/XML | ✅ |
| ktlint | Kotlin 代码规范 | Kotlin | ✅ |
| detekt | 静态代码分析 | Kotlin | ⚠️ 部分 |
| Android Lint | Android 专用检查 | Kotlin/Java | ⚠️ 部分 |
Spotless
安装配置
build.gradle.kts:
kotlin
plugins {
id("com.diffplug.spotless") version "6.25.0"
}
spotless {
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
ktlint("1.1.1")
.editorConfigOverride(mapOf(
"max_line_length" to "120",
"disabled_rules" to "no-wildcard-imports"
))
trimTrailingWhitespace()
indentWithSpaces(4)
endWithNewline()
}
kotlinGradle {
target("**/*.gradle.kts")
ktlint()
}
format("xml") {
target("**/*.xml")
targetExclude("**/build/**/*.xml")
indentWithSpaces(4)
trimTrailingWhitespace()
endWithNewline()
}
}常用命令
bash
# 检查格式
./gradlew spotlessCheck
# 自动修复
./gradlew spotlessApply
# 只检查 Kotlin
./gradlew spotlessKotlinCheck
# 只修复 Kotlin
./gradlew spotlessKotlinApplyGit Hooks
安装 pre-commit hook:
kotlin
tasks.register<Copy>("installGitHooks") {
from("scripts/pre-commit")
into(".git/hooks")
fileMode = 0b111101101 // 0755
}
tasks.named("build") {
dependsOn("installGitHooks")
}scripts/pre-commit:
bash
#!/bin/bash
./gradlew spotlessCheck
if [ $? -ne 0 ]; then
echo "❌ Code format check failed"
echo "Run: ./gradlew spotlessApply"
exit 1
fidetekt
安装配置
build.gradle.kts:
kotlin
plugins {
id("io.gitlab.arturbosch.detekt") version "1.23.4"
}
detekt {
buildUponDefaultConfig = true
allRules = false
config.setFrom("$projectDir/config/detekt.yml")
}
dependencies {
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.4")
}config/detekt.yml:
yaml
complexity:
LongMethod:
threshold: 50
LongParameterList:
functionThreshold: 6
constructorThreshold: 7
CyclomaticComplexMethod:
threshold: 15
style:
MaxLineLength:
maxLineLength: 120
MagicNumber:
ignoreNumbers: [-1, 0, 1, 2]
naming:
FunctionName:
functionPattern: '[a-z][a-zA-Z0-9]*'使用
bash
# 检查
./gradlew detekt
# 生成报告
./gradlew detekt --reports html
# 查看报告
open build/reports/detekt/detekt.htmlAndroid Lint
配置 Lint
build.gradle.kts:
kotlin
android {
lint {
// 错误视为失败
abortOnError = true
// 警告视为错误
warningsAsErrors = false
// 检查所有问题
checkAllWarnings = true
// 生成 HTML 报告
htmlReport = true
htmlOutput = file("$buildDir/reports/lint-results.html")
// 生成 XML 报告
xmlReport = true
xmlOutput = file("$buildDir/reports/lint-results.xml")
// 禁用特定检查
disable += setOf(
"TypographyFractions",
"TypographyQuotes"
)
// 启用特定检查
enable += setOf(
"RtlHardcoded",
"RtlCompat"
)
// 设置严重性
error += setOf("NewApi", "InlinedApi")
warning += setOf("UnusedResources")
ignore += setOf("GoogleAppIndexingWarning")
}
}Lint 配置文件
lint.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- 忽略特定警告 -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- 设置为错误 -->
<issue id="NewApi" severity="error" />
<!-- 忽略特定文件 -->
<issue id="UnusedResources">
<ignore path="src/main/res/values/donottranslate.xml" />
</issue>
</lint>baseline
创建 baseline:
bash
./gradlew lintDebug --create-baseline使用 baseline:
kotlin
android {
lint {
baseline = file("lint-baseline.xml")
}
}组合使用
统一质量检查
build.gradle.kts:
kotlin
tasks.register("check质量") {
group = "verification"
description = "运行所有代码质量检查"
dependsOn("spotlessCheck")
dependsOn("detekt")
dependsOn("lintDebug")
dependsOn("test")
}使用:
bash
./gradlew check质量CI 门禁
GitHub Actions:
yaml
name: Code Quality
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup JDK
uses: actions/setup-java@v3
with:
java-version: '17'
- name: Spotless Check
run: ./gradlew spotlessCheck
- name: detekt
run: ./gradlew detekt
- name: Lint
run: ./gradlew lintDebug
- name: Upload Reports
if: failure()
uses: actions/upload-artifact@v3
with:
name: quality-reports
path: |
**/build/reports/detekt/
**/build/reports/lint-*.html约定插件集成
质量检查插件
kotlin
class QualityConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
// 应用 Spotless
pluginManager.apply("com.diffplug.spotless")
extensions.configure<SpotlessExtension> {
kotlin {
target("**/*.kt")
ktlint()
}
}
// 应用 detekt
pluginManager.apply("io.gitlab.arturbosch.detekt")
extensions.configure<DetektExtension> {
buildUponDefaultConfig = true
}
// 配置 Android Lint
pluginManager.withPlugin("com.android.application") {
extensions.configure<ApplicationExtension> {
lint {
abortOnError = true
checkAllWarnings = true
}
}
}
// 创建统一任务
tasks.register("checkQuality") {
group = "verification"
dependsOn("spotlessCheck", "detekt", "lintDebug")
}
}
}
}使用:
kotlin
// build.gradle.kts
plugins {
id("my.quality")
}实战案例
案例1:完整的质量门禁
build.gradle.kts:
kotlin
plugins {
id("com.diffplug.spotless") version "6.25.0"
id("io.gitlab.arturbosch.detekt") version "1.23.4"
}
spotless {
kotlin {
target("**/*.kt")
ktlint("1.1.1")
trimTrailingWhitespace()
endWithNewline()
}
}
detekt {
config.setFrom("$projectDir/config/detekt.yml")
}
android {
lint {
abortOnError = true
baseline = file("lint-baseline.xml")
}
}
tasks.register("qualityGate") {
group = "verification"
dependsOn(
"spotlessCheck",
"detekt",
"lintDebug",
"testDebugUnitTest"
)
}案例2:自动修复工作流
fix-code.sh:
bash
#!/bin/bash
echo "🔧 Fixing code quality issues..."
# 修复格式
./gradlew spotlessApply
# 运行检查
./gradlew detekt
# 提交修复
git add -A
git commit -m "chore: fix code quality issues"
echo "✅ Done!"最佳实践
CI 强制检查:
yaml
- name: Quality Gate
run: ./gradlew spotlessCheck detekt lintDebug本地 Git Hooks:
bash
# pre-commit: 提交前检查
./gradlew spotlessCheck
# pre-push: 推送前完整检查
./gradlew qualityGate统一配置:
kotlin
// 在约定插件中统一配置
plugins {
id("my.quality") // 一行搞定
}Baseline 管理:
bash
# 初始项目创建 baseline
./gradlew lintDebug --create-baseline
# 定期更新 baseline
./gradlew lintDebug --update-baseline团队规范:
- PR 必须通过所有检查
- 不接受降低质量的代码
- 定期更新工具版本