Gitee Webhook 實現自動拉取程式碼並編譯程式碼

hejingtao發表於2019-03-04

一、Webhook 介紹與作用簡介

Webhook,顧名思義就是鉤子,簡而言之,可以在特定情況下觸發特定的操作。例如在遠端git倉庫中進行了push、tag等操作時,自動在遠端server端自動拉取、編譯程式碼。
以下是一個push程式碼到遠端倉庫後,自動拉取程式碼進行編譯後,將生成的Webassembly相關的檔案(.js,.wasm)和版本號push到遠端倉庫中的demo。

二、demo實現

1. 倉庫設定(以gitee為例)

首先,需要擁有專案的管理者許可權,點選專案首頁上方的管理,然後點選左側選單下方的WebHooks,進入到以下截圖的設定頁面。

WebHooks設定介面

]

在上面的的介面中,我已經新增了一個Webhook,觸發型別為push,同時還有一個密碼。
當你push程式碼到遠端倉庫時,會往這裡設定的URL傳送一個攜帶著設定好密碼的POST請求。當然你也可以勾選其他的操作型別。

Webhook新增介面.png

2. PHP程式碼實現

  • hooks.php
 <?php

// 本地倉庫路徑
$local = `/data/wwwroot/default/hooks/laserbox`;

// 安全驗證字串,為空則不驗證
$token = `123456`;

//  payload為字串,需要經過解析
$payload = file_get_contents(`php://input`);
if (!$payload) {
    header(`HTTP/1.1 400 Bad Request`);
    die(`HTTP HEADER or POST is missing.`);
}
$content = json_decode($payload, true);

// 如果啟用驗證,並且驗證失敗,返回錯誤
if ($token && $content[`password`] != $token) {
    header(`HTTP/1.1 403 Permission Denied`);
    die(`Permission denied.`);
}

//最後會執行一個指令碼編譯程式碼,然後再push程式碼到遠端
//所以會重複觸發WebHooks,因此此處判斷是否是本地的推送
if($content[`commits`][0][`author`][`name`] == `handsomeTaoTao`){
        header(`HTTP/1.1 403 Permission Denied`);
        die(`self push.`);
}

/*
 * 這裡有幾點需要注意:
 *
 * 1.確保PHP正常執行系統命令。寫一個PHP檔案,內容:
 * `<?php echo shell_exec(`ls -la`)`
 * 在通過瀏覽器訪問這個檔案,能夠輸出目錄結構說明PHP可以執行系統命令。
 *
 * 2、PHP一般使用www-data或者nginx使用者執行,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.`
 *
 */

// shell_exec函式預設是禁止的,無法使用的話需要進php.ini修改相關配置
//執行shell時,沒有sudo彷彿會執行不成功,只執行一小段,加了sudo之後執行成功,可以為執行php的使用者新增sudo許可權,參考資料有相關問題
echo shell_exec("cd {$local} && sudo  sh ./autoCompiled.sh");
die("done " . date(`Y-m-d H:i:s`, time()));
複製程式碼

  • autoCompiled.sh
#!/bin/sh
source /data/git/emsdk/emsdk_env.sh  // 載入命令,否則在命令列中無法使用emcc等編譯用的命令
cd  /data/git/Webassembly-Lib/Demo/  // 進入到執行命令的目錄中
git pull
rm -f src/version.h
git rev-list HEAD | sort > config.git-hash
LOCALVER=`wc -l config.git-hash | awk `{print $1}``
if [ $LOCALVER > 1 ] ; then
    VER=`git rev-list origin/master | sort | join config.git-hash - | wc -l | awk `{print $1}``
    if [ $VER != $LOCALVER ] ; then
        VER="$VER+$(($LOCALVER-$VER))"
    fi
    if git status | grep -q "modified:" ; then
        VER="${VER}M"
    fi
    VER="$VER $(git rev-list HEAD -n 1 | cut -c 1-7)"
    GIT_VERSION=r$VER
else
    GIT_VERSION=
    VER="x"
fi
rm -f config.git-hash

cat version.h.template | sed "s/$FULL_VERSION/$GIT_VERSION/g" > src/version.h


# 編譯和提交程式碼
make
git add .
git commit -m `Auto Compiled By handsomeTaoTao` 
git push

複製程式碼

三、結束語

目前這個demo還只是實現了比較簡單的功能,可以進一步優化功能,例如在瀏覽器訪問該地址時顯示上一次編譯是否成功的資訊,失敗的話則顯示錯誤資訊,這樣子可以方便除錯。


參考資料
stackoverflow: php-sudo-in-shell-exec
Gitee 配置文件
Github、GitLab、Gitee使用Webhooks實現程式碼自動部署

相關文章