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。

相关推荐
番茄灭世神36 分钟前
Git入门使用学习
git·gitee·软件工程·计算机专业入门
南_山无梅落2 小时前
团队协作高频Git实用手册(项目实战版)
git·团队开发
就叫飞六吧2 小时前
git提取当前分支指定文件历史版本
git
数字游民95272 小时前
网站备案全流程回放(腾讯云)
人工智能·git·github·腾讯云·网站备案·waytoopc
Albert Edison3 小时前
【Git】多人协作一(同一分支下)
git·vscode·svn·github
学好statistics和DS3 小时前
Git 同步冲突
大数据·git·elasticsearch
德彪稳坐倒骑驴16 小时前
Git常用命令
git
无限进步_16 小时前
【C语言&数据结构】对称二叉树:镜像世界的递归探索
c语言·开发语言·数据结构·c++·git·算法·visual studio
qq_54702617919 小时前
Git 使用指南
git
XiaoHu020720 小时前
Linux多线程(详细全解)
linux·运维·服务器·开发语言·c++·git