node实现github自动部署到云服务器

点击查看源码

目的

通过github管理的项目,每次push后都需要到服务器pull代码,然后手动打包,重复的操作挺糟心的。但是github提供了Webhooks,可以实现本地push代码到远程后,服务器自动拉取远程代码,自动打包部署,节省大量时间。

原理

github的Webhooks允许用户设置post请求的接口地址,当本地代码推送到远程分支后,github将主动调用设置的接口,并将当前修改相关信息作为请求参数给到接口。接口在服务器上被调用的时候,就知道当前远程代码库有更新,此时可以调用脚本执行更新、打包等操作。

用到的技术

接下来我会通过nodejs (opens new window)及github-webhook-handler (opens new window)模块实现监听github代码push的事件,然后通过shell (opens new window)脚本实现代码更新打包的操作。

前提条件

  • 具有公网ip的云服务器
  • github仓库

提供接口给github

接口的地址path通过github-webhook-handler模块配置产生,不需要自己额外的定义路由地址;同时需要设置secret,用于github校验。

github的webhooks

1、通过createHandler方法,可以配置path和secret,这两个参数自己随便定义就可以。

const createHandler = require('github-webhook-handler')
const handler = createHandler({ path: '/webhook', secret: 'sdsdfssdfsdf' })

2、监听push事件

handler.on('push', event=> {
   // github推送通知到接口后,会触发该方法,并拿到github请求的参数
});

3、监听error事件

handler.on('error', function (err) {
    console.error('Error:', err.message)
});

4、通过node的http模块启动服务

http.createServer( (req, res)=> {
    handler(req, res, function (err) {
        console.log('err',err);
        res.statusCode = 404
        res.end('api 404')
    });
}).listen(3001,()=>{
    console.log('running in http://127.0.0.1:3001/');
});

5、编写名为pull.sh的脚本

我的文章通过vuepress编写,所以我需要做的有三个步骤:

  • 进入到服务器上的vuepress项目
  • 通过git pull更新代码
  • 通过npm run docs:build打包代码
    当然,如果还有其他脚本也可以方进入,完整脚本如下:
#!/bin/bash 
# 更新代码
cd /xxx/xxx/项目名
git pull
npm run docs:build

6、监听到push事件后的处理

当监听到push事件后,event的payload参数中包含了github请求接口时的参数,而我只想处理master分支代码更新后,服务器自动拉取代码,因此只判断了event.payload.ref === 'refs/heads/master'时运行脚本;

通过node的require('child_process').spawn方法可以运行脚本,具体使用方法可见:child_process spawn(opens new window)

指定运行'sh'脚本,脚本路径为./bin/pull.sh,即可上面写的脚本文件。

spawn('sh', ['./bin/pull.sh']);
handler.on('push', event=> {
    try {
        const {repository,ref} = event.payload;
        const {full_name,name,private,size} = repository;
        const autoRun = ref === 'refs/heads/master';
        console.info(`
            - 接收到仓库:【${full_name}】的推送消息;
            - 修改分支:【${ref}】;
            - 仓库是否私有:${private};
            - 大小:【${size}】
            - 是否需要自动部署:${autoRun}】;
        `);

        // 判断是否需要自动部署
        if (!autoRun) {
            return
        }

        console.log('开始执行脚本');
        const s = spawn('sh', ['./bin/pull.sh']);
        s.stdout.on('data', (data) => {
          console.log(`${name}:${data}`);
        });
        s.stderr.on('data', (data) => {
          console.log(`${name}: ${data}`);
        });
        console.log('has rebuild');
    } catch (e) {
        console.log('build error',e)
    }
});

7、使用pm2运行项目

通过pm2可以让项目在服务器上一直运行,不会关闭服务器后项目就停。 在此,通过脚本实现接口项目的启动,在源码的bin/prod.sh (opens new window)中有如下脚本:

pm2 start npm -i 1 --name 'auto-run-github' -- run start

8、在github的webhooks中配置接口

如下图所示

  • Payload URL为你的接口地址,结尾应该是github-webhook-handler设置的path参数结尾;
  • Content type选择application/json;
  • Secret要和github配置保持一致;


完整代码如下:

const http = require('http')
const createHandler = require('github-webhook-handler')
const handler = createHandler({ path: '/webhook', secret: 'sdsdfssdfsdf' })
const spawn = require('child_process').spawn;

handler.on('error', function (err) {
    console.error('Error:', err.message)
});

handler.on('push', event=> {
    try {
        const {repository,ref} = event.payload;
        const {full_name,name,private,size} = repository;
        const autoRun = ref === 'refs/heads/master';
        console.info(`
            - 接收到仓库:【${full_name}】的推送消息;
            - 修改分支:【${ref}】;
            - 仓库是否私有:${private};
            - 大小:【${size}】
            - 是否需要自动部署:${autoRun}】;
        `);

        // 判断是否需要自动部署
        if (!autoRun) {
            return
        }

        console.log('开始执行脚本');
        const s = spawn('sh', ['./bin/pull.sh']);
        s.stdout.on('data', (data) => {
          console.log(`${name}:${data}`);
        });
        s.stderr.on('data', (data) => {
          console.log(`${name}: ${data}`);
        });
        console.log('has rebuild');
    } catch (e) {
        console.log('build error',e)
    }
});

http.createServer( (req, res)=> {
    handler(req, res, function (err) {
        console.log('err',err);
        res.statusCode = 404
        res.end('api 404')
    });
}).listen(3001,()=>{
    console.log('running in http://127.0.0.1:3001/');
});

你可能感兴趣的:(node实现github自动部署到云服务器)