Authored by 姜枫

change log type

@@ -9,6 +9,7 @@ import sh from 'shelljs'; @@ -9,6 +9,7 @@ import sh from 'shelljs';
9 import moment from 'moment'; 9 import moment from 'moment';
10 import path from 'path'; 10 import path from 'path';
11 import fsp from 'fs-promise'; 11 import fsp from 'fs-promise';
  12 +import fs from 'fs';
12 import config from '../../config/config'; 13 import config from '../../config/config';
13 import Tar from './tar'; 14 import Tar from './tar';
14 import ws from '../../lib/ws'; 15 import ws from '../../lib/ws';
@@ -76,6 +77,8 @@ class Build { @@ -76,6 +77,8 @@ class Build {
76 if (!sh.test('-e', this.rootPath)) { 77 if (!sh.test('-e', this.rootPath)) {
77 sh.mkdir('-p', this.rootPath); 78 sh.mkdir('-p', this.rootPath);
78 } 79 }
  80 + this.logFile = path.join(this.rootPath, 'building.log');
  81 + sh.touch(this.logFile);
79 } 82 }
80 83
81 _cloneCode(branch) { 84 _cloneCode(branch) {
@@ -91,13 +94,17 @@ class Build { @@ -91,13 +94,17 @@ class Build {
91 async: true 94 async: true
92 }); 95 });
93 96
94 - child.stdout.on('data', (data) => {  
95 - self._log(data);  
96 - }); 97 + child.stdout.pipe(fs.createWriteStream(self.logFile, {
  98 + flags: 'a'
  99 + }));
97 100
98 - child.stderr.on('data', (data) => {  
99 - self._log(data);  
100 - }); 101 + child.stderr.pipe(fs.createWriteStream(self.logFile, {
  102 + flags: 'a'
  103 + }));
  104 +
  105 + // child.stderr.on('data', (data) => {
  106 + // self._log(data);
  107 + // });
