Skip to content

Commit

Permalink
Brings storage rules deploy into the CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
mbleigh committed Sep 19, 2017
1 parent ef6cb05 commit 7976470
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 21 deletions.
25 changes: 25 additions & 0 deletions lib/deploy/storage/deploy.js
@@ -0,0 +1,25 @@
'use strict';

var _ = require('lodash');
var RSVP = require('rsvp');

var gcp = require('../../gcp');
var utils = require('../../utils');

module.exports = function(context, options) {
var files = _.get(context, 'storage.rules');
if (!files) {
return RSVP.resolve();
}

return gcp.storage.buckets.getDefault(options.project).then(function(defaultBucket) {
if (!defaultBucket) {
return utils.reject('Unable to locate your default bucket. Please visit the storage panel in the Firebase console to ensure provisioning.');
}

context.storage.defaultBucket = defaultBucket;
return gcp.rules.createRuleset(options.project, files);
}).then(function(rulesetName) {
context.storage.rulesetName = rulesetName;
});
};
4 changes: 3 additions & 1 deletion lib/deploy/storage/index.js
@@ -1,5 +1,7 @@
'use strict';

module.exports = {
prepare: require('./prepare')
prepare: require('./prepare'),
deploy: require('./deploy'),
release: require('./release')
};
26 changes: 8 additions & 18 deletions lib/deploy/storage/prepare.js
@@ -1,29 +1,21 @@
'use strict';

var chalk = require('chalk');
var fs = require('fs');
var RSVP = require('rsvp');
var api = require('../../api');

var gcp = require('../../gcp');
var utils = require('../../utils');
var chalk = require('chalk');

module.exports = function(context, options, payload) {
module.exports = function(context, options) {
var rulesPath = options.config.get('storage.rules');
if (rulesPath) {
rulesPath = options.config.path(rulesPath);
var src = fs.readFileSync(rulesPath, 'utf8');
var files = [{name: options.config.get('storage.rules'), content: src}];

utils.logBullet(chalk.bold.cyan('storage:') + ' checking rules for compilation errors...');
return api.request('POST', '/v1/projects/' + encodeURIComponent(options.project) + ':test', {
origin: api.rulesOrigin,
data: {
source: {
files: [{
content: src,
name: 'storage.rules'
}]
}
},
auth: true
}).then(function(response) {
return gcp.rules.testRuleset(options.project, files).then(function(response) {
if (response.body && response.body.issues && response.body.issues.length > 0) {
var add = response.body.issues.length === 1 ? '' : 's';
var message = 'Compilation error' + add + ' in ' + chalk.bold(options.config.get('storage.rules')) + ':\n';
Expand All @@ -35,9 +27,7 @@ module.exports = function(context, options, payload) {
}

utils.logSuccess(chalk.bold.green('storage:') + ' rules file compiled successfully');
payload.storage = {rules: [
{name: options.config.get('storage.rules'), content: src}
]};
context.storage = {rules: files};
return RSVP.resolve();
});
}
Expand Down
18 changes: 18 additions & 0 deletions lib/deploy/storage/release.js
@@ -0,0 +1,18 @@
'use strict';

var chalk = require('chalk');

var gcp = require('../../gcp');
var utils = require('../../utils');

var STORAGE_RELEASE_NAME = 'firebase.storage';

module.exports = function(context, options) {
return gcp.rules.updateOrCreateRelease(
options.project,
context.storage.rulesetName,
[STORAGE_RELEASE_NAME, context.storage.defaultBucket].join('/')
).then(function() {
utils.logSuccess(chalk.bold.green('storage: ') + 'released rules for bucket ' + context.storage.defaultBucket);
});
};
5 changes: 3 additions & 2 deletions lib/gcp/index.js
@@ -1,8 +1,9 @@
'use strict';

module.exports = {
cloudlogging: require('./cloudlogging'),
apikeys: require('./apikeys'),
cloudfunctions: require('./cloudfunctions'),
cloudlogging: require('./cloudlogging'),
storage: require('./storage'),
apikeys: require('./apikeys')
rules: require('./rules')
};
114 changes: 114 additions & 0 deletions lib/gcp/rules.js
@@ -0,0 +1,114 @@
'use strict';

var api = require('../api');
var logger = require('../logger');
var utils = require('../utils');

function _handleErrorResponse(response) {
if (response.body && response.body.error) {
return utils.reject(response.body.error, {code: 2});
}

logger.debug('[rules] error:', response.status, response.body);
return utils.reject('Unexpected error encountered deploying rules.', {code: 2});
}

/**
* Creates a new ruleset which can then be associated with a release.
* @param {String} projectId Project on which you want to create the ruleset.
* @param {Array} files Array of `{name, content}` for the source files.
*/
function createRuleset(projectId, files) {
var payload = {source: {files: files}};

return api.request('POST', '/v1/projects/' + projectId + '/rulesets', {
auth: true,
data: payload,
origin: api.rulesOrigin
}).then(function(response) {
if (response.status === 200) {
logger.debug('[rules] created ruleset', response.body.name);
return response.body.name;
}

return _handleErrorResponse(response);
});
}

/**
* Create a new named release with the specified ruleset.
* @param {String} projectId Project on which you want to create the ruleset.
* @param {String} rulesetName The unique identifier for the ruleset you want to release.
* @param {String} releaseName The name (e.g. `firebase.storage`) of the release you want to create.
*/
function createRelease(projectId, rulesetName, releaseName) {
var payload = {
name: 'projects/' + projectId + '/releases/' + releaseName,
rulesetName: rulesetName
};

return api.request('POST', '/v1/projects/' + projectId + '/releases', {
auth: true,
data: payload,
origin: api.rulesOrigin
}).then(function(response) {
if (response.status === 200) {
logger.debug('[rules] created release', response.body.name);
return response.body.name;
}

return _handleErrorResponse(response);
});
}

/**
* Update an existing release with the specified ruleset.
* @param {String} projectId Project on which you want to create the ruleset.
* @param {String} rulesetName The unique identifier for the ruleset you want to release.
* @param {String} releaseName The name (e.g. `firebase.storage`) of the release you want to update.
*/
function updateRelease(projectId, rulesetName, releaseName) {
var payload = {
name: 'projects/' + projectId + '/releases/' + releaseName,
rulesetName: rulesetName
};

return api.request('PUT', '/v1/projects/' + projectId + '/releases/' + releaseName, {
auth: true,
data: payload,
origin: api.rulesOrigin
}).then(function(response) {
if (response.status === 200) {
logger.debug('[rules] updated release', response.body.name);
return response.body.name;
}

return _handleErrorResponse(response);
});
}

function updateOrCreateRelease(projectId, rulesetName, releaseName) {
logger.debug('[rules] releasing', releaseName, 'with ruleset', rulesetName);
return updateRelease(projectId, rulesetName, releaseName).catch(function() {
logger.debug('[rules] ruleset update failed, attempting to create instead');
return createRelease(projectId, rulesetName, releaseName);
});
}

function testRuleset(projectId, files) {
return api.request('POST', '/v1/projects/' + encodeURIComponent(projectId) + ':test', {
origin: api.rulesOrigin,
data: {
source: {files: files}
},
auth: true
});
}

module.exports = {
createRuleset: createRuleset,
createRelease: createRelease,
updateRelease: updateRelease,
updateOrCreateRelease: updateOrCreateRelease,
testRuleset: testRuleset
};

0 comments on commit 7976470

Please sign in to comment.