Skip to content

Commit d04896d

Browse files
committed
Add support for a text manifest for differential deploys.
Add support for a text manifest that can be consulted to avoid re-uploading files that were part of the last upload. Text manifest can be generated with ember-cli-deploy-manifest.
1 parent cde10ca commit d04896d

File tree

6 files changed

+133
-26
lines changed

6 files changed

+133
-26
lines changed

index.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ module.exports = {
1717
createDeployPlugin: function(options) {
1818
function _beginMessage(ui, filesToUpload, bucket) {
1919
ui.write(blue('| '));
20-
ui.writeLine(blue('- uploading ' + filesToUpload.length + ' files to `' + bucket + '`'));
20+
ui.writeLine(blue('- preparing to upload to S3 bucket `' + bucket + '`'));
2121

2222
return Promise.resolve();
2323
}
2424

25-
function _successMessage(ui, filesToUpload) {
25+
function _successMessage(ui, filesUploaded) {
2626
ui.write(blue('| '));
27-
ui.writeLine(blue('- uploaded ' + filesToUpload.length + ' files ok'));
27+
ui.writeLine(blue('- uploaded ' + filesUploaded.length + ' files ok'));
2828

2929
return Promise.resolve();
3030
}
@@ -73,12 +73,13 @@ module.exports = {
7373
filePaths: filesToUpload,
7474
gzippedFilePaths: gzippedFiles,
7575
prefix: config.prefix,
76-
bucket: config.bucket
76+
bucket: config.bucket,
77+
manifestPath: context.manifestPath
7778
};
7879

7980
return _beginMessage(ui, filesToUpload, config.bucket)
8081
.then(s3.upload.bind(s3, options))
81-
.then(_successMessage.bind(this, ui, filesToUpload))
82+
.then(_successMessage.bind(this, ui))
8283
.catch(_errorMessage.bind(this, ui));
8384
}
8485
};

lib/s3.js

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1+
/* global require */
12
var CoreObject = require('core-object');
23
var fs = require('fs');
34
var path = require('path');
45
var mime = require('mime');
56

67
var Promise = require('ember-cli/lib/ext/promise');
7-
var denodeify = Promise.denodeify;
8-
var readFile = denodeify(fs.readFile);
98

9+
var _ = require('lodash');
1010
var chalk = require('chalk');
1111
var blue = chalk.blue;
12-
1312
var EXPIRE_IN_2030 = new Date('2030');
1413
var TWO_YEAR_CACHE_PERIOD_IN_SEC = 60 * 60 * 24 * 365 * 2;
1514

@@ -29,22 +28,64 @@ module.exports = CoreObject.extend({
2928

3029
upload: function(options) {
3130
options = options || {};
31+
return this._determineFilePaths(options).then(function(filePaths){
32+
return Promise.all(this._putObjects(filePaths, options));
33+
}.bind(this));
34+
},
3235

36+
_determineFilePaths: function(options) {
37+
var ui = this._ui;
38+
var filePaths = options.filePaths || [];
39+
if (typeof filePaths === 'string') {
40+
filePaths = [filePaths];
41+
}
42+
var prefix = options.prefix;
43+
var manifestPath = options.manifestPath;
44+
if (manifestPath) {
45+
var key = path.join(prefix, manifestPath);
46+
ui.write(blue('| '));
47+
ui.writeLine(blue("- Downloading manifest for differential deploy from `" + key + "`..."));
48+
return new Promise(function(resolve, reject){
49+
var params = { Bucket: options.bucket, Key: key};
50+
this._client.getObject(params, function(error, data) {
51+
if (error) {
52+
reject(error);
53+
} else {
54+
resolve(data.Body.toString().split('\n'));
55+
}
56+
}.bind(this));
57+
}.bind(this)).then(function(manifestEntries){
58+
ui.write(blue('| '));
59+
ui.writeLine(blue("- Manifest found. Differential deploy will be applied."));
60+
return _.difference(filePaths, manifestEntries);
61+
}).catch(function(reason){
62+
console.log(reason);
63+
ui.write(blue('| '));
64+
ui.writeLine(blue("- Manifest not found. Disabling differential deploy."));
65+
return Promise.resolve(filePaths);
66+
});
67+
} else {
68+
return Promise.resolve(filePaths);
69+
}
70+
},
71+
72+
_putObjects: function(filePaths, options) {
3373
var ui = this._ui;
3474
var cwd = options.cwd;
3575
var bucket = options.bucket;
3676
var prefix = options.prefix;
3777
var acl = options.acl || 'public-read';
38-
var filePaths = options.filePaths || [];
3978
var gzippedFilePaths = options.gzippedFilePaths || [];
4079
var cacheControl = 'max-age='+TWO_YEAR_CACHE_PERIOD_IN_SEC+', public';
4180
var expires = EXPIRE_IN_2030;
4281

43-
if (typeof filePaths === 'string') {
44-
filePaths = [filePaths];
82+
var manifestPath = options.manifestPath;
83+
var pathsToUpload = filePaths;
84+
if (manifestPath) {
85+
pathsToUpload.push(manifestPath);
4586
}
4687

47-
var promises = filePaths.map(function(filePath) {
88+
return pathsToUpload.map(function(filePath) {
4889
var basePath = path.join(cwd, filePath);
4990
var data = fs.readFileSync(basePath);
5091
var contentType = mime.lookup(basePath);
@@ -71,13 +112,10 @@ module.exports = CoreObject.extend({
71112
} else {
72113
ui.write(blue('| '));
73114
ui.writeLine(blue('- ✔ ' + key));
74-
75-
resolve();
115+
resolve(filePath);
76116
}
77117
});
78118
}.bind(this));
79119
}.bind(this));
80-
81-
return Promise.all(promises);
82120
}
83121
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"chalk": "^1.0.0",
4747
"core-object": "^1.1.0",
4848
"ember-cli-babel": "^5.0.0",
49+
"lodash": "^3.9.3",
4950
"mime": "^1.3.4",
5051
"minimatch": "^2.0.4"
5152
},

tests/fixtures/dist/manifest.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
app.css
2+
app.js

tests/unit/index-nodetest.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,7 @@ describe('s3 plugin', function() {
9292
return assert.isFulfilled(plugin.upload.call(plugin, context))
9393
.then(function() {
9494
assert.equal(mockUi.messages.length, 4);
95-
96-
var messages = mockUi.messages.reduce(function(previous, current) {
97-
if (/- uploading 2 files to `cccc`/.test(current)) {
98-
previous.push(current);
99-
}
100-
101-
return previous;
102-
}, []);
103-
104-
assert.equal(messages.length, 1);
95+
assert.match(mockUi.messages[0], /preparing to upload to S3 bucket `cccc`/);
10596
});
10697
});
10798

tests/unit/lib/s3-nodetest.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,79 @@ describe('s3', function() {
111111
});
112112
});
113113
});
114+
115+
describe('with a manifestPath specified', function () {
116+
it('uploads all files when manifest is missing from server', function (done) {
117+
var subject = new S3({
118+
ui: mockUi,
119+
client: {
120+
putObject: function(params, cb) {
121+
cb();
122+
},
123+
getObject: function(params, cb){
124+
cb(new Error("File not found"));
125+
}
126+
}
127+
});
128+
var options = {
129+
filePaths: ['app.js', 'app.css'],
130+
cwd: process.cwd() + '/tests/fixtures/dist',
131+
prefix: 'js-app',
132+
manifestPath: 'manifest.txt'
133+
};
134+
135+
var promise = subject.upload(options);
136+
137+
return assert.isFulfilled(promise)
138+
.then(function() {
139+
assert.equal(mockUi.messages.length, 5);
140+
assert.match(mockUi.messages[0], /- Downloading manifest for differential deploy.../);
141+
assert.match(mockUi.messages[1], /- Manifest not found. Disabling differential deploy\./);
142+
assert.match(mockUi.messages[2], /- js-app\/app\.js/);
143+
assert.match(mockUi.messages[3], /- js-app\/app\.css/);
144+
assert.match(mockUi.messages[4], /- js-app\/manifest\.txt/);
145+
done();
146+
}).catch(function(reason){
147+
done(reason);
148+
});
149+
});
150+
151+
it('only uploads missing files when manifest is present on server', function (done) {
152+
var subject = new S3({
153+
ui: mockUi,
154+
client: {
155+
putObject: function(params, cb) {
156+
cb();
157+
},
158+
getObject: function(params, cb){
159+
cb(undefined, {
160+
Body: "app.js"
161+
});
162+
}
163+
}
164+
});
165+
166+
var options = {
167+
filePaths: ['app.js', 'app.css'],
168+
cwd: process.cwd() + '/tests/fixtures/dist',
169+
prefix: 'js-app',
170+
manifestPath: 'manifest.txt'
171+
};
172+
173+
var promise = subject.upload(options);
174+
175+
return assert.isFulfilled(promise)
176+
.then(function() {
177+
assert.equal(mockUi.messages.length, 4);
178+
assert.match(mockUi.messages[0], /- Downloading manifest for differential deploy.../);
179+
assert.match(mockUi.messages[1], /- Manifest found. Differential deploy will be applied\./);
180+
assert.match(mockUi.messages[2], /- js-app\/app\.css/);
181+
assert.match(mockUi.messages[3], /- js-app\/manifest\.txt/);
182+
done();
183+
}).catch(function(reason){
184+
done(reason);
185+
});
186+
});
187+
});
114188
});
115189
});

0 commit comments

Comments
 (0)