写了个自动化打包工具,大大滴解放了电脑性能

2,335 阅读2分钟

前段时间手底下的小伙伴跟我吐槽,说后端一点小改动就马上要包,电脑性能很差一旦run build之后就得等好几分钟的空窗期,被迫摸鱼导致加班,我灵机一动,是不是可以利用服务器的性能,编写自动化构建从而实现让后端、测试点点点,就能得到他们想要的不同版本的包、或者不同分支的构建产物呢?

于是乎就有了我的设计并产出的开源:Sa-io https://github.com/LIAOJIANS/sa-io.git

Sa-io操作流程:新建项目(指定gitURL) => 内部执行(npm install)=> run build => SE(推送Sucesss日志) => publish(指定目标地址)=> dowl (下载专属产物)

image.png

项目架构

1、UI层

image.png

2、逻辑层

image.png 3、数据层

image.png

4、所需环境层

image.png

核心实现逻辑

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界面展示

build.gif

history.gif

最后放个项目地址:github.com/LIAOJIANS/s…