以前断断续续在重构一个项目,而后发现功能一开始设计太多了,可能须要花大量时间来增长,可是核心功能基本完成,因而想着能不能半上线状态,而后经过更新提交git,让服务器部署自动更新。这以前接触过git hook
是能够实现的,所以这里记录一篇文章边捣鼓边写。php
首先肯定须要完成的内容,明确需求:html
1.监听指定 git 提交 2.执行指定多个脚本
并且由于我这边是须要分别对client
和server
目录分别执行部署命令。因此须要特别处理。前端
首先去域名管理那边增长一条A记录指向新的项目名称.由于Webhooks
是须要外网域名的,所以先提早加一条。new.xxx.com
node
而后就是须要对服务器上Nginx
作转发配置。nginx
个人nginx
是好久以前配置的git
在etc/nginx/conf/vhost
里增长一个文件,里面写入以下内容:github
server { listen 80; server_name new.xxx.com; index index.html index.htm index.php default.html default.htm default.php; location / { proxy_pass http://127.0.0.1:8801; } access_log off; }
将本地的8801转发出去。web
而后重启一下Nginx nginx -s reload
mongodb
而后git clone 仓库
typescript
由于项目用了mongodb
数据库:
须要建立一个对应的数据库并添加权限。
1. 切换数据库到 abc 2. 指定了数据库 abc ,拥有权限: userAdmin db.createUser( { user: "123", pwd: "123", roles: [ { role: "userAdmin", db: "abc" } ] } ) 3. 验证下上面建立的帐号 123 db.auth('123','123') => 1
这个实际上是最简单的,只要在你的github对应的项目仓库右侧选择settings
而后选择webhooks
选择add webhook
而后按照以下配置便可:
这里须要记住你本身设置的secret
以及你定义的推送动做,我这里是pushCode
。
写以前先来看下最终的目录结构:
├── README.md ├── clean.sh // 清理缓存,而且执行git命令 ├── client │ ├── autoClient.sh // client端自动监听 │ ├── build │ ├── config │ ├── package.json │ ├── public │ ├── scripts │ ├── src │ ├── tsconfig.json │ ├── tsconfig.test.json │ ├── tslint.json │ ├── www │ ├── yarn.lock ├── deploy │ └── index.js // 监听webhook事件而后依次执行 clean.sh autoClient.sh autoServer.sh ├── package.json ├── server │ ├── autoServer.sh // server端自动监听 │ ├── dist │ ├── package.json │ ├── src │ ├── tsconfig.json │ ├── tslint.json │ └── yarn.lock
由于项目缘由,脚本还须要作一些定制。
首先是client
端,由于前端是用了typescript + React全家桶
因此打包起来特别慢,当在服务器build
的时候,由于阿里云内存给的不够,因此会很卡。基于这个考虑,是打算本地bulid
完以后,推送到git上,服务器去git pull
。
并且前端还有个考虑是用什么跑前端代码。由于服务器没装相似服务,所以打算用node框架koa
起一个HTTP服务来跑。
代码以下:
www目录中
app.js const Koa = require('koa') const morgan = require('koa-morgan') const path = require('path'); const static = require('koa-static') const fs = require('fs') const app = new Koa(); // logger app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms')); // static assets app.use(static(path.join(__dirname,'../build'))); //异步读取文件的形式 // app.use(async (ctx,next) =>{ // ctx.type = 'html'; // ctx.body = await fs.createReadStream(path.resolve(__dirname, '..', './build', 'index.html')); // }) module.exports = app;
index.js 'use strict'; const app = require('./app'); const PORT = process.env.PORT || 8801; console.log('client start') app.listen(PORT, () => { console.log(`App listening on port ${PORT}!`); });
这样经过命令node ./www/index.js
可以监听同级build
目录。
固然这比较粗暴,还须要慢慢改进。
咱们须要在client
目录下创建autoClient.sh
#! /bin/bash cd ./ echo 'client build' kill -9 $(lsof -i:8801 |awk '{print $2}' | tail -n 2) node ./www/index.js
用来自动执行监听动做。
由于屡次推送监听的前端端口一致,若是不处理会报错。须要先根据端口号8801
结束进程而后从新开启服务。
而后是server
端,由于整个后端是用koa
完成的,项目比较小,在服务端即时编译花费不了多少时间,所以直接执行yarn start
( "start": "yarn run build && yarn run watch",
)用来编译和监听。
在server
目录里创建autoServer.sh
#! /bin/bash cd ./ echo 'server start' kill -9 $(lsof -i:8866 |awk '{print $2}' | tail -n 2) yarn run start
一样咱们须要在执行监听以前结束上一个端口的进程。
而后咱们来看clean.sh
这个shell脚本是用来清理client
目录下build
文件夹。
#! /bin/bash rm rf ./client/build git reset --hard origin/master git clean -f git pull
能够看到 先清理了缓存而后再向服务器拉取代码.
最后咱们来看部署的脚本deploy/index.js
var spawn = require('child_process').spawn var http = require('http') var spawn = require('child_process').spawn var createHandler = require('github-webhook-handler') var handler = createHandler({ path: '/pushCode', secret: 'xxx' }) // 根据git上webhook的配置填写 http.createServer(function (req, res) { handler(req, res, function (err) { res.statusCode = 404; res.end('no such location') }) }).listen(7777) handler.on('error', function (err) { console.error('Error:', err.message) }) // 监听 push 事件 handler.on('push', function (event) { console.log('Received a push event for %s to %s', event.payload.repository.name, event.payload.ref) init() // 每次拉取都从新监听 } ) function rumCommand( cmd, args, cwd, callback ) { var child = spawn( cmd, args, {cwd: cwd} ) var response = '' child.stdout.on('data', function( buffer ){ response += buffer.toString(); }) child.stdout.on('end', function(){ callback( response ) }) } function init() { rumCommand('sh', ['../clean.sh'], './' ,function( result ) { // 清理缓存 console.log(result) }) rumCommand('sh', ['../server/autoServer.sh'], '../server' ,function( result ) { // cLient端更新 console.log(result) }) rumCommand('sh', ['../client/autoClient.sh'], '../client' ,function( result ) { // server端更新 console.log(result) }) } init() // 脚本运行第一次默认指向一次
这里须要声明的是由于多目录下执行脚本须要对应的环境。所以才把脚本都分开放。
部署咱们只须要对pm2 start deploy/index.js
而后就能够在本地开发完以后推送,服务器就能自动拉取代码而且部署。