GitHub / GitLab Webhook 接口开发指南

前一阵子要开发一个从 GitLab / GitHub 通过 Webhook 拉取文件并且上传指定 OSS 的接口,于是就找起了 GitHub 和 GitLab 的官方文档。

当然官方文档实在是太过冗长,尤其是公司自建的 GitLab 版本还有可能不一致,所以就只能看搭建的 GitLab 提供的文档信息,对于一些遇到的问题就看命看版本查了。

当然所幸除了接口版本以外并没有遇到什么太大的坑,遇到了问题也可以根据版本来查,可以说这绝对是严格遵照 RESTful API 的一个优点,这一点无论是 GitHub 还是 GitLab 都做得很好。

由于 GitLab 和 GitHub 用的是两套接口,所以这里分开来介绍,不过方法都是相同的:

拉取压缩包,解压缩,上传文件。另一种方法是 git clone 下来,但是感觉 git clone 依旧太麻烦,所以就选了拉取压缩包。

GitLab

下载压缩包的接口:https://docs.gitlab.com/ee/api/repositories.html#get-file-archive

这里有两个参数:

id (required) - The ID or URL-encoded path of the project owned by the authenticated user
sha (optional) - The commit SHA to download defaults to the tip of the default branch

这里需要两个信息,project 的 id 与 sha,都可以通过 Webhook 获得:

const { checkout_sha: checkoutSha, project_id: projectId } = body

但是不同的是 id 是放在 参数(param)中的,而 sha 则是以 querystring 传入的(GitHub 与它不一样),如果不传入 sha,默认为 master 分支最新的代码。

当然,我们还会设置 secret token,这个 secret token 可以通过 header 中的 x-gitlab-token 获得。

然后我们就得到了 GitLab 的相关信息。

如果 API 中获取的内容需要权限,可以使用 PRIVATE-TOKEN 这一 header 传入 token。

GitHub

GitHub 的 Webhook 接口方式与 GitLab 有点不同,我们这里使用的还是 V3 版的 Restful 接口。

针对 GitHub 的 Webhook 最重要的是怎么计算出 secret token 与我们原先设定的相一致。GitHub 就没有 GitLab 那么简单了,我们需要先计算一番,具体可见Validating payloads from GitHub,如果看不懂 Ruby 没关系,下面提供一段 JavaScript:

const strBody = JSON.stringify(body); // 将整个 body 带出去变成 string
const sign = crypto.createHmac("sha1", secretKey) // secretKey 为你需要核对的 token
  .update(strBody)
  .digest("hex"); // 加密成十六进制
ctx.assert(ctx.header["x-hub-signature"].replace("sha1=", "") === sign, 403, "Wrong Sign");

然后把 header 中的 x-hub-signature 带有 sha1=value 中的 value 和 sign 作对比即可。

其次 GitHub 需要通过 header 中的 x-github-event 来判断 event 的类型,否则会出错,不同的 Event 传入的内容可能不一样,需要对 ping 做一些特殊处理,如果是 ping,直接返回 200,这样就可以过 GitHub 的检查了。

从 request body 中,你还可以找到 repository 信息和相对应的 commit 的信息,也可以获得 Repo Org 的信息(这里我们不需要仓库 Org,所以暂不表述)

const { repository, head, head_commit: headCommit } = body;

我们需要的接口是:

https://github.com/${org}/${repositoryName}/archive/${sha}.zip

其中:

repositoryName = repository.name
sha = headCommit.id

其中如果需要授权,在 header 中写入:

"Authorization": `token ${TOKEN}`

如果您觉得文章不错,可以通过赞助支持我

标签: 知识, 代码段, 语法

添加新评论