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。

相关推荐
427724006 小时前
IDEA使用git不提示账号密码登录,而是输入token问题解决
java·git·intellij-idea
利刃大大14 小时前
【Git】五、多人协作
git
逸Y 仙X21 小时前
Git常见命令--助力开发
java·大数据·git·java-ee·github·idea
wgslucky1 天前
pipeline 使用git parameter插件实现动态选择分支构造
git
春天姐姐1 天前
vue3项目开发总结
前端·vue.js·git
{⌐■_■}1 天前
【git】工作流实战:从本地仓库到远程仓库,git pull 与git rebase使用讲解,案例解析
git
大溪地C1 天前
Git 合并冲突解决与状态分析笔记
笔记·git
CsbLanca1 天前
Git配置个人和公司的提交信息,通过‘目录配置‘
git
娶个名字趴1 天前
Git企业开发
git
fruge2 天前
git上传 项目 把node_modules也上传至仓库了,在文件.gitignore 中忽略node_modules 依然不行
大数据·git·elasticsearch