如何在Node.js中部署GitHub Webhook

403 阅读2分钟

下面的实现是我作为一个软件开发者的日常工作中的一个快速摘录。如果我遇到一个问题,并得出一个我认为值得分享的例子,我将把代码的要点放在这个网站上。它可能对其他偶然遇到相同任务的人有用。

下面的实现告诉你如何在Node.js中部署一个Github Webhook。就我个人而言,我正在使用这种GitHub Webhook来在Digital Ocean上自动部署我的网站。无需通过SSH进入我的Web服务器来手动部署我的网站,我的DigitalOcean实例上不断运行的Webhook可以确保(A)从GitHub提取最近的变化,(B)建立我的网站。

GitHub上的Webhook设置

首先决定你要为哪个GitHub仓库运行Webhook。然后,导航到该项目设置Webhooks。在那里你可以为这个GitHub仓库创建一个新的Webhook。

github webhook

首先,无论你是在DigitalOcean还是其他地方运行你的应用程序,最后,你只需要找出有可能与你的托管Webhook在下一步用Node.js实现通信的URL或IP地址。把这个地址放在Payload URL字段中。就我个人而言,我只是在这里使用IP地址和我将在Webhook的实现中引入的端口(例如:http://133.66.66.66:8080 )。

第二,将内容类型设置为application/json。第三,创建一个秘密字符串,不应该与其他人分享。最后,我们只希望在有人向我们的 GitHub 仓库推送新内容时收到事件。

使用 Node.js 的 GitHub Webhook

如果你没有一个正常运行的Node.js应用程序,可以看看这个最小的Node.js教程,以帮助你开始。最后,你的Node.js应用程序的Webhook所需要的一切就是以下的实现。

import http from 'http';
import crypto from 'crypto';
import { exec } from 'child_process';

const SECRET = 'MY_GITHUB_WEBHOOK_SECRET';

http
  .createServer((req, res) => {
    req.on('data', chunk => {
      const signature = `sha1=${crypto
        .createHmac('sha1', SECRET)
        .update(chunk)
        .digest('hex')}`;

      const isAllowed = req.headers['x-hub-signature'] === signature;

      const body = JSON.parse(chunk);

      const isMaster = body?.ref === 'refs/heads/master';

      if (isAllowed && isMaster) {
        // do something
      }
    });

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

该实现显示了一个在Node.js中运行的裸体HTTP服务器。一旦它被部署,它就会收到GitHub的Webhook请求;鉴于Payload URL被正确设置为你部署的Webhook。

还要确保将SECRET 替换为新的 GitHub Webhook 中的Secret。只有这样,只有你能对这个Webhook进行验证调用(见isAllowed boolean)。

此外,只有当有东西被推送到主分支时,我们才会在这个 Webhook 中做一些事情(见isMaster boolean)--如果你想用这个 Webhook 来部署你的 GitHub 仓库的最新版本,这是有意义的。如需进一步帮助,请交叉阅读DigitalOcean的这个教程

部署GitHub Webhook

现在,我们要把 Webhook 作为运行中的服务部署到 DigitalOcean -- 或者你所使用的任何主机提供商。因此,请遵循以下步骤:

  • 为你的Webhook项目创建一个独立的GitHub仓库。
  • 克隆这个Webhook项目到你的网络服务器上。
  • 确保它在你的网络服务器上运行,npm start

现在你可以在Github上为你创建Webhook的仓库执行一个样本请求。请求应该通过,你应该能够在以下两个地方看到一些:

    1. Github的Webhook控制台
    1. 通过你的Webhook项目的console.log()

接下来,我们将使Webhook项目在你的Web服务器上成为一个持续运行的HTTP服务器--如果出现问题,它也会重启。我们将使用PM2--一个Node.js进程管理器--来在我们的Web服务器上运行应用程序。首先,通过命令行在你的Web服务器上全面安装PM2:

sudo npm install -g pm2

其次,运行你的应用程序。

pm2 start my-github-webhook

如果你需要让PM2为你运行一个npm脚本,你可以用以下命令来代替触发它。

pm2 start npm --name my-github-webhook -- start

PM2应该输出一个你所有正在运行的应用程序的进程列表。现在,你不需要再担心手工启动你的Node.js应用程序。PM2会处理好这个问题。如果你需要更多关于DigitalOcean上的PM2的阅读,请交叉阅读DigitalOcean上的这个教程

自动网站部署

最后但同样重要的是,你需要在GitHub Webhook中实现必要的代码,以便自动部署你的网站或任何其他应用程序。例如,你可以用下面这行代码取代// do something

exec('cd /home/rwieruch/my-website && npm run build');

而你必须用你自己的路径和npm脚本来替换。如果执行中的命令变得冗长,可以考虑给你的项目--你要用Webhook部署的项目--一个bash脚本,执行所有内容来部署网站。

exec('cd /home/rwieruch/my-website && bash deploy.sh');

另外,如果你想在多个网络应用程序/网站部署中重复使用Webhook,你可以让执行脚本依赖于来自不同GitHub仓库的Webhook请求的传入。

import http from 'http';
import crypto from 'crypto';
import { exec } from 'child_process';

const SECRET = 'MY_GITHUB_WEBHOOK_SECRET';

const GITHUB_REPOSITORIES_TO_DIR = {
  'rwieruch/my-website-one-on-github': '/home/rwieruch/my-website-one',
  'rwieruch/my-website-two-on-github': '/home/rwieruch/my-website-two',
};

http
  .createServer((req, res) => {
    req.on('data', chunk => {
      const signature = `sha1=${crypto
        .createHmac('sha1', SECRET)
        .update(chunk)
        .digest('hex')}`;

      const isAllowed = req.headers['x-hub-signature'] === signature;

      const body = JSON.parse(chunk);

      const isMaster = body?.ref === 'refs/heads/master';
      const directory = GITHUB_REPOSITORIES_TO_DIR[body?.repository?.full_name];

      if (isAllowed && isMaster && directory) {
        try {
          exec(`cd ${directory} && bash deploy.sh`);
        } catch (error) {
          console.log(error);
        }
      }
    });

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

这种方法需要你为所有需要自动部署的GitHub仓库创建具有相同秘密的GitHub Hooks。此外,每个要部署的网站/网络应用都必须有一个bash的deploy.sh文件。你可以在这里找到我的GitHub Webhook实现,它为我的网站提供动力。