使用 git hook 规范 Android 项目

引言

本文所说的『规范』包含两个部分

  1. git commit 是注释的规范

  2. git commit 时对代码规范的检查

  3. 在 AndroidStudio 中 git 提交失败的信息可以在右下角的 Event Log 窗口查看

技术支持

  1. .git 目录下面有一个 hooks 目录,里面可以存放一些 hook 文件,对 git 操作进行 hook 。
git_hook_picture_1.png

其中 commit-msg 文件是我们用来检测 commit 注释的 hook ,pre-commit 可
以在 commit 之前做一次拦截 。这两个文件需要手动添加 。但是 git 提
供了一系列 sample 文件,就是上图里面的 xxx.sample ,去掉这些文件的后缀名
即可体验 git hook 。Linux 环境下,需要给这些 git hook 文件增加权限。(例如
chmod +x commit-msg)。
git hook 文件里面内容是一些脚本,可以是 shell 、perl 、bat 、groovy 。只要
你的电脑支持的脚本,都可以在这个文件里面使用。

  1. checkStyle 插件可以帮我们对 Java 编码进行检查,在 AndroidStudio 之中配置也特别方便。

开始实战

选取脚本

因为小组成员使用了 windows 和 mac 两种操作系统,所以排除 bat 、shell 脚本。在 Python 、per 、groovy 中选择了 groovy 脚本。毕竟 AndroidStudio 是使用 gradle 构建项目,gradle 使用的是 groovy 。
下载 groovy配置环境变量(如何配置环境变量这里省略)

hook git commit 的注释

复制 commit-msg.sample 文件,删除后缀名,赋予权限执行 chmod +x commit-msg(Windows 环境不需要),编辑文件删除内容,添加内容如下
#!/usr/bin/env groovy
import static java.lang.System.exit

    println "commit-msg" 
    // First argument is the name of the
    // temporary commit message file.COMMIT_EDITMSG
    def msgFileName = args[0]
     
    // Get the commit message file.
    def msgFile = new File(msgFileName)
     
    // Read commit message from file.
    def commitMessage = msgFile.text
    
    /**
     * 提交规范
     * 必须包含  header 、body、footer  使用两个换行区分
     * 其中 header 必须,body 和 footer 可选
     *
     * 每个部分不得超过 70 个字
     * header 必须包含两个部分  type:subject 使用冒号区分
     * type 必须是以下类型的一种
     *      --feat: 新功能
     *      --fix:修复bug
     *      --style:格式变动,不影响代码运行
     *      --refactor:重构
     *      --perf:新能优化
     *      --test:增加测试
     * subject 是对 commit 的描述
     * 
     */
    def inputs = commitMessage.split("\n\n")
    
    def template = "提交格式错误\n" +
            "{Type}:{Subject}\n\n" +
            "{Body} \n\n" +
            "{Footer} \n\n" +
            "-------参数说明------ \n"+
            "每个部分不得超过70个字 \n" +
            "{Type},{Subject} 不能为空 \n" +
            "Type 必须是以下类型\n" +
            "    --feat: 新功能\n" +
            "    --fix:修复bug\n" +
            "    --style:格式变动,不影响代码运行\n" +
            "    --refactor:重构\n" +
            "    --perf:新能优化\n" +
            "    --test:增加测试\n" +
            "Subject 是对 commit 的描述,不能为空"
    if (inputs.length > 3) {
        println template
        exit 1
    }
    
    inputs.any {
        if (it.length() > 70)
            exit 1
    }
    def head =inputs[0].split(":")
    if(head.length!=2){
        println template
        exit 1
    }
    def type = head[0]
    def subject = head[1]
    def types = ["feat","fix","style","refactor","perf","test"]
    
    if(subject.isEmpty()||!types.contains(type)){
        println template
        exit 1
    }
    exit 0

第一行声明使用的脚本类型,必须保证当前环境变量中存在该脚本 bin 目录。
git commit 注释的内容会存到 .git 目录的 COMMIT_EDITMSG 文件中,文件会被当做一个 参数传递给 commit-msg 脚本(即存储在 args[0] 之中)。

上面的脚本对 commit 的注释做了一写格式判断,不符合判断的注释会导致提交失败。

使用 checkStyle

在 AndroidStudio 中配置 checkStyle 的 task。
checkStyle 配置在 Android 工程最外层 build.gradle 之中。

git_hook_picture_2.png

在Android 工程最外层防止一个 checkStyle.xml 文件,该文件来自华为 checkStyle

配置完成以后,我们可以在 AndroidStudio 的 Terminal 窗口执行 ./gradle checkStyle
进行 checkStyle 检查。(比如故意把变量设置为 aaa_bbb)

git_hook_picture_3.png

在 windows 环境先可能出现中文乱码

是因为 windows 环境的 cmd 默认是 gbk 编码,可以执行

     chcp 65001  

把 cmd 设置为 utf-8 编码 参考资料

checkStyle 命令有一个 bug
第一次检测出 Java 规范问题以后,再次执行就会检测到。需要在每次 checkStyle 之前执行一次 clean 命令 。完善后的 checkStyle 命令为

       ./gradle clean checkStyle 
git hook 调用 checkStyle

在 pre-commit 的hook 中用 gradle 调用对应的 task 如果检测不通过,提交失败。(pre-commit 的创建参考上面内容),内容如下

    #!/usr/bin/env groovy
    import static java.lang.System.exit
    
    def command = " ./gradlew  clean  checkstyle "
    
    if (System.properties['os.name'].toLowerCase().contains('windows')) {
        println "it's Windows"
        command = "cmd /c gradlew  clean  checkstyle "
    } else {
        println "it's not Windows"
    }
    
    def proc = command.execute()
    proc.waitFor()
    
    // Obtain status and output
    //println "return code: ${ proc.exitValue()}"
    //println "stdout: ${proc.in.text}"
    //println "stdout: ${proc.text}"
    //println "stderr: ${proc.err.text}"
    def result = proc.err.text
    
    if(result.isEmpty()){
        exit 0
    }else{
        println result
        exit 1
    }

在 Windows 环境下,groovy 调用 cmd 需要在 命令之前增加 "cmd /c" 否则 git 会报错找不到gradlew 命令

最后说几点

  1. .git 目录不会提交到远程仓库,所以需要客户端自己把 hook 文件放到 .git/hooks 目录下面。
    可以在项目中增加一个 gitHooks 目录存放这些 hooks 文件。
  2. git hook 可以绕过,所以最好在 git 的服务端也配置 hook ,针对 git push 请求进行拦截。

以上就是『使用 git hook 规范 Android 项目』 全部调研。

参考资料

Android项目git+gradle实现commit时checkstyle检查

自定义 Git - Git 钩子

Android Studio项目gradle+Git Hooks 实现提交时对提交日志和代码(checkStyle)的检查

我的提交信息规范

Windows下CMD中文乱码问题解决方法

推荐阅读更多精彩内容