如何使用git的hook來驗證程式碼規範

ruixin發表於2018-09-21

首先

  • 需要知道基本的git使用
  • 知道eslint是什麼鬼
    • ESLint 是一個語法規則和程式碼風格的檢查工具,可以用來保證寫出語法正確、風格統一的程式碼。

開始表演

1.需要一份eslint配置檔案(.eslintrc.js)

下面使我們的公司的規範

module.exports = {
    root: true, 
    extends: "eslint:recommended",
    parserOptions: {
        sourceType: "module",
        ecmaVersion: 7
    },
    env: {
        browser: true,
        es6: true
    },
    plugins: [
        "html"
    ],
    parser: "babel-eslint",
    rules: {
        "indent": ["error", "tab",{"SwitchCase": 1}],
        "quotes": ["error", "single", { "allowTemplateLiterals": true }],
        "semi": ["error", "always",{ "omitLastInOneLineBlock": true }],
        "no-console": ["error",{allow:["log","warn"]}],
        "arrow-parens": 0,
        "no-news":0,
        "no-case-declarations":0,
        "no-var":2,
        "no-empty-function":2,
        "no-debugger":0,
        "max-params": ["error", 3]
    } 
}
複製程式碼

更詳細的

2.談談git的鉤子是啥

  • git鉤子(可自定義)

    鉤子都被儲存在Git目錄下的hooks目錄中

    cd .git/hooks && ls

    這些鉤子的功能主要分為提交工作流鉤子、電子郵件工作流鉤子和其它鉤子。比如提交程式碼之前檢查,提交給同組開發人員發郵件等等。

我們這裡只做對程式碼風格的校驗
會用到鉤子是pre-commit,這個鉤子會在我們提交程式碼到本地倉是進行驗證
此時我們只需要在專案的根目錄 .git/hooks 下 新建檔案pre-commit即可
但是預設情況下 鉤子用的是bash命令 #!/bin/sh
但是靈活度肯定不如我們直接寫node來的快 ,此時的我們只需要把檔案的首行改為 #!/usr/env/node
複製程式碼

檔案內容如下

#!/usr/env/node

'use strict';
let exec = require('child_process').exec;  //為node呼叫git命令列做準備
let path = require("path");
let config = require(path.resolve(".eslintrc.js"));//載入你的eslint配置檔案,注意是是放在專案的根目錄下

let CLIEngine = require("eslint").CLIEngine;//使用官方提供的eslint的API
//API參考地址: https://eslint.org/docs/developer-guide/nodejs-api 

let cli = new CLIEngine(config);

//儲存不滿足eslint的資訊
let errCached = {};

//執行git命令的獲取修改的檔案(注意引數是--cached或者--staged,不要用HEAD,這個會把別人不想提交的也會檢測很麻煩)
exec('git diff --cached --name-only --diff-filter=ACMR -- src/',(error, stdout, stderr) => {  
	
    // stdout 是以換行分割的包含改動檔案的路徑的字串
    //獲取到修改的檔案
    if(stdout.length){
        let allFile = stdout.split("\n");
        //只需要檢測我們需要的型別
    	allFile = allFile.filter((item)=>{
    	    return /\.(js|vue)$/g.test(item);
    	})
    	
    	//allFile 是所有的改動檔案路徑的陣列
    	let report = cli.executeOnFiles(allFile);
複製程式碼

這個report返回的是這個格式的陣列

{
    results: [   //N條檢測結果的集合,陣列中的每一個物件都是檢測的每個檔案的詳細報告
        {
            filePath: "/Users/eslint/project/myfile.js",
            messages: [
                {
                    ruleId: "semi",
                    severity: 2,
                    message: "Missing semicolon.",
                    line: 1,
                    column: 13,
                    nodeType: "ExpressionStatement",
                    fix: { range: [12, 12], text: ";" }
                }
            ],
            errorCount: 1,
            warningCount: 0,
            fixableErrorCount: 1,
            fixableWarningCount: 0,
            source: "\"use strict\"\n"
        }
    ],
    //下面這幾個是對所有的檢測報告做的彙總比如說報錯多少個,警告多少個之類的
    errorCount: 1, 
    warningCount: 0,
    fixableErrorCount: 1,
    fixableWarningCount: 0
}
複製程式碼

拿到上述結果,我們可以在下面做一些的簡單的邏輯判斷以及一些提示語言

        //簡單做些計算和統計
	if(Number(report.errorCount) > 0 || Number(report.warningCount) > 0){
		for(let item of report.results){
			let temp = errCached[item.filePath] = [];
			if( Number(item.errorCount) > 0 || Number(item.warningCount) > 0){
				for(let errMsg of item.messages){
					temp.push({
						ruleId:errMsg.ruleId,
						message:errMsg.message,
						line:errMsg.line,
						column:errMsg.column
					})
				}
			}
		}
		
		//梳理輸出結果
		console.log("以下檔案存在問題(不滿足eslint規範)\n");
		let num = 1;
		for(let str in errCached){
			let temp = errCached[str];
			if(temp.length > 0){
				console.log(`${num++}=>${str}\n`);
				let index = 0;
				for(let item of temp){
					console.log(`\t${++index}.錯誤為:${item.message},行:${item.line},列:${item.column},錯誤規則:${item.ruleId}`);
				}
			}
			
		}
		
		if( num > 1){
			console.log('\n\錯誤太多,建議你把config下的webpack.dev.conf.js的所屬自己的板塊的eslint驗證開啟');
			process.exit(1);
		}
		else{
			console.log("牛逼驗證通過了,可以上傳");
			process.exit(0);
		}
		
	}else{
		console.log("牛逼驗證通過了,可以上傳");
		process.exit(0);
	}
		
    }else{
		console.log("牛逼驗證通過了,可以上傳")
		process.exit(0);
	}
    if (error !== null) {
        console.log('exec error: ' + error);
		process.exit(1);
    }
});
複製程式碼

怎麼區分檢測是否通過或者不通過呢
國際統一標準,退出值為!0的情況下為失敗 返回為0 則為成功

process.exit(1);
複製程式碼

好的,結束!

相關文章