Skip to content

Commit 83ec6c3

Browse files
author
Aaron Chambers
committed
Merge pull request #1 from strange-studios/upload-to-s3
Upload to s3
2 parents ed9b78b + cbdbfa7 commit 83ec6c3

File tree

10 files changed

+605
-6
lines changed

10 files changed

+605
-6
lines changed

index.js

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,85 @@
11
/* jshint node: true */
22
'use strict';
33

4+
var Promise = require('ember-cli/lib/ext/promise');
5+
var minimatch = require('minimatch');
6+
var path = require('path');
7+
8+
var chalk = require('chalk');
9+
var blue = chalk.blue;
10+
var red = chalk.red;
11+
12+
var validateConfig = require('./lib/utilities/validate-config');
13+
var S3 = require('./lib/s3');
14+
415
module.exports = {
5-
name: 'ember-cli-deploy-s3'
16+
name: 'ember-cli-deploy-s3',
17+
18+
createDeployPlugin: function(options) {
19+
function _beginMessage(ui, filesToUpload, bucket) {
20+
ui.write(blue('| '));
21+
ui.writeLine(blue('- uploading ' + filesToUpload.length + ' files to `' + bucket + '`'));
22+
23+
return Promise.resolve();
24+
}
25+
26+
function _successMessage(ui, filesToUpload) {
27+
ui.write(blue('| '));
28+
ui.writeLine(blue('- uploaded ' + filesToUpload.length + ' files ok'));
29+
30+
return Promise.resolve();
31+
}
32+
33+
function _errorMessage(ui, error) {
34+
ui.write(blue('| '));
35+
ui.writeLine(red('- ' + error));
36+
37+
return Promise.reject(error);
38+
}
39+
40+
return {
41+
name: options.name,
42+
43+
willDeploy: function(context) {
44+
var deployment = context.deployment;
45+
var ui = deployment.ui;
46+
var config = deployment.config[this.name] = deployment.config[this.name] || {};
47+
48+
return validateConfig(ui, config)
49+
.then(function() {
50+
ui.write(blue('| '));
51+
ui.writeLine(blue('- config ok'));
52+
});
53+
},
54+
55+
upload: function(context) {
56+
var deployment = context.deployment;
57+
var ui = deployment.ui;
58+
var config = deployment.config[this.name];
59+
60+
var filePattern = config.filePattern;
61+
var distDir = context.distDir;
62+
var distFiles = context.distFiles || [];
63+
var filesToUpload = distFiles.filter(minimatch.filter(filePattern, { matchBase: true }));
64+
65+
var s3 = context.s3Client || new S3({
66+
ui: ui,
67+
config: config,
68+
client: context.client
69+
});
70+
71+
var options = {
72+
cwd: context.distDir,
73+
filePaths: filesToUpload,
74+
prefix: config.prefix,
75+
bucket: config.bucket
76+
};
77+
78+
return _beginMessage(ui, filesToUpload, config.bucket)
79+
.then(s3.upload.bind(s3, options))
80+
.then(_successMessage.bind(this, ui, filesToUpload))
81+
.catch(_errorMessage.bind(this, ui));
82+
}
83+
};
84+
}
685
};

lib/s3.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
var CoreObject = require('core-object');
2+
var fs = require('fs');
3+
var path = require('path');
4+
var mime = require('mime');
5+
6+
var Promise = require('ember-cli/lib/ext/promise');
7+
var denodeify = Promise.denodeify;
8+
var readFile = denodeify(fs.readFile);
9+
10+
var chalk = require('chalk');
11+
var blue = chalk.blue;
12+
13+
var EXPIRE_IN_2030 = new Date('2030');
14+
var TWO_YEAR_CACHE_PERIOD_IN_SEC = 60 * 60 * 24 * 365 * 2;
15+
16+
module.exports = CoreObject.extend({
17+
init: function(options) {
18+
var config = options.config;
19+
20+
var AWS = require('aws-sdk');
21+
this._client = options.client || new AWS.S3({
22+
accessKeyId: config.accessKeyId,
23+
secretAccessKey: config.secretAccessKey,
24+
region: config.region
25+
});
26+
27+
this._ui = options.ui;
28+
},
29+
30+
upload: function(options) {
31+
options = options || {};
32+
33+
var ui = this._ui;
34+
var cwd = options.cwd;
35+
var bucket = options.bucket;
36+
var prefix = options.prefix;
37+
var acl = options.acl || 'public-read';
38+
var filePaths = options.filePaths || [];
39+
var cacheControl = 'max-age='+TWO_YEAR_CACHE_PERIOD_IN_SEC+', public';
40+
var expires = EXPIRE_IN_2030;
41+
42+
if (typeof filePaths === 'string') {
43+
filePaths = [filePaths];
44+
}
45+
46+
var promises = filePaths.map(function(filePath) {
47+
var basePath = path.join(cwd, filePath);
48+
var data = fs.readFileSync(basePath);
49+
var contentType = mime.lookup(basePath);
50+
var key = path.join(prefix, filePath);
51+
52+
var params = {
53+
Bucket: bucket,
54+
ACL: acl,
55+
Body: data,
56+
ContentType: contentType,
57+
Key: key,
58+
CacheControl: cacheControl,
59+
Expires: expires
60+
};
61+
62+
return new Promise(function(resolve, reject) {
63+
this._client.putObject(params, function(error, data) {
64+
if (error) {
65+
reject(error);
66+
} else {
67+
ui.write(blue('| '));
68+
ui.writeLine(blue('- uploaded: ' + filePath));
69+
70+
resolve();
71+
}
72+
});
73+
}.bind(this));
74+
}.bind(this));
75+
76+
return Promise.all(promises);
77+
}
78+
});

