如题,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配置项的钩子选项了。
|