假設,我們有三個環境:
線上倉庫。如Github、GitLab或Gitee(開源中國)
本地倉庫。日常開發用的。
服務器倉庫。一般是自動在測試服務器,或者生產服務器。
這裡我們要達到的目的是,
當有新的本地 commit push 到線上倉庫時,服務器倉庫自動pull最線上倉庫新的代碼。
1 工作原理
Webhooks工作原理很簡單,如下圖。
當我們push 代碼到線上倉庫,線上倉庫必然知道這個push操作,就會hook(回調)我們預留的URL。
而這個URL對應一段後臺代碼,這段代碼執行了git pull,這樣就實現下拉代碼操作。
上圖是以PHP為例,實際上用Java、Javascrtip等都可以,理論上一行代碼就可以搞定。
不過實際稍微複雜一點,需要進行一些安全驗證。
2 準備工作
首先,我們需要在服務器(生產或者測試等等)做一些準備工作。
最先應該做的,就是在服務器上安裝git(哈哈,這個應該都沒問題)
然後,克隆代碼:
$ cd /var/www/html # 代碼存放目錄
$ git clone https://github.com/yeszao/fastphp.git
因為這是公共倉庫,所以這裡我們使用的是https方式。
如果用SSH方式,需要配置SSH KEY,請參考這裡。
克隆完成後,代碼就在這個目錄裡面了:
/var/www/html/fastphp
這個就是服務器上的一個網站根目錄了,而且通過域名也是可以訪問其下的index.php等文件的。
3 PHP代碼
Github、GitLab和Gitee(開源中國,碼雲)雖然都是git倉庫平臺,但是發送的webhooks請求的數據格式有些差別。
Github支持application/json和application/x-www-form-urlencoded兩種格式,安全token需通過請求頭X-Hub-Signature加密發給URL,服務器需要解密後驗證。瞭解更多。
GitLab支持application/json格式,安全token通過請求頭HTTP_X_GITLAB_TOKEN明文發給URL。瞭解更多。
Gitee也支持application/json和application/x-www-form-urlencoded兩種格式,安全token放在請求體明文發給URL,名稱是password。瞭解更多。
請求頭我們可以通過$_SERVER全局變量獲得請求的值,比如$_SERVER['X-Hub-Signature']。
請求體則分為兩種:
如果是application/json格式,用這個方式獲得:
$payload = json_decode(file_get_contents('php://input'), true);
如果是application/x-www-form-urlencoded,就要用$_POST獲得:
$payload = $_POST['payload'];
完整代碼如下(GitLab):
/ 本地倉庫路徑
$local = '/var/www/html/awaimai';
// 安全驗證字符串,為空則不驗證
$token = '123456';
// 如果啟用驗證,並且驗證失敗,返回錯誤
$httpToken = isset($_SERVER['HTTP_X_GITLAB_TOKEN']) ? $_SERVER['HTTP_X_GITLAB_TOKEN'] : '';
if ($token && $httpToken != $token) {
header('HTTP/1.1 403 Permission Denied');
die('Permission denied.');
}
// 如果倉庫目錄不存在,返回錯誤
if (!is_dir($local)) {
header('HTTP/1.1 500 Internal Server Error');
die('Local directory is missing');
}
//如果請求體內容為空,返回錯誤
$payload = file_get_contents('php://input');
if (!$payload) {
header('HTTP/1.1 400 Bad Request');
die('HTTP HEADER or POST is missing.');
}
/*
* 這裡有幾點需要注意:
*
* 1.確保PHP正常執行系統命令。寫一個PHP文件,內容:
* `
* 在通過瀏覽器訪問這個文件,能夠輸出目錄結構說明PHP可以運行系統命令。
*
* 2、PHP一般使用www-data或者nginx用戶運行,PHP通過腳本執行系統命令也是用這個用戶,
* 所以必須確保在該用戶家目錄(一般是/home/www-data或/home/nginx)下有.ssh目錄和
* 一些授權文件,以及git配置文件,如下:
* ```
* + .ssh
* - authorized_keys
* - config
* - id_rsa
* - id_rsa.pub
* - known_hosts
* - .gitconfig
* ```
*
* 3.在執行的命令後面加上2>&1可以輸出詳細信息,確定錯誤位置
*
* 4.git目錄權限問題。比如:
* `fatal: Unable to create '/data/www/html/awaimai/.git/index.lock': Permission denied`
* 那就是PHP用戶沒有寫權限,需要給目錄授予權限:
* ``
* sudo chown -R :www-data /data/www/html/awaimai`
* sudo chmod -R g+w /data/www/html/awaimai
* ```
*
* 5.SSH認證問題。如果是通過SSH認證,有可能提示錯誤:
* `Could not create directory '/.ssh'.`
* 或者
* `Host key verification failed.`
*
*/
echo shell_exec("cd {$local} && git pull 2>&1");
die("done " . date('Y-m-d H:i:s', time()));
GitHub驗證方式請看:https://gist.github.com/milo/daed6e958ea534e4eba3
4 Webhooks配置
4.1 Github
4.2 Githab
4.3 Gitee
請求數據格式默認是application/json格式,application/x-www-form-urlencoded格式的話需要選擇:Old format。
5 測試
以上我們都訂閱了push事件。
這樣只要我們本地倉庫有push命令,都會執行一遍服務器倉庫的git pull操作。
git push -u origin master
閱讀更多 生活社會大雜燴 的文章