lib/utilities/validate-config.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
var Promise = require('ember-cli/lib/ext/promise');
2+
3+
var chalk = require('chalk');
4+
var yellow = chalk.yellow;
5+
var blue = chalk.blue;
6+
var red = chalk.red;
7+
8+
module.exports = function(ui, config) {
9+
ui.write(blue('| '));
10+
ui.write(blue('- validating config\n'));
11+
12+
var defaultConfig = {
13+
region: 'us-east-1',
14+
filePattern: '**/*.{js,css,png,gif,jpg,map,xml,txt}',
15+
prefix: ''
16+
};
17+
18+
['region', 'filePattern', 'prefix'].forEach(function(prop) {
19+
if (!config[prop]) {
20+
var value = defaultConfig[prop];
21+
config[prop] = value;
22+
ui.write(blue('| '));
23+
ui.writeLine(yellow('- Missing config: ' + prop + ', using default: `' + value + '`'));
24+
}
25+
});
26+
27+
var promise = Promise.resolve();
28+
29+
['accessKeyId', 'secretAccessKey', 'bucket'].forEach(function(prop) {
30+
if (!config[prop]) {
31+
ui.write(blue('| '));
32+
ui.writeLine(red('- Missing config: `' + prop + '`'));
33+
34+
promise = Promise.reject();
35+
}
36+
});
37+
38+
return promise;
39+
}

package.json

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"scripts": {
1010
"start": "ember server",
1111
"build": "ember build",
12-
"test": "ember try:testall"
12+
"test": "node tests/runner.js"
1313
},
1414
"repository": "https://github.com/zapnito/ember-cli-deploy-s3",
1515
"engines": {
@@ -19,6 +19,8 @@
1919
"license": "MIT",
2020
"devDependencies": {
2121
"broccoli-asset-rev": "^2.0.2",
22+
"chai": "^2.2.0",
23+
"chai-as-promised": "^5.0.0",
2224
"ember-cli": "0.2.3",
2325
"ember-cli-app-version": "0.3.3",
2426
"ember-cli-content-security-policy": "0.4.0",
@@ -29,15 +31,23 @@
2931
"ember-cli-qunit": "0.3.10",
3032
"ember-cli-uglify": "1.0.1",
3133
"ember-data": "1.0.0-beta.16.1",
32-
"ember-export-application-global": "^1.0.2",
3334
"ember-disable-prototype-extensions": "^1.0.0",
34-
"ember-try": "0.0.4"
35+
"ember-export-application-global": "^1.0.2",
36+
"ember-try": "0.0.4",
37+
"glob": "^5.0.5",
38+
"mocha": "^2.2.4"
3539
},
3640
"keywords": [
37-
"ember-addon"
41+
"ember-addon",
42+
"ember-cli-deploy-plugin"
3843
],
3944
"dependencies": {
40-
"ember-cli-babel": "^5.0.0"
45+
"aws-sdk": "^2.1.25",
46+
"chalk": "^1.0.0",
47+
"core-object": "^1.1.0",
48+
"ember-cli-babel": "^5.0.0",
49+
"mime": "^1.3.4",
50+
"minimatch": "^2.0.4"
4151
},
4252
"ember-addon": {
4353
"configPath": "tests/dummy/config"

tests/fixtures/dist/app.css

Whitespace-only changes.

tests/fixtures/dist/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
some content here

tests/runner.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
var glob = require('glob');
4+
var Mocha = require('mocha');
5+
6+
var mocha = new Mocha({
7+
reporter: 'spec'
8+
});
9+
10+
var arg = process.argv[2];
11+
var root = 'tests/';
12+
13+
function addFiles(mocha, files) {
14+
glob.sync(root + files).forEach(mocha.addFile.bind(mocha));
15+
}
16+
17+
addFiles(mocha, '/**/*-nodetest.js');
18+
19+
if (arg === 'all') {
20+
addFiles(mocha, '/**/*-nodetest-slow.js');
21+
}
22+
23+
mocha.run(function(failures) {
24+
process.on('exit', function() {
25+
process.exit(failures);
26+
});
27+
});

0 commit comments

Comments
 (0)