写了个自动化打包工具,大大滴解放了电脑性能
前段时间手底下的小伙伴跟我吐槽,说后端一点小改动就马上要包,电脑性能很差一旦run build
之后就得等好几分钟的空窗期,被迫摸鱼导致加班,我灵机一动,是不是可以利用服务器的性能,编写自动化构建从而实现让后端、测试点点点,就能得到他们想要的不同版本的包、或者不同分支的构建产物呢?
于是乎就有了我的设计并产出的开源:Sa-io https://github.com/LIAOJIANS/sa-io.git
Sa-io操作流程:新建项目(指定gitURL) => 内部执行(npm install)=> run build => SE(推送Sucesss日志) => publish(指定目标地址)=> dowl (下载专属产物)
项目架构
1、UI层
2、逻辑层
3、数据层
4、所需环境层
核心实现逻辑
1、技术清单
child_process
:创建子进程并执行构建脚本;chokidar
: 监听日志文件内容;scp2
:建立SSH连接并传输文件;Vue3
:UI界面采用VUE3 + TS
2、核心逻辑
Run Build
router.post('/build', [
(() =>
['shell', 'install', 'projectName'].map((fild) =>
body(fild)
.notEmpty()
.withMessage('username or token is null'),
))(),
], (req, res, next) => {
checkBeforRes(next, req, async () => {
const {
shell,
install,
removeNm,
shellContent,
branch,
projectName,
pull,
...onter
} = req.body
if (os.platform() !== 'linux' && shell) {
return new Result(null, 'Running shell scripts must be in a Linux environment!!!')
.fail(res)
}
const curTime = Date.now()
const id = `${projectName}-${curTime}`
const fileName = `${id}.log`
const logPath = path.resolve(__dirname, `../log/${fileName}`)
let status = 'success'
const getHistory = () => getFileContentByName('history', [])
// 生成构建历史
let data = [
...getHistory(),
{
id,
projectName,
buildTime: curTime,
status: '',
branch
}
]
// 生成日志文件
getFileContentByName(
'',
'',
logPath
)
// 写入history基本信息
setFileContentByName(
'history',
data,
true
)
if (removeNm) {
await rmDir(projectName, 'node_modules') // 删除node_modules 防止不同分支不同版本的依赖冲突
rmFile(`${projectName}/package-lock.json`) // 删除安装依赖日志,防止版本缓存
}
if (branch) { // 如果有分支,并且分支不能等于当前分支,否则切换分支并拉取最新
const projects = getFileContentByName('projects')
const project = projects.find(p => p.projectName === projectName)
if (project.branch !== branch) {
try {
if (install) {
rmFile(`${projectName}/package-lock.json`) // 删除安装依赖日志,防止版本缓存
}
await gitCheckoutPro(projectName, branch)
setFileContentByName('projects', [
...projects.map(p => {
if (p.projectName === projectName) {
p.branch = branch
}
return p
})
], true)
} catch (e) {
console.log(e)
setFileContentByName(
'history',
[
...data,
{
projectName,
buildTime: curTime,
status: 'error',
branch
}
],
true
)
res.status(500).send('checkout error!!! Please review the log output!!!!!!')
}
} else if (pull) { // 拉取最新
try {
await gitPullPro(projectName, logPath)
} catch (e) {
res.status(500).send('checkout error!!! Please review the log output!!!!!!')
}
}
}
new Result(`${id}`, 'building, Please review the log output!!!!!!').success(res)
const compressedPro = () => {
status = 'success'
compressed(`${projectName}-${curTime}`, projectName)
console.log('success')
copyFile(
path.resolve(__dirname, `../project/${projectName}/dist`),
path.resolve(__dirname, `../builds/${projectName}-${curTime}`)
)
const {
publish,
...left
} = onter
if (publish) {
publishTragetServer({
...left,
localPath: path.resolve(__dirname, `../builds/${projectName}-${curTime}`)
})
}
}
if (shell) { // 执行sh脚本
setFileContentByName(
projectName,
shellContent,
true,
path.resolve(__dirname, `../project/${projectName}/build.sh`)
)
await shellPro(projectName, logPath)
.then(compressedPro)
.catch(() => {
status = 'error'
console.log('error')
})
} else { // 执行打包工作流
(
await (install ? installAfterBuildPro : buildPro)(projectName, logPath)
.then(compressedPro)
.catch(() => {
status = 'error'
console.log('error')
})
)
}
let newData = getHistory()
newData = newData.map(c => {
if (c.id === id) {
c.status = status
}
return c
})
setFileContentByName(
'history',
newData,
true
)
})
})
UI界面展示
最后放个项目地址:github.com/LIAOJIANS/s…
作者:大码猴
来源:juejin.cn/post/7445098587808514082
来源:juejin.cn/post/7445098587808514082