以前斷斷續續在重構一個項目,而後發現功能一開始設計太多了,可能須要花大量時間來增長,可是核心功能基本完成,因而想着能不能半上線狀態,而後經過更新提交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
而後就能夠在本地開發完以後推送,服務器就能自動拉取代碼而且部署。