不會寫shell的程序員照樣是好前端——用Node.JS實現git hooks

PYABess 8年前發布 | 16K 次閱讀 Git Node.js Node.js 開發 Shell

來自: http://hao.jser.com/archive/10098/

前言

git hooks想必很多攻城獅都不陌生,官方對于hooks有詳細的 文檔 ,也有站內網友的文章 Git Hooks (1):介紹 , GIt Hooks (2):腳本分類 ,說的非常詳細了,這里就不多做介紹,這里主要介紹一下如何寫一個hook。

一個基本的git hook長什么樣?

對git-hooks有一個入門認識的朋友都知道,hooks存放在git倉庫的 .git/hooks 目錄下,其中包括很多hooks,這些是在git 倉庫創建的時候自動生成的,后綴名統一都是 .sample ,表示這些hooks都是默認不啟用的,當把后綴名去掉之后,就變成了可以使用的hook。

舉個栗子

pre-commit這個hook是在 git commit 的時候觸發的hook,這個hook里面寫了什么呢?代碼我就不貼了,沒啥勁,主要的幾點就是:

  1. 這是一個shell腳本

  2. 這個腳本運行了一些東西然后退出了

  3. 退出的時候退出的錯誤碼不是確定的

這就是一個hook的最基本的組成:在命令行執行git操作的時候,自動執行hooks目錄下相應的可執行腳本,然后根據腳本的退出狀態決定此次操作是否成功。當退出的錯誤碼不為0的時候,表示失敗,操作終止,否則操作繼續。

模擬場景

如果現在有這樣一個場景,在你的git倉庫里,要求不允許提交 dist 目錄,并且通過 mocha 的測試,否則不允許提交,用git hook 怎么做呢?

首先,這是在提交的時候的一個限制,所以應該考慮使用 pre-commit 這個hook,代碼就不寫了(不會寫shell… Orz),整個過程如下:

  1. 檢查是否有 dist 目錄,如果沒有的話下一步,否則退出,錯誤碼置為1。

  2. 執行mocha命令進行測試,如果測試全部通過的話,退出,錯誤碼為0,否則錯誤碼為1,同樣退出。

這樣,當上述任何一步沒有通過的時候,這個hook就會被終止,git-commit就無法通過,也就達到了限制提交的目的。

shell腳本的局限性——不會寫

作為一名普通的前端,兼,一名不太合格的工程師,我對于shell腳本實在是不熟悉,連Linux命令都玩不轉,別說寫出666的shell腳本了,囧~ 所以要另辟巧徑做這件事。

前端仔們對js應該是非常熟練的,所以如果能用js寫hooks,那不就爽了?而Node.JS正好給了我們希望,感激涕零的話就不多說了,絕對感動到哭!

Node.js寫起腳本來也非常簡單,比如一個最簡單的腳本

#!/usr/bin/env node

console.log('Hello World!');

給腳本賦予可執行權限之后就完全可以當做shell腳本來跑了,麻麻再也不用擔心我不會shell了。同樣的,在hooks中我們也可以這樣用。再舉個栗子

還是剛才的場景,不允許有 dist 目錄,同時通過所有mocha測試,用Node就可以這樣寫(這次我能show出代碼了)

#!/usr/bin/env node
var fs = require('fs'),
    spawnSync = require('child_process').spawnSync;
if(fs.existsSync('./dist')){
    console.log('Commit Abort!Please remove dist directory.');
    process.exit(1);
}
// 使用同步方法spawnSync執行mocha,測試的結果在result.status中,通過為0,不通過為1
var result = spawnSync('./node_modules/.bin/mocha',['test']); 
if(result.status){
    console.log('Commit Abort!Test failure.');
}
process.exit(result.status);

這就是一個用Node.JS實現的基本的git-hook。

Node.JS的局限性——不能動

client-side hook的一個問題就是沒法在隨著倉庫變動,如果項目成員多的話,每個人都需要在自己本地添加一次,hooks有變動了更新也比較麻煩。

解決方案

我個人對這個問題有一個簡單解決方案,我做了一個倉庫 git-hooks-node ,每次寫好git hooks之后通過自己寫的工具進行build,生成一個類似于安裝器的文件,然后提交到遠程倉庫,如 pre-commit.js 是hook具體的內容, pre-commit.installer.js 是生成的安裝文件,也是一個腳本,github上的每一個文件都有相應的raw地址,如這個安裝文件的地址為 raw pre-commit.installer.js ,然后mac OS下的用戶就可以使用 curl 獲取腳本并運行,如下:

curl https://raw.githubusercontent.com/y8n/git-hooks-node/master/xgfe-ma/pre-commit.installer.js | node

安裝效果如下

這樣只要寫好一個hook并發布,項目成員只要知道地址就可以一鍵安轉(想想還有點小激動呢)。這樣雖然沒有解決hook不會隨著倉庫移動的問題,但也提供了一種在項目組里通用一套hook的方案。

其他解決方法

husky 是GitHub上一個開源項目,它的做法是在 npm install 這個模塊的時候自動在 .git/hooks 目錄下創建很多hooks,然后再在package.json中指定每一個hook的執行腳本,如下

"scripts": {
    "precommit": "npm test",
    "prepush": "npm test",
    "commit-msg": "./validate-commit-msg.js",
    "...": "..."
  }

這樣就可以把hooks隨著項目變動,真正做到項目成員共用一個git hook,但問題就是必須在項目中依賴husky,不過想想這樣的方法也比上面我的方法高明許多 -.-!

 本文由用戶 PYABess 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!