网上查了一堆教程都是 Linux 的,最后自己在 Windows 下尝试实现了项目自动部署,写个笔记记录一下..

这是新博客创建后写的第一篇文章,同时由于从未使用过 MarkDown 语法,还是花了不少的时间去适应的.. 网上找到一篇 Hexo Markdown 简明语法手册 ,作为参考

这篇文章假定你已经在 Windows 下安装好 Git 并设定好账号、项目部署目录,以及 先clone一遍。如果你还没安装,网上有一堆教程,这里就不再废话了。

WebHook 的原理就是当项目触发了指定事件时(例如push),Coding 会以 POST 方式请求你指定好的地址(你写好的 php 接口),其中包含了事件的相关信息,例如 pusher 信息,commit 信息等..

新建WebHook:首先在你的项目页面找到 "设置"-"WebHook"-"新建WebHook"

新建WebHook

上图中我打码的那段链接就是我已经添加好的 WebHook

URL: WebHook访问的地址 内容类型: 选application/json 监听事件: 根据需要勾选

创建好后我们查看 Coding WebHook 开发文档Push事件 的相关说明,了解请求信息的键值含义:

Key Value
hook_id 当前 WebHook 的 ID
hook 当前 WebHook 的配置数据
ref 推送的 commit sha
before 该分支之前的 commit sha
after 该分支新的 commit sha
compare compare 的 url 地址
commits 更新的 commits 内容
head_commit 最新的 commit 内容
pusher 推送者

然后,你就可以去项目里随便触发一次 push 事件,之后到 "设置"-"WebHook"-"修改"里,点击发送记录,就可以查看 POST 请求的完整 JSON 数据。

这是一段请求例子:
请求头部

Request URL: http://yourserver/test/test_webhook.php Request method: POST User-Agent: Coding.net Hook X-Coding-Event: push X-Coding-Delivery: 6c228fe0-6f10-4f4e-85d5-88fe59b55534 X-Coding-WebHook-Version: v2 X-Coding-Signature: sha1=6acb186554d58b5e61c004ad2396601142fa9fdf

请求内容(部分信息已隐藏)

{
  "ref": "refs/heads/master", 
  "before": "a2099911911e3f8a0090e5351b01b8952f5068fd",
  "after": "3638f90bf79b2eb02259c4a2f594e362953a464d",
  "created": false,
  "deleted": false,
  "compare": "...",
  "commits": [
​    {
​      "id": "3638f90bf79b2eb02259c4a2f594e362953a464d",
​      "distinct": false,
      "message": "push的信息\n",
​      "timestamp": 1543366074000,
      "url": "相关commit页面",
​      "author": {
​        "name": "CrazyKidCN",
​        "email": "[email protected]",
​        "username": "..."
​      },
​      "committer": {
​        "name": "CrazyKidCN",
​        "email": "[email protected]",
​        "username": "..."
​      },
​      "added": [],
​      "removed": [
        "testfile.txt" //此次push删除了一个文件
      ],
​      "modified": []
​    }
  ],
  "head_commit": {
​    "id": "3638f90bf79b2eb02259c4a2f594e362953a464d",
​    "distinct": false,
​    "message": "test add push\n",
​    "timestamp": 1543366074000,
    "url": "...",
​    "author": {
​      "name": "CrazyKidCN",
​      "email": "[email protected]",
​      "username": "..."
​    },
​    "committer": {
​      "name": "CrazyKidCN",
​      "email": "[email protected]",
​      "username": "..."
​    },
​    "added": [],
​    "removed": [
​      "testfile.txt"
​    ],
​    "modified": []
  },
  "pusher": { //推送人信息"name": "...",
​    "email": "...",
​    "username": "..."
  },
  "sender": {
    "id": ..., //Coding 用户ID
    "login": "...", //Coding 用户名称
    "avatar_url": "...", //Coding 用户头像
    "url": "...",
​    "html_url": "...",
​    "name": "CrazyKidCN",
​    "name_pinyin": ""
  },
  "repository": {
​    "id": ..., //repo id
    "name": "...", //repo名称
    "full_name": "", //repo全名
    "owner": { //repo所有者
      "id": ...,
​      "login": "CrazyKidCN",
​      "avatar_url": "https://dn-coding-net-production-static.qbox.me/837a90ac-5efb-4f67-bbed-11178d80c683.jpg?imageMogr2/auto-orient/format/jpeg/crop/!596x596a0a0",
​      "url": "...",
​      "html_url": "https://coding.net/u/CrazyKidCN",
​      "name": "CrazyKidCN",
​      "name_pinyin": ""
​    },
​    "private": true,
    "html_url": "...", //repo地址(html超链接形式)
    "description": "",
​    "fork": false,
    "url": "...", //repo地址
    "created_at": 1523760758000,
​    "updated_at": 1523760758000,
    "clone_url": "...",
​    "ssh_url": "...",
​    "default_branch": "master"
  }
}

