如何使用Node.js和Github Webhooks保持远程项目同步

在本指南中,您将开发一个Node.js服务器,只要您或其他人将代码推送到GitHub,它就会监听GitHub webhook通知。此脚本将使用最新版本的代码自动更新远程服务器上的存储库,从而无需登录服务器来提取新提交。

介绍

在处理具有多个开发人员的项目时,当一个人推送到存储库然后另一个人开始对过时版本的代码进行更改时,这可能会令人沮丧。 像这些花费时间的错误,这使得设置脚本以保持您的存储库同步是值得的。 您还可以在生产环境中应用此方法以快速推送修补程序和其他更改。

虽然存在其他解决方案来完成此特定任务,但编写自己的脚本是一种灵活的选项,为将来的自定义留出了空间。

GitHub允许您为存储库配置webhook ,这些事件是在事件发生时发送HTTP请求的事件。 例如,您可以使用webhook在有人创建拉取请求或推送新代码时通知您。

在本指南中,您将开发一个Node.js服务器,只要您或其他人将代码推送到GitHub,它就会监听GitHub webhook通知。 此脚本将使用最新版本的代码自动更新远程服务器上的存储库,从而无需登录服务器来提取新提交。

先决条件

要完成本教程,您需要:

  • 一个Ubuntu 16.04服务器按照Ubuntu 16.04初始服务器设置指南进行设置 ,包括具有sudo权限和防火墙的非root用户。
  • Git安装在本地计算机上。 您可以按照教程贡献开源:Git入门在您的计算机上安装和设置Git。
  • Node.js和npm使用官方PPA安装在远程服务器上,如在Ubuntu 16.04上如何安装Node.js中所述 安装发行版稳定版就足够了,因为它为我们提供了推荐的版本而无需任何其他配置。
  • Github上的一个存储库,包含您的项目代码。 如果您没有考虑项目,请随意分享我们将在本教程的其余部分中使用的示例。

第1步 - 设置Webhook

我们首先为您的存储库配置webhook。 这一步很重要,因为没有它,Github不知道发生事件时要发送什么事件,或者发送它们的位置。 我们将首先创建webhook,然后创建将响应其请求的服务器。

登录您的GitHub帐户并导航到您要监控的存储库。 单击存储库页面顶部菜单栏中的“设置”选项卡,然后单击左侧导航菜单中的“ Webhooks ”。 单击右上角的添加Webhook ,然后在出现提示时输入您的帐户密码。 你会看到一个如下所示的页面:

Webhooks页面

  • Payload URL字段中,输入http:// your_server_ip :8080 这是我们即将编写的Node.js服务器的地址和端口。
  • Content类型更改为application/json 我们将编写的脚本将需要JSON数据,并且无法理解其他数据类型。
  • 对于Secret ,请输入此webhook的密码。 您将在Node.js服务器中使用此秘密来验证请求并确保它们来自GitHub。
  • 对于您想要触发此webhook 的事件 ,请选择推送事件 我们只需要push事件,因为那时代码已更新并需要同步到我们的服务器。
  • 选中“ 活动”复选框。
  • 查看字段,然后单击添加webhook以创建它。

ping将首先失败,但请放心,您的webhook现已配置完毕。 现在让我们将存储库克隆到服务器。

第2步 - 将存储库克隆到服务器

我们的脚本可以更新存储库,但它最初无法处理设置存储库,所以我们现在就这样做。 登录您的服务器:

ssh sammy@your_server_ip

确保您在主目录中。 然后使用Git克隆您的存储库。 一定要用你的GitHub用户名替换sammy用你的Github项目名称替换hello_hapi

cd
git clone https://github.com/sammy/hello_hapi.git

这将创建一个包含项目的新目录。 您将在下一步中使用此目录。

克隆项目后,您可以创建webhook脚本。

第3步 - 创建Webhook脚本

让我们创建我们的服务器来监听来自GitHub的那些webhook请求。 我们将编写一个Node.js脚本,用于在端口8080上启动Web服务器。 服务器将监听来自webhook的请求,验证我们指定的秘密,并从GitHub中提取最新版本的代码。

导航到您的主目录:

cd ~

为您的webhook脚本创建一个名为NodeWebhooks的新目录:

mkdir ~/NodeWebhooks

然后导航到新目录:

cd ~/NodeWebhooks

NodeWebhooks目录中创建一个名为webhook.js的新文件。

nano webhook.js

将这两行添加到脚本中:

webhook.js
var secret = "your_secret_here";
var repo = "/home/sammy/hello_hapi";

