部署PHP+Swoole实现自动更新项目的GitHub Webhooks

发布时间 2023-06-25 17:32:06作者: A-GREATE-USERNAME

前言

在项目开发过程中,每次需要手动登录服务器并执行git pull命令来更新代码,这样非常繁琐和耗时。为了简化这个过程,我们可以利用GitHub的Webhooks功能,结合PHP和Swoole来编写一个自动更新项目的接口脚本。

实现步骤

以下是实现自动更新项目的GitHub Webhooks的步骤:

  1. 首先,你得有一个github项目,进入github项目,点击设置 -》webhooks-》add webhook
    • 配置Payload URL:将Payload URL设置为你自己服务器的脚本地址。
    • 选择Content type:如果你用的是swoole部署的自动更新脚本,那么需要确保请求是application/x-www-form-urlencoded或multipart/form-data格式发送的。如果content-type不是这俩种类型swoole可能无法正确解析post数据。所以webhooks的content
      type需要配置为application/x-www-form-urlencoded
    • 填写“Secret”,后续接口校验会用到
    • 选择"Which events would you like to trigger this webhook?":我这边选择“Just the push event.”,当推送时触发webhook
    • 保存并更新Webhook配置。
  2. 确保已经安装了Swoole扩展
  3. 创建一个名为GitWebhook的PHP类,用于处理GitHub Webhooks的请求。
    • 在OnRequest方法中,获取请求的URI,并检查是否为有效的目录。
    • 校验请求的事件类型,确保为推送事件。
    • 获取请求的签名,并使用密钥进行校验。
    • 解析请求中的JSON数据,提取相关的提交信息,如提交ID、作者、提交消息等。
    • 执行git pull命令来更新项目代码,并将执行结果保存在一个变量中。
    • 在控制台输出更新日志和执行结果。
    • 响应GitHub Webhooks请求,返回更新成功的消息。
  4. 启动Swoole HTTP 服务:php GitWebhook.php

以下是GitWebhook类的PHP代码:

class GitWebhook
{
    public $http;
    public $dir = [
        'fastadmin',
        'chat',
    ];
    private $secret = '20230625';//密钥

    public function __construct()
    {
        $this->http = new Swoole\Http\Server('0.0.0.0', 9501);
        $this->http->on('Request', [$this, 'OnRequest']);
        $this->http->start();
    }

    /**
     * @param $request
     * @param $response
     */
    public function OnRequest($request, $response)
    {
        $uri = trim($request->server['request_uri'], '/');
        if (!in_array($uri, $this->dir, true)) {
            $response->status(500);
            $this->show($request, $response, '目录丢失');
            return;
        }

        $event = $request->header['x-github-event'] ?? '';
        if ($event !== 'push') {
            $response->status(500);
            $this->show($request, $response, '错误事件:' . $event);
            return;
        }
        // 签名
        $signature = $request->header['x-hub-signature-256'] ?? '';
        if (!$signature) {
            $response->status(403);
            $this->show($request, $response, '没有权限');
            return;
        }
        list($algo, $hash) = explode('=', $signature, 2);

        //需要确保请求是application/x-www-form-urlencoded或multipart/form-data格式发送的。如果content-type不是这俩种类型,
        //swoole可能无法正确解析post数据。
        //所以webhooks的content type需要配置为application/x-www-form-urlencoded
        $_hash = hash_hmac($algo, $request->rawContent(), $this->secret);
        //校验
        if ($hash !== $_hash) {
            $response->status(403);
            $this->show($request, $response, '没有权限');
            return;
        }

        $payload = json_decode($request->post['payload'], true);
        $commit  = $payload['head_commit']['id'];
        $author  = $payload['head_commit']['author']['name'];
        $message = $payload['head_commit']['message'];

        echo "【{$uri}】 " . date('Y-m-d H:i:s') . ": Push event received. Commit: {$commit}, Author: {$author}, Message: {$message}\n";
        $output = shell_exec("cd /www/{$uri} && git pull 2>&1");
        echo $output . PHP_EOL;

        $response->end(' Webhook 更新成功.');
    }

    private function show($request, $response, $msg)
    {
        print_r($request->header, null);
        echo $msg, PHP_EOL;

        $response->end($msg);
    }
}

(new GitWebhook());

测试

随便修改提交文件,观察控制台是否有以下内容输出:

root@57b11c01f356:/www/fastadmin/swoole# php GitWebhook.php 
【chat】 2023-06-25 08:05:15: Push event received. Commit: 156037988721162341e4b24df328ab9db2e79abe, Author: **, Message: 测试webhook
From github.com:**/chat
   4a5a5f2..1560379  main       -> origin/main
Updating 4a5a5f2..1560379
Fast-forward
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

看到类似上面内容输出说明测试成功了。

这时候你也可以到webhooks的Recent Deliveries 查看最最新一条记录body返回内容是否为:"Webhook 更新成功."