Skip to content

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_key

gitea 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;