然后我们就可以开始写 php 来解析其中的 json 了。下面以实现触发 push 事件后自动部署项目为例子,我的代码:

$header = get_all_header(); //获取头信息
$json = json_decode(file_get_contents('php://input'), true); //解析json

//验证信息是否正确
if (strcmp($header["user-agent"], "Coding.net Hook")==0 &&
​	strcmp($header["x-coding-event"], "push")==0 &&
​	strcmp($json["repository"]["name"], "项目名称")==0 )
{
   //区别于Linux系统的地方
​	$shell = 'cd C:/test && "C:\Program Files\Git\cmd\git.exe" pull 2>&1';
​	
   //运行命令
   exec($shell,$out);

   //输出git结果到log.txt
   file_put_contents("log.txt", "\nGit output: ".$out."\n");
}

exit("");


function get_all_header()
{
​	$ignore = array('host','accept','content-length','content-type');
​	$headers = array();
​	foreach($_SERVER as $key=>$value){
​		if(substr($key, 0, 5)==='HTTP_'){
​			$key = substr($key, 5);
​			$key = str_replace('_', ' ', $key);
​			$key = str_replace(' ', '-', $key);

			$key = strtolower($key);
			if(!in_array($key, $ignore)){
			  $headers[$key] = $value;
			}
		}
	}
	return $headers;
}

区别于网上Linux系统的教程,最关键的一句话是:

$pull = 'cd C:/test && "C:\Program Files\Git\cmd\git.exe" pull 2>&1';

其中, cd C:/test 为切换到你的项目部署目录, "C:\Program Files\Git\cmd\git.exe" pull 等同于 git pull,只不过手动指定了git程序的地址。最后的 2>&1 解决无法正确输出 $out 的问题。

这样,就实现了push后自动部署项目了。。。


后续:进一步获取commit中文件的变动详情,从而实现更多针对性的操作,我的代码:

for ($j=0; $j<count($json["commits"]); $j++){ //由于一次可push多个commit,所以要遍历数组
​	file_put_contents("log.txt", "File added:".count($json["commits"][$j]["added"])."\n", FILE_APPEND);
​	for ($i=0; $i<count($json["commits"][$j]["added"]); $i++){
​		file_put_contents("log.txt", $json["commits"][$j]["added"][$i]."\n", FILE_APPEND);
​	}
​	
​	file_put_contents("log.txt", "File removed:".count($json["commits"][$j]["removed"])."\n", FILE_APPEND);
​	for ($i=0; $i<count($json["commits"][$j]["removed"]); $i++){
​		file_put_contents("log.txt", $json["commits"][$j]["removed"][$i]."\n", FILE_APPEND);
​	}
​	
	file_put_contents("log.txt", "File modified:".count($json["commits"][$j]["modified"])."\n", FILE_APPEND);
	for ($i=0; $i<count($json["commits"][$j]["modified"]); $i++){
		file_put_contents("log.txt", $json["commits"][$j]["modified"][$i]."\n", FILE_APPEND);
	}
}

以上!
由于本人仍在学习 git 和 php ,文章难免存在错误,请各位大佬多多指教,感谢ww
博客的第一篇文章完工,成就感满满的呢~