利用Git Hook執行程式碼品質檢查 — How to use git pre-commit hook to trigger jshint

問題

使用Git的時候常常會遇到一個狀況:commit之後才發現jshint檢查不通過(通常都是少了個分號啊什麼的)。如果一個repo多人使用,merge之後一整排的jshint Error那更是歡樂無比。

解決方式

懶人包 || TL;DR

Git Pre-commit Hook + JSHint (or JSLint 或任何你在用的檢查工具)

詳細說明及設定步驟

既然我們需要commit時後都能通過jshint檢查,那麼就可以使用Git Hook來完成這件任務。Git Hook簡單的說就是一個trigger:當某一個git動作發生的時候,會去執行相對應的hook執行檔。以本文來說,我們需要在commit之前,執行一個幫我們做jshint檢查的shell script。

設定方式非常簡單,到repo下面的.git/hooks裏面,建立一個名為pre-commit的檔案,裏面執行jshint指令即可。筆者的pre-commit指令如下:

    #!/bin/sh
    #
    # Run JSHint validation before commit.

    files=$(git diff --cached --name-only --diff-filter=ACM | grep ".js$")
    pass=true

    echo "files:"
    if [ "$files" != "" ]; then
        for file in ${files}; do
            echo $file
            result=$(jshint -c .jshintrc ${file})

            if [ "$result" != "" ]; then
                echo $result
                pass=false
            fi
        done
    fi


    if $pass; then
        exit 0
    else
        echo ""
        echo "COMMIT FAILED:"
        echo "Some JavaScript files are invalid. Please fix errors and try committing again."
        exit 1
    fi

這個shell script做了什麼事情?利用git diff把這次commit修改的檔案名稱抓出來,並以grep過濾出.js檔,然後對他們執行jshint。(在這邊我有設定jshint的設定檔為.jshintrc)如果沒有問題就exit 0正常結束(git commit就會繼續執行),如果有問題就印出錯誤訊息並exit 1中斷commit。

系統需求

JSHint: npm install -g jshint

Grunt進階版

如果你的repo有很多人在用,又剛好是使用grunt,那麼可以新增下列task幫你自懂安裝git hook。(當然啦,如果你不想一直坐在椅子上,想跟同事多多交流,筆者會建議您不要使用這麼無腦的自動安裝方法,走過去直接跟您同事說吧!)


    grunt.registerTask('install-hooks', function () {
    var fs = require('fs');

    // my precommit hook is inside the repo as /pre-commit.hook
    // copy the hook file to the correct place in the .git directory
    grunt.file.copy('pre-commit.hook', '.git/hooks/pre-commit');

    // chmod the file to readable and executable by all
    fs.chmodSync('.git/hooks/pre-commit', '755');
  });

記得把你的pre-commit檔放在repo的/pre-commit.hook,這樣使用這個repo的人只要執行一次grunt install-hooks,系統就會自動安裝我們寫好的hooks了。

當然hooks有很多種,pre-commit hook也可以做更多事情,就看個人需求變化嘍。