最近在开发中,经常接触到gitlab的自动化构建和部署。gitlab是如何实现这种自动化?自己能不能实现呢?带着这种思想,一步一步探索。
- 喜欢的可以点赞和
star
噢,欢迎issue
和PR
。 - 完整代码
- 注意:不要在
windows
运行,-exec
会报错
实现思路
- 监听文件变化
- 读取项目配置文件
- 执行项目配置命令,并替换变量
其中执行项目命令包括:
- 查找文件,替换特定字符串
- 安装依赖包
- 构建项目
- 复制私钥,使用scp免密上传,把构建文件上传到服务器
- 删除复制私钥
- 执行成功输出success, 失败删除私钥
开发准备
node.js
: 使用child_process
模块中的exec
方法执行common
, 使用fs
模块中的readFile
方法读取配置文件。chokidar
: 监听文件变动lodash
: 使用debounce
实现防抖pm2
:管理node项目- 服务器一台
服务器scp免密传输配置
- 安装
ssh
:yum install -y openssl openssh-server
- 开启ssh服务:
启动ssh的服务:
systemctl start sshd.service
设置开机自动启动ssh服务
systemctl enable sshd.service
- 在
node
代码运行终端上,生成私钥和秘钥ssh-keygen -t rsa -C "xxxxx@xxxxx.com"
- 把公钥内容放到服务器的
/root/.ssh/authorized_keys
文件中。
正式开发
1. 初始化chokidar
实现文件监听
// 初始化watcher
const watcher = chokidar.watch(watchPath,{
awaitWriteFinish: {
stabilityThreshold: 2000,
pollInterval: 100
},
// 忽略的文件
ignored: /node_modules|build|dist|\.pem|\.sed/,
ignoreInitial: true, // 初始化不执行文件事件
cwd: '.', // 表示当前目录
});
忽略监听
node_modules
、build
和dist
文件的原因是:当执行安装依赖和构建的时候,会生成文件,从而触发文件监听事件。
.pem
和.sed
是生成私钥文件和替换文件,所以也要被忽略。
2. 获取项目配置(类似gitlab的ci文件)
const getProjectConf = (path)=>{
return new Promise((resolve, reject)=>{
fs.readFile(path,(err, data)=>{
let conf = {};
if (err){
log('yellow', `${path} file not find, use default conf`);
}else {
conf = JSON.parse(data);
}
resolve(conf);
})
})
};
// 获取配置
global.projectConf = await getConf.getProjectConf(`${config.WATCH_PATH}/${config.PROJECT_CONF_NAME}`);
3. 执行项目配置命令
- 在执行命令之前,我们需要把特定字符串替换的。格式为
${your_string}
function commonReplaceString(common){
const match = common.match(/\$\{([^]+?)\}/g);
if (match){
match.forEach(o=>{
const current = o.replace(/\${|\}/g, '');
try {
const val = config.REPLACE_STRINGS[current];
if (val){
o.replace(current,config.REPLACE_STRINGS[current]);
common = common.replace(o,config.REPLACE_STRINGS[current]);
}
}catch (e) {
console.log(e);
}
})
}
return common;
}
- 正式执行命令
const commons = global.projectConf.commons;
// 不要用forEach 配合await执行命令,这样执行顺序不会如你所愿
for (const common of commons){
await utils.execFn(utils.commonReplaceString(common))
}
看起来高大尚,其实使用
node
这部分核心代码就这点儿。
项目配置
{
"commons": [
"echo --- Replace string ---",
"echo s/___TEST_STRING___/${TEST_STRING}/g > pattern.sed ",
"find . \\( -path \"./dist\" -o -path \"./node_modules\" \\) -prune -o -type f \\( -iname \"*.js\" -o -iname \"*.html\" -o -iname \"*.vue\" \\) -print -exec sed -i -f pattern.sed {} \\;",
"rm -rf pattern.sed",
"echo Replace success",
"echo --- Install dependent ---",
"yarn install",
"echo --- Start build project ---",
"npm run build",
"echo --- Get primary key ---",
"cat ${PRIVATE_KEY} > ${PRIVATE_KEY_FILE_NAME}",
"chmod 600 ${PRIVATE_KEY_FILE_NAME}",
"echo --- Start use scp upload files ---",
"scp -o StrictHostKeyChecking=no -i ${PRIVATE_KEY_FILE_NAME} -r dist/* ${SERVICE_USER}@${SERVICE_IP}:${SERVICE_PROJECT_PATH}",
"rm -rf ${PRIVATE_KEY_FILE_NAME}",
"echo --- Deploy success ---"
]
}
- 以上命令因为是写在json文件仲,括号和”都需要转义
命令:
"find . \\( -path \"./dist\" -o -path \"./node_modules\" \\) -prune -o -type f \\( -iname \"*.js\" -o -iname \"*.html\" -o -iname \"*.vue\" \\) -print -exec sed -i -f pattern.sed {} \\;"
大概意思是查找当前目录,忽略dist
和node_modules
目录的所有js
、html
和vue
文件 并执行替换操作。
命令:
cat ${PRIVATE_KEY} > ${PRIVATE_KEY_FILE_NAME}
: 把私钥写入凭证文件
命令:scp -o StrictHostKeyChecking=no -i ${PRIVATE_KEY_FILE_NAME} -r dist/* ${SERVICE_USER}@${SERVICE_IP}:${SERVICE_PROJECT_PATH}
:scp
免密传输,关闭严格密钥检查,带上凭证文件,实现不需要用户确认直接登录,从而上传文件
总结
在很多人看来,现阶段都有gitlab-runner
、jenkins
那么成熟的工具,为什么还要去弄一个这样的东西。
在我看来,熟练的工具只是用,明其理才是自己的东西。主要的目的还是把别人的东西变成自己的!
最后附上一张结果图:
