gitea 使用 webhook 实现代码自动部署
利用
webhook钩子自动拉取代码时,要用到ssh密钥,所以这里生成ssh秘钥的用户和运行web的用户要一致,我们默认为 www 用户【如果你的用户不是www,则以实际运行web的用户为准】,所以要先切换用户再生成秘钥
ssh秘钥生成
bash
# 切换用户
su - www -s /bin/bash
# 生成秘钥
ssh-keygen -t ed25519 -C "Gitea SSH Key" -f gitea_keygitea ssh配置
在gitea中,ssh秘钥分为
个人秘钥和部署秘钥,个人秘钥可以拉取和上传代码,部署秘钥只能拉取代码,建议本地开发使用个人秘钥,服务器部署使用部署秘钥,只用来拉取代码
配置个人秘钥
右上角头像 => 设置 => 左侧导航栏【SSH / GPG 密钥】 => 增加秘钥 => 秘钥内容【填写生成秘钥时创建的公钥内容,例如:gitea_key.pub】
配置项目部署秘钥
项目主页 => 右上角设置 => 左侧导航栏【部署密钥】 => 添加部署秘钥 => 秘钥内容【填写生成秘钥时创建的公钥内容,例如:gitea_key.pub】
拉取代码
项目主页的右上角,有HTTPS/SSH两种模式,这里我们使用ssh,切换到SSH选项卡,复制ssh拉取地址
bash
# 命令行解释:git clone gitea运行用户名@你的域名:用户名/项目名.git
git clone user@gdomain:username/project.git- user:gitea运行用户名
- domain:域名
- username:用户名
- project:项目名
webhook 钩子
项目主页 => 右上角设置 => 左侧导航栏【Web钩子】 => 右上角【添加web钩子】 => gitea
- 目标 URL:填写webhook钩子的访问url路径
- HTTP 方法: POST
- POST Content Type:application/json
- 密钥文本:填写您的秘钥
- 触发条件:推送事件
php钩子脚本代码
php
<?php
# gitea设置的webhook秘钥
$secret_key = '123';
# 网站根目录
$webDir = '/www/wwwroot/test';
# web运行用户
$wwwUser = 'www';
# web运行用户组
$wwwGroup = 'www';
/**
* 日志记录
* @param string $msg 日志内容
* @param string $file 日志文件路径
* @return void
*/
function logWrite($msg, $file = 'post.log')
{
file_put_contents($file,$msg.PHP_EOL,FILE_APPEND);
}
// 判断是否为POST方法
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
logWrite('FAILED - not POST - '. $_SERVER['REQUEST_METHOD']);
exit();
}
// 判断请求类型是否为:application/json
$content_type = isset($_SERVER['CONTENT_TYPE']) ? strtolower(trim($_SERVER['CONTENT_TYPE'])) : '';
if ($content_type != 'application/json') {
logWrite('FAILED - not application/json - '. $content_type);
exit();
}
// 判断是否有提交内容
$payload = trim(file_get_contents("php://input"));
if (empty($payload)) {
logWrite('FAILED - no payload');
exit();
}
// 判断加密字符串是否存在
$header_signature = isset($_SERVER['HTTP_X_GITEA_SIGNATURE']) ? $_SERVER['HTTP_X_GITEA_SIGNATURE'] : '';
if (empty($header_signature)) {
logWrite('FAILED - header signature missing');
exit();
}
// 验证秘钥
$payload_signature = hash_hmac('sha256', $payload, $secret_key, false);
if ($header_signature !== $payload_signature) {
logWrite('FAILED - payload signature');
exit();
}
// 判断请求内容是否为json格式
$decoded = json_decode($payload, true);
if (json_last_error() !== JSON_ERROR_NONE) {
logWrite('FAILED - json decode - '. json_last_error());
exit();
}
// 解析完成
logWrite('webhook钩子内容解析正确');
// 判断是否开启 shell_exec 函数,用于执行git拉取命令
if (!function_exists('shell_exec')){
logWrite('php 不支持 shell_exec 方法');
exit();
}
// 命令
$cmd = "cd $webDir && git pull 2>&1";
// 执行命令
$msg = shell_exec($cmd);
// 记录执行结果
logWrite($msg);
// 输出结果
echo $msg;