首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何使用PHP+WebHook自动同步Gitee、Github仓库内的代码到服务器?

如何使用PHP+WebHook自动同步Gitee、Github仓库内的代码到服务器?

作者头像
房东的狗丶
发布2023-02-17 15:20:00
1.1K0
发布2023-02-17 15:20:00
举报
文章被收录于专栏:友人a的笔记丶友人a的笔记丶

本文以Gitee作为演示,Github实现步骤是一样的,区别在于二者WebHook推送的数据有所区别。

WebHook

1.WebHook是什么

WebHook 功能是帮助用户 push 代码后,自动回调一个您设定的 http 地址。 这是一个通用的解决方案,用户可以自己根据不同的需求,来编写自己的相关程序。

实现过程

1.处理过程

  1. 远程仓库接收到Push推送,触发WebHook向接口推送更新的消息;
  2. 服务器接口接收到推送的更新消息,提取仓库地址、分支名、仓库名(仓库名用于同步多个仓库时进行区分);
  3. 接口将提取的更新信息,投递到后台的异步任务。
  4. 异步任务自动执行Git命令,同步指定仓库的代码到对应的目录。

2.功能组成

服务器后台运行一个PHP cli 脚本,脚本运行时启动一个SSH客户端,然后再运行一个Redis客户端,Redis保持订阅,接收来自接口的Redis消息发布。

每当Redis接收到发布的推送消息,触发回调,通过SSH客户端执行Git命令。

PHP SSH 客户端

https://cloud.tencent.com/developer/article/2218877

实际代码

1.HTTP接口

HTTP接口接收来自远程仓库的更新推送,然后把数据进行处理后推送给异步任务。

<?php

/*
 * 创建redis
 * */
function getRedis():Redis
{
    $redis = new Redis();
    $redis->connect("IP","端口");
    $redis->setOption(3, -1);
    return $redis;
}

/* 获取推送的数据 */
$json = file_get_contents("php://input");
$data = json_decode($json, true);

/* 判断推送是否来自指定的用户 */
if ($data['user_name'] != "friend-nicen") {
    exit("非法请求");
}

/* 处理数据 */
$need = [
    "clone" => $data['repository']["clone_url"], //远程仓库地址
    "path" => $data['repository']["path"], //远程仓库名
    "branch" => str_replace("refs/heads/", '', $data['ref'])  //分支
];

/*通过Redis订阅,进行任务投递*/
getRedis()->publish("RECV_GIT", json_encode($need));

exit("正在处理本次更新...");

2.PHP Cli脚本

使用前请先按照https://cloud.tencent.com/developer/article/2218877,安装PHP拓展,您需要准备:

  1. Redis的IP和端口
  2. SSH账号和密码
  3. 存放所有仓库的根目录
<?php

include_once 'vendor/autoload.php';

/* 引入SSH客户端 */
use phpseclib3\Net\SSH2;

/* 封装一下 */
class Ssh extends SSH2
{

    private $finish = "@EXEC@"; //结束的标志
    private $count = 1; //计算命令条数

    public function __construct($host, $port)
    {
        parent::__construct($host, $port);
    }

    /*
     * 获取当前命令的结束标志
     * */
    private function getEnd()
    {
        return $this->finish . "-" . $this->count;
    }

    /*
     * 读取消息
     * */
    public function read_raw()
    {

        $raw = "";  //缓存消息

        /*
         * 循环读取
         * */
        while (true) {

            $msg = $this->read('username@username:~$');

            if (!empty($msg)) {
                $raw .= $msg;
            }

            /* 结束的标记 */
            if (strpos($raw, $this->getEnd()) !== false) {
                break;
            }
        }

        /* 登录 */
        $raw = str_replace($this->getEnd(), "", $raw);
        return str_replace("&& echo", "", $raw);
    }


    /*
     * 执行命令并输出消息
     */
    public function exec_command($command)
    {
        $this->write($command . ' && echo ' . $this->getEnd() . "\n");
        echo $this->read_raw(); //读取初始化的消息
        $this->count++; //计数++
    }
}



/*
 * 创建redis
 * */
function getRedis():Redis
{
    $redis = new Redis();
    $redis->connect("IP","端口");
    $redis->setOption(3, -1);
    return $redis;
}


/* 结束的标志 */
$redis = getRedis(); //创建redis
$root = "/home/repos/"; //存放仓库的目录


/*
 * SSH连接配置
 * */
$ssh = new Ssh('localhost', 22);

/*如果登录失败*/
if (!$ssh->login('root', '************')) {
    exit();
}

sleep(1); //等待登录,防止write过快导致异常

/*设置读取间隔时间*/
$ssh->setTimeout(0.1);


/*
 * redis订阅消息
 * */
$redis->subscribe(["RECV_GIT"], function ($redis, $chan, $msg) use ($ssh, $root) {

    echo "收到消息:" . $msg . "\n"; //收到消息

    if (strpos($msg, "branch") === false) return;

    try {

        $data = json_decode($msg, true); //处理结果

        /*
          * 判断仓库是否存在
          * */
        $path = $root . $data['path']; //本地仓库路径

        /*
         * 仓库目录是否存在
         * 不存在则创建目录
         * */
        if (file_exists($path)) {
            $ssh->exec_command("rm -rf " . $path); //创建目录
        }

        $ssh->exec_command("mkdir " . $path); //创建目录
        $ssh->exec_command("cd " . $root); //打开所在目录

        $ssh->exec_command("git clone " . $data['clone']); //添加仓库

        echo "同步完毕\n";

    } catch (\Throwable $e) {
        echo $e->getMessage() . "\n";
    }
});

3.运行脚本

打开上方Cli脚本所在目录,运行如下命令:

# 前台运行
php 文件名.php  

# 后台台运行
nohup php 文件名.php  &

每次脚本运行的日志,会自动写入到当前目录的nohup.out文件,作为日志方便观察同步结果 ;

运行之后,每次仓库有更新,脚本都会自动同步这一次的更新;本文只是简单的实现,您完全可以通过这个案例实现更复杂的功能。

4.使用秘钥

<?php
use phpseclib3\Net\SSH2;
use phpseclib3\Crypt\PublicKeyLoader;

$key = PublicKeyLoader::load(file_get_contents("./include/ssh.pem"));
$ssh = new SSH2('localhost',22);
$ssh->login('root', $key));

5.解决异常的不知名报错

  • 重新启动网络服务器
  • 使用多个并行终端。有时关闭其中一个或两个窗口会有所帮助。
  • 使用 API 为 ssh 用户创建临时并行工作密码。也许我们“有时”登录太快了。创建并行密码后,在登录之前等待 1 秒。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WebHook
    • 1.WebHook是什么
    • 实现过程
      • 1.处理过程
        • 2.功能组成
        • 实际代码
          • 1.HTTP接口
            • 2.PHP Cli脚本
              • 3.运行脚本
                • 4.使用秘钥
                  • 5.解决异常的不知名报错
                  相关产品与服务
                  云数据库 Redis
                  腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档