第一行定义了一个变量来保存您在第1步中创建的秘密,该变量验证请求来自GitHub。 第二行定义了一个变量,该变量包含要在本地磁盘上更新的存储库的完整路径。 这应该指向您在第2步中签出的存储库。

接下来,添加这些将httpcrypto库导入到脚本中的行。 我们将使用这些来创建我们的Web服务器并散列秘密,以便我们可以将它与我们从GitHub收到的内容进行比较:

webhook.js
let http = require('http');
let crypto = require('crypto');

接下来,包含child_process库,以便您可以从脚本执行shell命令:

webhook.js
const exec = require('child_process').exec;

接下来,添加此代码以定义处理GitHub webhook请求的新Web服务器,如果它是真实的请求,则下拉新版本的代码:

webhook.js
http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let payload = JSON.parse(chunk.toString());
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

http.createServer()函数在端口8080上启动Web服务器,该服务器监听来自Github的传入请求。 出于安全目的,我们验证请求中包含的秘密与我们在第1步中创建webhook时指定的秘密相匹配。秘密在x-hub-signature标头中作为SHA1散列字符串传递,因此我们将我们的秘密哈希并将其与GitHub发送给我们的内容进行比较。

如果请求是可信的,我们执行shell命令以使用git pull更新我们的本地存储库。

完成的脚本如下所示:

webhook.js
const secret = "your_secret_here";
const repo = "~/your_repo_path_here/";

const http = require('http');
const crypto = require('crypto');
const exec = require('child_process').exec;

http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let payload = JSON.parse(chunk.toString());
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

如果您按照初始服务器设置指南进行操作,则需要允许此Web服务器通过允许端口8080上的流量与外部Web通信:

sudo ufw allow 8080/tcp

现在我们的脚本已经到位,让我们确保它正常工作。

第4步 - 测试Webhook

我们可以通过使用node在命令行中运行它来测试我们的webhook。 启动脚本并在终端中打开进程:

cd ~/NodeWebhooks
nodejs webhook.js

返回Github.com上的项目页面。 单击存储库页面顶部菜单栏中的“设置”选项卡,然后单击左侧导航菜单中的“ Webhooks ”。 单击您在第1步中设置的webhook旁边的编辑 。向下滚动,直到看到Recent Exiveries部分,如下图所示:

编辑Webhook

按下最右边的三个点以显示Redeliver按钮。 在节点服务器运行的情况下,单击“ Redeliver ”再次发送请求。 一旦确认要发送请求,您将看到成功的响应。 重新启动ping后,这由200 OK响应代码表示。

我们现在可以继续确保我们的脚本在后台运行并在启动时启动。 使用CTRL+C停止节点webhook服务器。

第5步 - 将Webhook安装为Systemd服务

systemd是Ubuntu用来控制服务的任务管理器。 我们将设置一个服务,允许我们在启动时启动webhook脚本,并使用systemd命令来管理它,就像我们使用任何其他服务一样。

首先创建一个新的服务文件:

sudo nano /etc/systemd/system/webhook.service

将以下配置添加到服务文件,该文件告诉systemd如何运行脚本。 这告诉Systemd在哪里找到我们的节点脚本并描述我们的服务。

确保用您的用户名替换sammy

/etc/systemd/system/webhook.service
[Unit]
Description=Github webhook
After=network.target

[Service]
Environment=NODE_PORT=8080
Type=simple
User=sammy
ExecStart=/usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

启用新服务,以便在系统引导时启动:

sudo systemctl enable webhook.service

现在开始服务:

sudo systemctl start webhook

确保服务已启动:

sudo systemctl status webhook

您将看到以下输出,指示该服务处于活动状态:

● webhook.service - Github webhook
   Loaded: loaded (/etc/systemd/system/webhook.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2018-08-17 19:28:41 UTC; 6s ago
 Main PID: 9912 (nodejs)
    Tasks: 6
   Memory: 7.6M
      CPU: 95ms
   CGroup: /system.slice/webhook.service
           └─9912 /usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js

您现在可以将新提交推送到存储库并查看服务器上的更改。

从桌面计算机克隆存储库:

git clone https://github.com/sammy/hello_hapi.git

对存储库中的一个文件进行更改。 然后提交文件并将代码推送到GitHub。

git add index.js
git commit -m "Update index file"
git push origin master

webhook将触发,您的更改将显示在您的服务器上。

结论

您已经设置了一个Node.js脚本,该脚本将自动将新提交部署到远程存储库。 您可以使用此过程来设置您要监视的其他存储库。 您甚至可以将其配置为在推送存储库时将网站或应用程序部署到生产环境。