nodejs实现简单的自动化部署

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 15:51   2101   0

如题,nodejs通过码云提供的web-hooks实现简单的服务器自动部署

大致流程:

1.通过码云提供的web-hooks,创建一个request通过后的回调接口(说白了就是配置一个码云审批通过触发的接口)

2.nodejs服务器监听监听这个接口,如果接口触发了,就执行自动部署逻辑。

3.创建文件夹,并将最新的目标分支上的文件下载到文件夹中;

安装文件依赖npm install(因为一般依赖目录不会上传到仓库的);

安装完依赖后进行npm run build进行项目打包。

4.通过执行shell脚本将打包后的文件上传到服务器。(这个脚本让后端部署人员写一个就行,一般就是doctor啥的)

目录结构:

具体细节演示和讲解:

1.webhooks相关的配置

进入如图所示页面,在url中配置可以访问到的域名+接口名称 ps:务必使用可使用的域名,本地地址无法使用

事件可以根据业务需求选择使用,一般自动化部署的话不是push就是pull request

点击测试按钮,如果能调通表示接口可以使用。

2.新建nodejs服务,并创建webhook.js,监听webhook发出的接口请求。

const http = require('http');
const shell = require("shelljs");
const createHandler = require('gitee-webhook-handler')
const config = require('./config');
const handler = createHandler({
    path: '/webhooks_push',//webhook ping的链接路径
    secret: '123456'//webhook 密码
});

console.log('hook文件启动成功')

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

//监听pr
handler.on('Merge Request Hook', function (event) {
    console.log('执行Merge Request Hook');
    let payload = event.payload;
    let branch = payload.target_branch;//合并的目标分支
    let pull_request = payload.pull_request;
    let state = pull_request.state;//PR当前的状态
    let branchs = config.branchs;
    if (state === 'merged') {//合并PR
        for (let i in branchs) {
            if (branchs[i].targetBranchName === branch) {
                shellstr = 'node index.js ' + branch
                shell.exec(shellstr);
            }
        }
    }
})

try {
    http.createServer(function (req, res) {
        handler(req, res, function (err) {
            res.statusCode = 404
            res.end('no such location')
        })
    }).listen(6666)
} catch (err) {
    console.error('Error:', err.message)
}

3.编写下载、安装依赖、打包发布脚本。本人不熟悉shell脚本语法,所以使用的js语法写的,如新建一个index.js文件

const fs = require("fs");
const shell = require("shelljs");  // 执行文件操作
const { promiseShellExec } = require('./utils/tools');
const config = require('./config');
require('console-color-mr');

//检查控制台是否以运行`git `开头的命令
//在控制台输出内容
if (!shell.which('git')) {
    shell.echo('Sorry, this script requires git');
    shell.exit(1);
}

console.log('指令文件启动')

//检查控制台是否以运行`docker `开头的命令
//在控制台输出内容
// if (!shell.which('docker')) {
//     shell.echo('Sorry, this script requires docker');
//     shell.exit(1);
// }

//处理下载分支(默认develop)
function handleBranch() {
    let branch = process.argv.length > 2 ? process.argv.splice(2) : 'develop';
    return branch;
}

//处理下载链接(如果config中配置了用户名和密码,那么将拼接在链接上)
function handleCloneDownloadUrl() {
    let downloadUrl = config.downloadUrl
    if (config.password && config.username && config.downloadUrl.length) {
        downloadUrl = downloadUrl.split('gitee.com')[0] + config.username + ':' + config.password + '@gitee.com' + downloadUrl.split('gitee.com')[1]
        console.log(downloadUrl)
    }
    return downloadUrl;
}

//处理上传shell指令
function handlePullServerShell(branch) {
    let pullServerShell = config.branchs[branch] ? config.branchs[branch].pullServerShell : ''
    if (!pullServerShell.length) {
        console.error('没有在配置文件中填写上传服务器指令!')
    }
    return pullServerShell;
}

//将下载的文件存放在build目录中
fs.exists('build', async function (exists) {
    if (exists) {
        shell.rm('-rf', 'build');
        console.info('build目录删除成功')
    }
    try {
        shell.mkdir('build');
        console.info('build目录创建成功')
        shell.cd('./build');
        console.info('进入build目录成功')
        await promiseShellExec('git init', 'git初始化成功', 'git初始化失败');
        let branch = handleBranch();
        let downloadUrl = handleCloneDownloadUrl();
        await promiseShellExec(`git clone -b ${branch} ${downloadUrl}`, '仓库下载成功', '仓库下载失败');
        if (shell.ls().code !== 0) {
            return console.error('获取文件信息失败!')
        }
        let folderName = shell.ls().stdout;
        let projectPath = './' + folderName;
        shell.cd(projectPath);
        await promiseShellExec('npm install', '依赖安装成功', '依赖安装失败');
        await promiseShellExec('npm run build', '文件打包成功', '文件打包失败');
        let pullServerShell = handlePullServerShell(branch);
        await promiseShellExec(pullServerShell, '文件上传成功', '文件上传失败');
        shell.cd('..');
    } catch (err) {
        console.error(err)
    }
})

为了方便复用,贴一下config配置

const config = {
    username: 'xxxxxxxxxxxxxxxxxx',//git 用户名
    password: 'xxxxxxxxxxxx',//git 用户密码
    downloadUrl: 'https://gitee.com/xxxxxxxxxxxx/xxxxxxx_home.git',//下载链接
    branchs: {//分支配置
        'develop':{//分支标识(使用分支名称)
            targetBranchName: 'develop',//分支名称
            pullServerShell: 'docker cp dist/ xxxxxxxxx:/app/web/teacher/'//上传至服务器指令(目前设置为docker)
        }
    }
};

module.exports = config;

基本部署流程如上,本文代码博主已经在测试环境跑过,能够顺利执行。但是因为服务器资源紧张,就没有放在正式环境中,当作学习的项目了。

个人再说明一下,github和码云的自动部署都可以通过这种方式实现,但是两者监听的方法名有区别的,github的方法名请参考gitee-webhook-handler库,码云的可能需要参考webhook配置项的钩子选项了。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP