From 02e9ab9e7edb695afe804b95df4bbaf339259063 Mon Sep 17 00:00:00 2001 From: David Von Lehman Date: Fri, 10 Apr 2015 11:33:57 -0700 Subject: [PATCH] New deleteAllVersions and listFiles functions --- README.md | 14 ++++--- lib/s3.js | 56 +++++++++++++++++++++------- test/s3.js | 107 ++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 127 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index e55f075..6c08a0e 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,6 @@ You can pass in any valid option accepted by the [AWS.config](http://docs.aws.am ~~~js // Deploy an individual file -var fileInfo = { - path: '/js/app.js', - contents: fs.createReadStream('/js/app.js'), - size: fs.statSync('/js/app.js').size -}; - s3Deployments.deployFile(appId, versionId, fileInfo, callback); // Returns a readable stream @@ -45,10 +39,18 @@ s3Deployments.readFileStream(appId, versionId, filePath); // Delete version s3Deployments.deleteVersion(appId, versionId, callback); +// Delete all deployed versions for an app +s3Deployments.deleteAllVersions(appId, callback); + +// List all the files for a version +s3Deployments.listFiles(appId, versionId, callback); + // Check if file exists s3Deployments.fileExists(appId, versionId, filePath, callback); ~~~ +See the [unit tests](https://github.com/4front/s3-deployments/blob/master/test/s3.js) for example calls of all these functions. + ## Running Tests ~~~ npm test diff --git a/lib/s3.js b/lib/s3.js index 45e6475..2f73cb6 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -60,20 +60,7 @@ S3Deployments.prototype.readFileStream = function(appId, versionId, filePath) { // Delete a deployed version of an app S3Deployments.prototype.deleteVersion = function(appId, versionId, callback) { - var self = this; - var prefix = appId + '/' + versionId; - - this._s3.listObjects({Bucket: this.options.bucket, Prefix: prefix}, function(err, data) { - if (err) - return callback(err); - - // Now delete each object - var keys = _.map(data.Contents, "Key"); - - async.each(keys, function(key, cb) { - self._s3.deleteObject({Bucket: self.options.bucket, Key: key}, cb); - }, callback); - }); + this._deleteObjects(appId + "/" + versionId, callback); }; S3Deployments.prototype.fileExists = function(appId, versionId, filePath, callback) { @@ -91,3 +78,44 @@ S3Deployments.prototype.fileExists = function(appId, versionId, filePath, callba callback(null, true); }); }; + +// Delete all deployed versions for a given application +S3Deployments.prototype.deleteAllVersions = function(appId, callback) { + this._deleteObjects(appId, callback); +}; + +// List the files deployed for a given version +S3Deployments.prototype.listFiles = function(appId, versionId, callback) { + var prefix = appId + '/' + versionId; + this._listKeys(prefix, function(err, keys) { + if (err) return callback(err); + + var prefixLength = prefix.length; + var filePaths = _.map(keys, function(key) { + return key.slice(prefixLength + 1); + }); + + callback(null, filePaths); + }); +}; + +S3Deployments.prototype._listKeys = function(prefix, callback) { + var self = this; + this._s3.listObjects({Bucket: this.options.bucket, Prefix: prefix}, function(err, data) { + if (err) + return callback(err); + + callback(null, _.map(data.Contents, "Key")); + }); +}; + +S3Deployments.prototype._deleteObjects = function(prefix, callback) { + var self = this; + this._listKeys(prefix, function(err, keys) { + if (err) return callback(err); + + async.each(keys, function(key, cb) { + self._s3.deleteObject({Bucket: self.options.bucket, Key: key}, cb); + }, callback); + }); +}; diff --git a/test/s3.js b/test/s3.js index d3f24d3..31af41b 100644 --- a/test/s3.js +++ b/test/s3.js @@ -12,21 +12,20 @@ require('dash-assert'); describe('S3Deployments', function() { var self; + var port = 4658; + var bucket = "4front-deployments"; + + var s3Deployments = new S3Deployments({ + bucket: bucket, + accessKeyId: "123", + secretAccessKey: "abc", + endpoint: "localhost:" + port, + sslEnabled: false, + s3ForcePathStyle: true + }); + before(function(done) { self = this; - - var port = 4658; - var bucket = "4front-deployments"; - - this.s3 = new S3Deployments({ - bucket: bucket, - accessKeyId: "123", - secretAccessKey: "abc", - endpoint: "localhost:" + port, - sslEnabled: false, - s3ForcePathStyle: true - }); - var s3rver = new S3rver(); var fakeS3Dir = '/tmp/s3rver'; @@ -50,7 +49,7 @@ describe('S3Deployments', function() { }, function(cb) { // Ensure the bucket exists - self.s3._s3.createBucket({ACL: 'public-read', Bucket: bucket}, function(err) { + s3Deployments._s3.createBucket({ACL: 'public-read', Bucket: bucket}, function(err) { if (err && err.code !== 'BucketAlreadyExists') return cb(err); @@ -76,10 +75,10 @@ describe('S3Deployments', function() { async.series([ function(cb) { - self.s3.deployFile(self.appId, self.versionId, fileInfo, cb); + s3Deployments.deployFile(self.appId, self.versionId, fileInfo, cb); }, function(cb) { - self.s3.fileExists(self.appId, self.versionId, fileInfo.path, function(err, exists) { + s3Deployments.fileExists(self.appId, self.versionId, fileInfo.path, function(err, exists) { if (err) return cb(err); assert.isTrue(exists); @@ -88,7 +87,7 @@ describe('S3Deployments', function() { }, function(cb) { var output = ''; - self.s3.readFileStream(self.appId, self.versionId, fileInfo.path) + s3Deployments.readFileStream(self.appId, self.versionId, fileInfo.path) .on('data', function(chunk) { output += chunk.toString(); }) @@ -104,7 +103,7 @@ describe('S3Deployments', function() { }); it('fileExists returns false for missing file', function(done) { - self.s3.fileExists(this.appId, this.versionId, 'missingfile.txt', function(err, exists) { + s3Deployments.fileExists(this.appId, this.versionId, 'missingfile.txt', function(err, exists) { if (err) return done(err); assert.isFalse(exists); @@ -113,7 +112,7 @@ describe('S3Deployments', function() { }); it('read missing file', function(done) { - this.s3.readFileStream(this.appId, this.versionId, 'missingfile.txt') + s3Deployments.readFileStream(this.appId, this.versionId, 'missingfile.txt') .on('missing', function(err) { assert.equal(err.code, 'fileNotFound'); done(); @@ -123,29 +122,39 @@ describe('S3Deployments', function() { }); }); - it('delete version', function(done) { + it('listFiles()', function(done) { + var files = ["js/main.js", "css/styles.css", "index.html"]; + async.series([ + function(cb) { + deployTestFiles(self.appId, self.versionId, files, cb); + }, + function(cb) { + s3Deployments.listFiles(self.appId, self.versionId, function(err, data) { + if (err) return cb(err); + + assert.noDifferences(files, data); + cb(); + }) + } + ], done); + }); + + it('deleteVersion()', function(done) { var files = ['js/main.js', 'css/styles.css']; async.series([ function(cb) { // Upload some files - async.each(files, function(path, cb1) { - var fileInfo = { - path: path, - contents: sbuff(path), - size: path.length - }; - self.s3.deployFile(self.appId, self.versionId, fileInfo, cb1); - }, cb); + deployTestFiles(self.appId, self.versionId, files, cb); }, function(cb) { // Delete the version - self.s3.deleteVersion(self.appId, self.versionId, cb); + s3Deployments.deleteVersion(self.appId, self.versionId, cb); }, function(cb) { // Verify that the files are gone. async.each(files, function(filePath, cb1) { - self.s3.fileExists(self.appId, self.versionId, filePath, function(err, exists) { + s3Deployments.fileExists(self.appId, self.versionId, filePath, function(err, exists) { if (err) return cb1(err); assert.isFalse(exists); @@ -155,4 +164,42 @@ describe('S3Deployments', function() { } ], done); }); + + it('deleteAllVersions()', function(done) { + var versions = _.times(3, function() { + return shortid.generate(); + }); + + var files = ['js/main.js', 'css/styles.css']; + + async.series([ + function(cb) { + async.each(versions, function(versionId, cb1) { + deployTestFiles(self.appId, versionId, files, cb1); + }, cb); + }, + function(cb) { + // Delete the application + s3Deployments.deleteAllVersions(self.appId, cb); + }, + function(cb) { + // Verify that the versions are gone + s3Deployments._listKeys(self.appId, function(err, keys) { + assert.equal(0, keys.length); + cb(); + }); + } + ], done); + }); + + function deployTestFiles(appId, versionId, files, callback) { + async.each(files, function(path, cb) { + var fileInfo = { + path: path, + contents: sbuff(path), + size: path.length + }; + s3Deployments.deployFile(appId, versionId, fileInfo, cb); + }, callback); + } });