101 108
102 child.on('close', (code) => { 109 child.on('close', (code) => {
103 if (code == 0) { 110 if (code == 0) {
@@ -121,13 +128,19 @@ class Build { @@ -121,13 +128,19 @@ class Build {
121 async: true 128 async: true
122 }); 129 });
123 130
124 - child.stdout.on('data', (data) => {  
125 - self._log(data);  
126 - }); 131 + // child.stdout.on('data', (data) => {
  132 + // self._log(data);
  133 + // });
127 134
128 - child.stderr.on('data', (data) => {  
129 - self._log(data);  
130 - }); 135 + // child.stderr.on('data', (data) => {
  136 + // self._log(data);
  137 + // });
  138 + child.stdout.pipe(fs.createWriteStream(self.logFile, {
  139 + flags: 'a'
  140 + }));
  141 + child.stderr.pipe(fs.createWriteStream(self.logFile, {
  142 + flags: 'a'
  143 + }));
131 144
132 child.on('close', (code) => { 145 child.on('close', (code) => {
133 if (code == 0) { 146 if (code == 0) {
@@ -157,7 +170,8 @@ class Build { @@ -157,7 +170,8 @@ class Build {
157 } 170 }
158 171
159 _log(line) { 172 _log(line) {
160 - ws.broadcast(`/building/${this.project._id}/log`, line); 173 + // ws.broadcast(`/building/${this.project._id}/log`, line);
  174 + fsp.appendFile(this.logFile, line + '\n');
161 } 175 }
162 } 176 }
163 177
@@ -134,7 +134,7 @@ class Deploy { @@ -134,7 +134,7 @@ class Deploy {
134 self._state('unziped'); 134 self._state('unziped');
135 reslove(); 135 reslove();
136 } else { 136 } else {
137 - reject('unzip fail'); 137 + reject('unzip fail: ' + script);
138 } 138 }
139 }); 139 });
140 } 140 }
@@ -143,7 +143,7 @@ class Deploy { @@ -143,7 +143,7 @@ class Deploy {
143 } 143 }
144 144
145 _startup(conn) { 145 _startup(conn) {
146 - let self =this; 146 + let self = this;
147 let startup = this.project.scripts.start; 147 let startup = this.project.scripts.start;
148 return new Promise((reslove, reject) => { 148 return new Promise((reslove, reject) => {
149 self._state('starting'); 149 self._state('starting');
@@ -172,7 +172,7 @@ class Deploy { @@ -172,7 +172,7 @@ class Deploy {
172 }); 172 });
173 } 173 }
174 174
175 - async _state(state){ 175 + async _state(state) {
176 ws.broadcast(`/deploy/${this.project._id}`, { 176 ws.broadcast(`/deploy/${this.project._id}`, {
177 host: this.info.host, 177 host: this.info.host,
178 state: state 178 state: state
@@ -204,7 +204,7 @@ class Deploy { @@ -204,7 +204,7 @@ class Deploy {
204 } 204 }
205 205
206 get localFile() { 206 get localFile() {
207 - return path.join(config.buildDir, this.building.distFile); 207 + return path.join(config.buildDir, this.building.distFile);
208 } 208 }
209 } 209 }
210 210
@@ -45,7 +45,7 @@ const p = { @@ -45,7 +45,7 @@ const p = {
45 deploy.name = envs[env]; 45 deploy.name = envs[env];
46 let targets = []; 46 let targets = [];
47 47
48 - deploy.target.forEach(async (host) => { 48 + deploy.target.forEach(async(host) => {
49 let info = await DeployInfo.findOne({ 49 let info = await DeployInfo.findOne({
50 projectId: project._id, 50 projectId: project._id,
51 host: host, 51 host: host,
@@ -53,6 +53,7 @@ const p = { @@ -53,6 +53,7 @@ const p = {
53 }); 53 });
54 targets.push({ 54 targets.push({
55 host: host, 55 host: host,
  56 + hostFm: host.replace(/\./g, '-'),
56 info: info 57 info: info
57 }) 58 })
58 }); 59 });
@@ -144,7 +145,10 @@ const p = { @@ -144,7 +145,10 @@ const p = {
144 let p = await Project.findById(pid); 145 let p = await Project.findById(pid);
145 let build = new Build(p); 146 let build = new Build(p);
146 147
147 - let { buildTime, distFile } = build.build(env); 148 + let {
  149 + buildTime,
  150 + distFile
  151 + } = build.build(env);
148 let buildingDoc = await Building.insert({ 152 let buildingDoc = await Building.insert({
149 buildTime: buildTime, 153 buildTime: buildTime,
150 project: p.name, 154 project: p.name,
@@ -177,7 +181,7 @@ const p = { @@ -177,7 +181,7 @@ const p = {
177 let project = await Project.findByName(building.project); 181 let project = await Project.findByName(building.project);
178 let targets = project.deploy[building.env].target; 182 let targets = project.deploy[building.env].target;
179 183
180 - targets.forEach(async (host) => { 184 + targets.forEach(async(host) => {
181 let info = { 185 let info = {
182 projectId: project._id, 186 projectId: project._id,
183 host: host, 187 host: host,
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <div class="panel panel-default" data-env='{{deploy.env}}'> 19 <div class="panel panel-default" data-env='{{deploy.env}}'>
20 <div class="panel-heading"> 20 <div class="panel-heading">
21 <div class="pull-right"> 21 <div class="pull-right">
22 - <a class="btn btn-info btn-rounded mr5 log-btn"><i class="fa fa-eye"></i> 查看实时日志</a> 22 + <a class="btn btn-info btn-rounded mr5 log-btn"><i class="fa fa-eye"></i> 查看构建日志</a>
23 <a class="btn btn-warning btn-rounded mr5 rollback-btn"><i class="fa fa-reply"></i> 回滚</a> 23 <a class="btn btn-warning btn-rounded mr5 rollback-btn"><i class="fa fa-reply"></i> 回滚</a>
24 <a class="btn btn-success btn-rounded mr20 build-btn"><i class="glyphicon glyphicon-plus"></i> 新增构建</a> 24 <a class="btn btn-success btn-rounded mr20 build-btn"><i class="glyphicon glyphicon-plus"></i> 新增构建</a>
25 <a href="" class="tooltips panel-minimize"><i class="fa fa-minus"></i></a> 25 <a href="" class="tooltips panel-minimize"><i class="fa fa-minus"></i></a>
@@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
49 <div class="panel-body"> 49 <div class="panel-body">
50 <div class="row"> 50 <div class="row">
51 {{#each targets}} 51 {{#each targets}}
52 - <div class="col-md-4" id="d-{{host}}"> 52 + <div class="col-md-4" id="d-{{hostFm}}">
53 <div class="panel panel-info noborder"> 53 <div class="panel panel-info noborder">
54 <div class="panel-heading noborder"> 54 <div class="panel-heading noborder">
55 <div class="panel-btns"> 55 <div class="panel-btns">
@@ -65,6 +65,9 @@ @@ -65,6 +65,9 @@
65 <h5 class="md-title mt10">当前状态</h5> 65 <h5 class="md-title mt10">当前状态</h5>
66 <span class="label label-success deploy-log-btn" data-host="{{host}}"><i class="fa fa-spinner fa-spin fa-fw margin-bottom"></i> <b>{{#if info}}{{info.state}}{{^}}未知部署{{/if}}</b></span> 66 <span class="label label-success deploy-log-btn" data-host="{{host}}"><i class="fa fa-spinner fa-spin fa-fw margin-bottom"></i> <b>{{#if info}}{{info.state}}{{^}}未知部署{{/if}}</b></span>
67 </div> 67 </div>
  68 + <div class="col-xs-6">
  69 +
  70 + </div>
68 </div> 71 </div>
69 </div><!-- panel-body --> 72 </div><!-- panel-body -->
70 </div><!-- panel --> 73 </div><!-- panel -->
@@ -120,9 +123,11 @@ @@ -120,9 +123,11 @@
120 return '<button '+(disabled? 'disabled' : '')+' class="btn btn-success btn-xs deploy-btn" data-id="'+data+'" data-build='+row.buildTime+'>分发</button>'; 123 return '<button '+(disabled? 'disabled' : '')+' class="btn btn-success btn-xs deploy-btn" data-id="'+data+'" data-build='+row.buildTime+'>分发</button>';
121 }, 124 },
122 targets: 3 125 targets: 3
123 - }],  
124 - initComplete: function(){  
125 - $('.deploy-btn').click(function(){ 126 + }]
  127 + });
  128 +
  129 + $(this).on( 'draw.dt', function () {
  130 + $('.deploy-btn').click(function(){
126 var id = $(this).data('id'); 131 var id = $(this).data('id');
127 var build = $(this).data('build'); 132 var build = $(this).data('build');
128 layer.confirm('确定发布版本<code>' + build + '</code>吗?', { 133 layer.confirm('确定发布版本<code>' + build + '</code>吗?', {
@@ -131,8 +136,7 @@ @@ -131,8 +136,7 @@
131 doDeploy(id); 136 doDeploy(id);
132 }); 137 });
133 }); 138 });
134 - }  
135 - }); 139 + } );
136 }); 140 });
137 141
138 function doDeploy(build){ 142 function doDeploy(build){
@@ -211,21 +215,22 @@ @@ -211,21 +215,22 @@
211 } 215 }
212 }); 216 });
213 217
214 - ws.on('/building/{{project._id}}/log', function(data){  
215 - if(tag == '') {  
216 - cm.replaceRange("> " + data + "\n", {line: Infinity});  
217 - }  
218 - }); 218 + // ws.on('/building/{{project._id}}/log', function(data){
  219 + // if(tag == '') {
  220 + // cm.replaceRange("> " + data + "\n", {line: Infinity});
  221 + // }
  222 + // });
219 223
220 ws.on('/deploy/{{project._id}}', function(data){ 224 ws.on('/deploy/{{project._id}}', function(data){
221 - $('#d-' + data.host).find('b').text(data.state); 225 + console.log(data);
  226 + $('#d-' + data.host.replace(/\./g, '-')).find('b').text(data.state);
222 }); 227 });
223 228
224 - ws.on('/deploy/{{project._id}}/log', function(data){  
225 - if(tag == data.host){  
226 - cm.replaceRange("> " +data.msg+ "\n", {line: Infinity});  
227 - }  
228 - }); 229 + // ws.on('/deploy/{{project._id}}/log', function(data){
  230 + // if(tag == data.host){
  231 + // cm.replaceRange("> " +data.msg+ "\n", {line: Infinity});
  232 + // }
  233 + // });
229 }); 234 });
230 ws.on('error', function(){ 235 ws.on('error', function(){
231 console.log('connect fail'); 236 console.log('connect fail');
1 'use strict'; 1 'use strict';
2 2
  3 +import _ from 'lodash';
  4 +
3 const helpers = { 5 const helpers = {
4 equals: (a, b, opts) => { 6 equals: (a, b, opts) => {
5 if (a === b) { 7 if (a === b) {
@@ -7,6 +9,9 @@ const helpers = { @@ -7,6 +9,9 @@ const helpers = {
7 } else { 9 } else {
8 return opts.inverse(this); 10 return opts.inverse(this);
9 } 11 }
  12 + },
  13 + replace: (str, pattern, replacement) => {
  14 + return _.replace(str, new RegExp(pattern), replacement);
10 } 15 }
11 }; 16 };
12 17
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 "koa-mount": "^2.0.0", 43 "koa-mount": "^2.0.0",
44 "koa-router": "^7.0.1", 44 "koa-router": "^7.0.1",
45 "koa-static": "^3.0.0", 45 "koa-static": "^3.0.0",
  46 + "lodash": "^4.13.1",
46 "moment": "^2.13.0", 47 "moment": "^2.13.0",
47 "nedb": "^1.8.0", 48 "nedb": "^1.8.0",
48 "nedb-promise": "^2.0.0", 49 "nedb-promise": "^2.0.0",