diff --git a/lib/Serverless.js b/lib/Serverless.js index 8da591b47..0a49ac05d 100644 --- a/lib/Serverless.js +++ b/lib/Serverless.js @@ -176,8 +176,11 @@ class Serverless { // Get Meta Object, Populate Variables if (_this._projectRootPath) { _this._meta = SUtils.getMeta(_this._projectRootPath); - console.log("Loaded: ", _this._meta) - // TODO: Populate Variables Here, Detect Stage/Region via CLI or evt + + //_this._project = SUtils.populateVariables(_this._project, _this._meta, { + // type: 'private' + //}); + //console.log(_this._project); } // Add pre hooks, action, then post hooks to queued diff --git a/lib/templates/s-project.json b/lib/templates/s-project.json index 53553269d..1c2a8bd12 100644 --- a/lib/templates/s-project.json +++ b/lib/templates/s-project.json @@ -37,7 +37,7 @@ "IamPolicyLambda": { "Type": "AWS::IAM::Policy", "Properties": { - "PolicyName": "$$stage-$$projectName-lambda", + "PolicyName": "${stage}-${projectName}-lambda", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -48,7 +48,7 @@ "logs:CreateLogStream", "logs:PutLogEvents" ], - "Resource": "arn:aws:logs:$$region:*:" + "Resource": "arn:aws:logs:${region}:*:" } ] }, diff --git a/lib/utils/index.js b/lib/utils/index.js index a4f72d0b1..9487d9173 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -9,6 +9,7 @@ let BbPromise = require('bluebird'), rawDebug = require('debug'), path = require('path'), async = require('async'), + traverse = require('traverse'), readdirp = require('readdirp'), SError = require('../ServerlessError'), fs = require('fs'), @@ -218,6 +219,74 @@ exports.saveMeta = function(projectRootPath, projectMeta) { }; +/** + * Populate Variables + * - variable names are provided with the ${someVar} syntax. Ex. {projectName: '${someVar}'} + * - variables can be of any type, but since they're referenced in JSON, variable names should always be in string quotes: + * - Ex. {projectName: '${someVar}'} - someVar can be an obj, or array...etc + * - you can provide more than one variable in a string. Ex. {projectName: '${firstName}-${lastName}-project'} + * - we get the value of the variable based on stage/region provided. If both are provided, we'll get the region specific value, + * - if only stage is provided, we'll get the stage specific value, if none is provided, we'll get the private or public specific value (depending on the type property of the option obj) + * - example options: {type: 'private', stage: 'development', region: 'us-east-1'} + **/ + +exports.populateVariables = function(project, meta, options) { + + options.type = options.type || 'private'; // private is the default type + + // Validate providing region without stage is invalid! + if (!options.stage) options.region = null; + + // Validate Stage exists + if (typeof options.stage != 'undefined' && !meta.private.stages[options.stage]) { + throw Error('Stage doesnt exist!'); + } + + // Validate Region exists + if (typeof options.region != 'undefined' && !meta.private.stages[options.stage].regions[options.region]) { + throw Error('Region doesnt exist in the provided stage!'); + } + + // Traverse the whole project and replace variables + traverse(project).forEach(function(projectVal) { + + // check if the current string is a variable + if (typeof(projectVal) === 'string' && projectVal.match(/\${([^{}]*)}/g) != null) { + + let newVal = projectVal; + + // get all ${variable} + projectVal.match(/\${([^{}]*)}/g).forEach(function(variableSyntax) { + let variableName = variableSyntax.replace('${', '').replace('}', ''); + + let value; + if (options.stage && options.region) { + value = meta[options.type].stages[options.stage].regions[options.region].variables[variableName]; + + } else if (options.stage) { + value = meta[options.type].stages[options.stage].variables[variableName]; + + } else if (!options.stage && !options.region) { + value = meta[options.type].variables[variableName]; + } + + if (typeof value === 'undefined') { + throw Error('Variable Doesnt exist!'); + } else if (typeof value === 'string') { + newVal = newVal.replace(variableSyntax, value); + } else { + newVal = value; + } + }); + + this.update(newVal); + + } + }); + + return project; +}; + /** * Execute (Command) */ diff --git a/other/examples/project.json b/other/examples/project.json index b9e9d01fd..203baf79e 100644 --- a/other/examples/project.json +++ b/other/examples/project.json @@ -34,7 +34,7 @@ "IamPolicyLambda": { "Type": "AWS::IAM::Policy", "Properties": { - "PolicyName": "$$stage-$$projectName-lambda", + "PolicyName": "${stage}-${projectName}-lambda", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -45,7 +45,7 @@ "logs:CreateLogStream", "logs:PutLogEvents" ], - "Resource": "arn:aws:logs:$$region:*:" + "Resource": "arn:aws:logs:${region}:*:" } ] }, diff --git a/package.json b/package.json index 028dee213..2af9069a4 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "shelljs": "^0.5.3", "shortid": "^2.2.2", "temp": "^0.8.3", + "traverse": "^0.6.6", "wrench": "^1.5.8" } }