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。

相关推荐
zy2152151 小时前
Git 命令全流程总结
git
thels_6 小时前
记录一个用了很久的git提交到github和gitee比较方便的方法
git·gitee·github
5upport9 小时前
Gradle Version Catalog的IDE辅助工具
gradle·android studio·intellij idea
雨白9 小时前
初识版本控制工具 Git
git
急速前行Klein10 小时前
Ubuntu中安装git
linux·git·ubuntu
饼干ovo16 小时前
shell编程
java·git·github
bubiyoushang8881 天前
解决 Git 访问 GitHub 时的 SSL 错误
git·github·ssl
海码0071 天前
【版本控制】Git 和 GitHub 入门教程
git·github
网硕互联的小客服1 天前
503 Service Unavailable:服务器暂时无法处理请求,可能是超载或维护中如何处理?
服务器·git·github
abcnull1 天前
github开源协议选择
git·github·开源协议