-
Notifications
You must be signed in to change notification settings - Fork 17
/
s3push.js
202 lines (161 loc) · 5.86 KB
/
s3push.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
var _ = require('lodash'),
async = require('async'),
fs = require("fs"),
path = require("path"),
colors = require('colors'),
jsdiff = require('diff'),
utils;
module.exports = {
name:'s3push',
description:'Builds all of the front end assets for each microservice and pushes them to S3 for the current environment',
example:'bosco -e <environment> -b <build> s3push <tag>',
cmd:cmd
}
var tag = "", noprompt = false;
function cmd(bosco, args) {
if(args.length > 0) tag = args[0];
cdnUrl = bosco.config.get('aws:cdn') + "/";
force = bosco.options.force;
noprompt = bosco.options.noprompt;
bosco.log("Compile front end assets across services " + (tag ? "for tag: " + tag.blue : ""));
var repos = bosco.config.get('github:repos');
if(!repos) return bosco.error("You are repo-less :( You need to initialise bosco first, try 'bosco fly'.");
var pushAllToS3 = function(staticAssets, confirmation, next) {
var toPush = [];
_.forOwn(staticAssets, function(asset, key) {
if(tag && tag !== asset.tag) return;
if(!asset.content) return;
// Check confirmation by type and key
if(asset.type == 'js' && !confirmation[asset.tag][asset.type]) return;
if(asset.type == 'css' && !confirmation[asset.tag][asset.type]) return;
if(asset.type == 'html' && !confirmation[asset.tag][asset.assetType]) return;
if(asset.type == 'plain' && !confirmation[asset.tag][asset.assetType]) return;
toPush.push({content:asset.content, path:key, type:asset.type});
});
saveS3record(toPush);
// Add index
toPush.push({content:staticAssets.formattedAssets, path:(bosco.options.environment + "/" + bosco.options.build + "/index.html"), type:'html'});
async.mapSeries(toPush, pushToS3, next);
}
var saveS3record = function(toPush) {
// Get the environment + build tag to save in your config file
if(toPush.length > 0) {
var envBuild = toPush[0].path.split("/")[1];
var myRepos = bosco.config.get('S3:published') || [];
if(!_.contains(myRepos,envBuild)) {
myRepos.push(envBuild);
var envConfig = bosco.config.stores.environment;
envConfig.store.S3 = {published: myRepos};
bosco.config.save();
};
}
}
var pushToS3 = function(file, next) {
if(!bosco.knox) return bosco.warn("Knox AWS not configured for environment " + bosco.options.envrionment + " - so not pushing " + file.path + " to S3.");
var buffer = new Buffer(file.content);
var headers = {
'Content-Type': file.type == 'js' ? 'application/javascript': 'text/' + file.type,
'Cache-Control': 'max-age=300'
};
bosco.knox.putBuffer(buffer, file.path, headers, function(err, res){
if(res.statusCode != 200 && !err) err = {message:'S3 error, code ' + res.statusCode};
bosco.log('Pushed to S3: ' + cdnUrl + file.path);
next(err, {file: file});
});
}
var confirm = function(message, next) {
bosco.prompt.start();
bosco.prompt.get({
properties: {
confirm: {
description: message
}
}
}, function (err, result) {
if(!result) return next({message:'Did not confirm'});
if(result.confirm == 'Y' || result.confirm == 'y') {
next(null, true);
} else {
next(null, false);
}
});
}
var checkManifests = function(staticAssets, next) {
if(!bosco.knox) return next({message: "You don't appear to have any S3 config for this environment?"});
var manifestFiles = [];
_.forOwn(staticAssets, function(value, key) {
if(value.extname == '.manifest') {
value.file = key;
manifestFiles.push(value);
}
});
async.mapSeries(manifestFiles, function(file, cb) {
bosco.log("Pulling previous version of " + file.file.blue + " from S3");
bosco.knox.getFile(file.file, function(err, res){
var currFile = "", isError;
if(!err && res.statusCode == 404) return cb(null, true);
if(err || res.statusCode !== 200) {
bosco.error("There was an error talking to S3 to retrieve the file:")
isError = true;
}
res.on('data', function(chunk) { currFile += chunk; });
res.on('end', function() {
if(isError) {
bosco.error(currFile);
return cb(null, false);
}
if(currFile == file.content) {
bosco.log("No changes".green + " found in " + file.file.blue + "." + (force ? " Forcing push anyway." : ""));
return cb(null, force);
}
bosco.log("Changes found in " + file.file.blue + ", diff:");
showDiff(currFile, file.content, cb);
});
});
}, function(err, result) {
var results = {};
result.forEach(function(confirm, index) {
var mkey = manifestFiles[index].tag, atype = manifestFiles[index].assetType;
results[mkey] = results[mkey] || {};
results[mkey][atype] = confirm;
});
next(err, results);
});
}
var showDiff = function(original, changed, next) {
var diff = jsdiff.diffLines(original, changed);
diff.forEach(function(part){
var color = part.added ? 'green' :
part.removed ? 'red' : 'grey';
bosco.log(part.value[color]);
});
confirm("Are you certain you want to push based on the changes above?".white, next);
}
var go = function() {
bosco.log("Compiling front end assets, this can take a while ... ");
var options = {
repos: repos,
minify: true,
tagFilter: tag,
watchBuilds: false,
reloadOnly: false
}
bosco.staticUtils.getStaticAssets(options, function(err, staticAssets) {
checkManifests(staticAssets, function(err, confirmation) {
if(err) return bosco.error(err.message);
pushAllToS3(staticAssets, confirmation, function(err) {
if(err) return bosco.error("There was an error: " + err.message);
bosco.log("Done");
});
})
});
}
if(!noprompt) {
var confirmMsg = "Are you sure you want to publish ".white + (tag ? "all " + tag.blue + " assets in " : "ALL".red + " assets in ").white + bosco.options.environment.blue + " (y/N)?".white
confirm(confirmMsg, function(err, confirmed) {
if(!err && confirmed) go();
})
} else {
go();
}
}