Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ The region your bucket is located in. (e.g. set this to `eu-west-1` if your buck

*Default:* `undefined`

### awsPrefix

A optional prefix to add to the uploaded destination of your built fastboot assets. Useful if your app is hosted at a nested path on S3. For example if you set `awsPrefix` to `'blog'`, `fastboot-deploy-info.json` will look something like this:
```json
{
"bucket": "my-bucket",
"key": "blog/dist-0.0.0+a3323e2.zip"
}
```
**Note** that a trailing slash is added to the value to separate it from the `archivePrefix` value.

*Default:* `''`

### revisionKey

The unique revision number for the version of the app. By default this option will use either the `revision` passed in from the command line or the `revisionData.revisionKey` property from the deployment context.
Expand Down
50 changes: 42 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function _list(opts) {
return new Date(b.LastModified) - new Date(a.LastModified);
})
.map((d) => {
let match = d.Key.match(new RegExp(archivePrefix+'([^.]*)\\.zip'));
let match = d.Key.match(new RegExp(archivePrefix+'(.*)\\.zip'));
if (!match) {
return; // ignore files that are no zipped app builds
}
Expand Down Expand Up @@ -91,7 +91,8 @@ module.exports = {
return context.fastbootDownloaderManifestContent;
},

manifestKey: 'fastboot-deploy-info.json'
manifestKey: 'fastboot-deploy-info.json',
awsPrefix: ''
},

requiredConfig: ['bucket', 'region'],
Expand All @@ -100,24 +101,35 @@ module.exports = {
let revisionKey = this.readConfig('revisionKey');
let bucket = this.readConfig('bucket');
let archivePrefix = this.readConfig('archivePrefix');
let awsPrefix = this.readConfig('awsPrefix');
// update manifest-file to point to passed revision
let downloaderManifestContent = this.readConfig('downloaderManifestContent');

let manifest = downloaderManifestContent(bucket, `${archivePrefix}${revisionKey}.zip`);
let buildKey = `${archivePrefix}${revisionKey}.zip`;
if (awsPrefix) {
buildKey = `${awsPrefix}/${buildKey}`;
}

this.log(`creating manifest for bucket: ${bucket} and buildKey: ${buildKey}`, {verbose: true});
let manifest = downloaderManifestContent(bucket, buildKey);
let AWS = require('aws-sdk');
let RSVP = require('rsvp');
let accessKeyId = this.readConfig('accessKeyId');
let secretAccessKey = this.readConfig('secretAccessKey');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');

manifestKey = awsPrefix ? `${awsPrefix}/${manifestKey}` : manifestKey;

let client = new AWS.S3({
accessKeyId,
secretAccessKey,
region
});
let putObject = RSVP.denodeify(client.putObject.bind(client));

this.log(`updating manifest at ${manifestKey}`, {verbose: true});

return putObject({
Bucket: bucket,
Key: manifestKey,
Expand All @@ -135,6 +147,7 @@ module.exports = {
let secretAccessKey = this.readConfig('secretAccessKey');
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');
let awsPrefix = this.readConfig('awsPrefix');

let client = new AWS.S3({
accessKeyId,
Expand All @@ -146,10 +159,13 @@ module.exports = {

let data = fs.readFileSync(context.fastbootArchivePath);

let key = awsPrefix ? `${awsPrefix}/${context.fastbootArchiveName}` : context.fastbootArchiveName;

this.log(`uploading fastboot archive to ${bucket}/${key}`, {verbose: true});
return putObject({
Bucket: bucket,
Body: data,
Key: context.fastbootArchiveName
Key: key
});
},

Expand All @@ -160,12 +176,22 @@ module.exports = {
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');
let awsPrefix = this.readConfig('awsPrefix');

archivePrefix = awsPrefix ? `${awsPrefix}/${archivePrefix}` : archivePrefix;
manifestKey = awsPrefix ? `${awsPrefix}/${manifestKey}` : manifestKey;

let opts = {
accessKeyId, secretAccessKey, archivePrefix, bucket, region, manifestKey
};

return _list(opts);
return _list(opts)
.then(({ revisions }) => {
revisions.forEach(r => {
this.log(`${r.revision} | ${r.timestamp} | active: ${r.active}`, {verbose: true});
});
return { revisions };
});
},

fetchInitialRevisions: function() {
Expand All @@ -175,14 +201,22 @@ module.exports = {
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');
let awsPrefix = this.readConfig('awsPrefix');

archivePrefix = awsPrefix ? `${awsPrefix}/${archivePrefix}` : archivePrefix;
manifestKey = awsPrefix ? `${awsPrefix}/${manifestKey}` : manifestKey;

let opts = {
accessKeyId, secretAccessKey, archivePrefix, bucket, region, manifestKey
};

return _list(opts)
.then((data) => {
return { initialRevisions: data.revisions };
return _list(opts, this)
.then(({ revisions }) => {
revisions.forEach(r => {
this.log(`${r.revision} | ${r.timestamp} | active: ${r.active}`, {verbose: true});
});

return { initialRevisions: revisions };
});
}
});
Expand Down
89 changes: 86 additions & 3 deletions tests/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,21 @@ function cleanBucket() {
});
}

function setupTestData() {
function setupTestData(ops = {}) {
function addTestData() {
let existingDists = ['dist-12.zip', 'dist-34.zip', 'dist-56.zip'];
let promises = existingDists.map((n) => {
if (ops.awsPrefix) {
n = `${ops.awsPrefix}/${n}`;
}
return put({ Bucket: process.env.TEST_BUCKET, Key: n, Body: 'Body: ' + n });
});
promises.push(put({
Bucket: process.env.TEST_BUCKET,
Key: 'fastboot-deploy-info.json',
Key: (ops.awsPrefix ? `${ops.awsPrefix}/` : '') + 'fastboot-deploy-info.json',
Body: JSON.stringify({
bucket: process.env.TEST_BUCKET,
key: 'dist-34.zip'
key: (ops.awsPrefix ? `${ops.awsPrefix}/` : '') + 'dist-34.zip'
})
}));

Expand Down Expand Up @@ -154,6 +157,31 @@ describe('fastboot-app-server-aws plugin', function() {
assert.isTrue(false, 'upload failed');
});
});

it('uploads objects to a nested path if `awsPrefix` is set', function() {
let FILE_NAME = 'dist-78.zip';
let CONTENT = 'testtest';
let PREFIX = 'blog';
let KEY = `${PREFIX}/${FILE_NAME}`;

fs.writeFileSync(FILE_NAME, CONTENT);

context.fastbootArchivePath = FILE_NAME;
context.fastbootArchiveName = FILE_NAME;

context.config['fastboot-app-server-aws'].awsPrefix = PREFIX;

return plugin.upload(context)
.then(() => {
return get({ Bucket: process.env.TEST_BUCKET, Key: KEY });
})
.then((data) => {
assert.equal(data.Body, CONTENT, 'file was uploaded correctly');
})
.catch(() => {
assert.isTrue(false, 'upload failed');
});
});
});

describe('#fetchRevisions', function() {
Expand All @@ -166,6 +194,19 @@ describe('fastboot-app-server-aws plugin', function() {
});
});

it('respects `awsPrefix` when looking for revisions', function() {
let PREFIX = 'blog';
return setupTestData({ awsPrefix: PREFIX }).then(() => {
context.config['fastboot-app-server-aws'].awsPrefix = PREFIX;
return plugin.fetchRevisions(context)
.then((data) => {
let revisions = data.revisions.map((d) => d.revision);
assert.deepEqual(revisions, ['12', '34', '56']);
assert.isTrue(data.revisions[1].active, 'revision 34 marked current');
});
})
});

it('does not fail when bucket is empty', function() {
return cleanBucket()
.then(() => {
Expand All @@ -188,6 +229,19 @@ describe('fastboot-app-server-aws plugin', function() {
});
});

it('respects `awsPrefix` when fetching initial revisions', function() {
let PREFIX = 'blog';
return setupTestData({ awsPrefix: PREFIX }).then(() => {
context.config['fastboot-app-server-aws'].awsPrefix = PREFIX;
return plugin.fetchInitialRevisions(context)
.then((data) => {
let revisions = data.initialRevisions.map((d) => d.revision);
assert.deepEqual(revisions, ['12', '34', '56']);
assert.isTrue(data.initialRevisions[1].active, 'revision 34 marked current');
});
})
});

it('does not fail when bucket is empty', function() {
return cleanBucket()
.then(() => {
Expand Down Expand Up @@ -226,6 +280,35 @@ describe('fastboot-app-server-aws plugin', function() {
assert.isTrue(false, "can't find manifest-file");
});
});

it('uploads the manifest with a key prefix if `awsPrefix` is set', function() {
let PREFIX = 'blog';

context.commandOptions = {
revision: '56'
};
context.config['fastboot-app-server-aws'].awsPrefix = PREFIX;

return plugin.activate(context)
.then(() => {
return get({
Bucket: process.env.TEST_BUCKET,
Key: `${PREFIX}/fastboot-deploy-info.json`
});
})
.then((data) => {
let expected = {
bucket: process.env.TEST_BUCKET,
key: `${PREFIX}/dist-56.zip`
};
let actual = JSON.parse(data.Body.toString());

assert.deepEqual(actual, expected, 'manifest file updated as expected');
})
.catch(() => {
assert.isTrue(false, "can't find manifest-file");
});
});
});
});
});