Android Gradle 配置 Git Hooks 踩坑记录

Android Gradle 配置 Git Hooks

1. Git Hooks是什么

Git Hooks是一些自定义脚本,它们与特定git命令关联,如:git commitgit push等,允许我们在这些操作前/后调用。

通常为了规范化协作开发,我们会对提交代码做一系列的检查,比如:静态代码扫描、unit test检查、规范commit message格式等。

本文将演示,如何基于gradle脚本透明地配置pre-push,使得developer push代码时执行静态代码检查和unit test

2. 配置 Git Hooks

2.1 准备pre-push脚本

sh 复制代码
#!/usr/bin/env bash
function runDetekt() {
    echo "Running detekt..."
    OUTPUT="/tmp/detekt-$(date +%s)"
    ./gradlew ./gradlew detekt --auto-correct > $OUTPUT
    EXIT_CODE=$?
    if [ $EXIT_CODE -ne 0 ]; then
      cat $OUTPUT
      rm $OUTPUT
      echo "***********************************************"
      echo "                 detekt failed                 "
      echo " Please fix the above issues before pushing "
      echo "***********************************************"
      exit $EXIT_CODE
    fi
    rm $OUTPUT
}
​
function runUnitTest() {
    echo "Running unit test..."
    OUTPUT="/tmp/unit-test-$(date +%s)"
    ./gradlew app:testDebugUnitTest > $OUTPUT
    EXIT_CODE=$?
    if [ $EXIT_CODE -ne 0 ]; then
      cat $OUTPUT
      rm $OUTPUT
      echo "***********************************************"
      echo "                 unit test failed                 "
      echo " Please fix the above issues before pushing "
      echo "***********************************************"
      exit $EXIT_CODE
    fi
    rm $OUTPUT
}
​
runDetekt
runUnitTest

2.2 将pre-push拷贝到.git/hooks/

项目文件结构如下:

perl 复制代码
my-project/
   .git/
   app/
   hooks/
      pre-push
   ...
kotlin 复制代码
// app/build.kts
project.afterEvaluate {
    val fromHooksDir = File(rootProject.projectDir, "hooks")
    val toHooksDir = File(rootProject.projectDir, ".git/hooks")
    fromHooksDir.listFiles().forEach { file ->
        val target = File(toHooksDir, file.name)
        file.copyTo(target, overwrite = true)
    }
}

run/sync项目的时候,就会把pre-push hook配置好

2.3 权限问题

sh 复制代码
➜  git push         
hint: The '.git/hooks/pre-push' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.

2.4 通过脚本设置执行权限

我们可以通过chmod +x ${file path}来修改权限

kotlin 复制代码
// app/build.gradle.kts
project.afterEvaluate {
    val fromHooksDir = File(rootProject.projectDir, "hooks")
    val toHooksDir = File(rootProject.projectDir, ".git/hooks")
    fromHooksDir.listFiles().forEach { file ->
        val target = File(toHooksDir, file.name)
        file.copyTo(target, overwrite = true)
        
        // 修改权限
        val command = "chmod +x ${target.path}"
        Runtime.getRuntime().exec(command).inputStream.use {
            String(it.readBytes()).trim()
        }
    }
}

sync项目后,便可以将pre-push配置好,且有执行权限。

但是,当我们运行项目的时候,会报错:

sh 复制代码
Configuration cache problems found in this build.
​
1 problem was found storing the configuration cache.
- Build file 'app/build.gradle.kts': external process started 'chmod +x /Users/xxx/my-project/.git/hooks/pre-push'
  See https://docs.gradle.org/8.4/userguide/configuration_cache.html#config_cache:requirements:external_processes

afterEvaluated不允许开启新进程了,所以chmod +x操作不能放在这里

2.5 新增installGitHooksTask执行

kotlin 复制代码
// app/build.gradle.kts
project.afterEvaluate {
   // 找个依附的task,这里用了preDebugBuild
   tasks.findByPath("preDebugBuild")?.dependsOn("installGitHooksTask")
}
​
tasks.register("installGitHooksTask") {
    doLast {
        val fromHooksDir = File(rootProject.projectDir, "hooks")
        val toHooksDir = File(rootProject.projectDir, ".git/hooks")
        fromHooksDir.listFiles().forEach { file ->
            val target = File(toHooksDir, file.name)
            file.copyTo(target, overwrite = true)
            val command = "chmod +x ${target.path}"
            Runtime.getRuntime().exec(command).inputStream.use {
                String(it.readBytes()).trim()
            }
            println("git hook '${file.name}' installed")
        }
    }
}

还是会报错,

sh 复制代码
Configuration cache problems found in this build.
​
1 problem was found storing the configuration cache.
- Task `:app:installGitHooksTask` of type `org.gradle.api.DefaultTask`: cannot serialize Gradle script object references as these are not supported with the configuration cache.
  See https://docs.gradle.org/8.4/userguide/configuration_cache.html#config_cache:requirements:disallowed_types

在task doLast块中不能依赖project,最终调整如下:

kotlin 复制代码
// app/build.gradle.kts
project.afterEvaluate {
   // 找个依附的task,这里用了preDebugBuild
   tasks.findByPath("preDebugBuild")?.dependsOn("installGitHooksTask")
}
​
tasks.register("installGitHooksTask") {
    val fromHooksDir = File(rootProject.projectDir, "hooks")
    val toHooksDir = File(rootProject.projectDir, ".git/hooks")
    doLast {
        fromHooksDir.listFiles().forEach { file ->
            val target = File(toHooksDir, file.name)
            file.copyTo(target, overwrite = true)
            val command = "chmod +x ${target.path}"
            Runtime.getRuntime().exec(command).inputStream.use {
                String(it.readBytes()).trim()
            }
            println("git hook '${file.name}' installed")
        }
    }
}

3. 总结

本文通过一个案例,演示了基于gradle实现git hook自动配置,大家可以根据实际情况,定制适合自身团队的git hook。

相关推荐
解道Jdon9 小时前
[Budi插件:VsCode状态栏显示Copilot使用情况
ide·windows·git·svn·eclipse·github·visual studio
kisshyshy9 小时前
掌握 Git 基础
git
绿色水杯00710 小时前
Android Gradle 依赖分析器
gradle
全糖可乐气泡水10 小时前
Codex适配国产信创环境安装部署与技术适配全解析
开发语言·git·python·算法·百度
一只大袋鼠13 小时前
Git 四种仓库连接方式操作指南
git
活宝小娜15 小时前
git windows安装教程
git
青春喂了后端17 小时前
Go Sidecar Repository 并发锁改造:让并发请求安全地进入 Git 仓库层
git·安全·golang
小雨青年17 小时前
GitHub Actions 工作流性能优化实战,先看瓶颈,再改缓存和并发
git
0x000719 小时前
Git Bash 中无法启动 Claude Code ?
开发语言·git·bash
xuhaoyu_cpp_java19 小时前
Git学习(六)
git·学习