Templates: now available at the Project level. Any file in the project root that starts with 's-template...' can contain templates

This commit is contained in:
ac360 2016-01-21 18:00:01 -08:00
parent e2d4fc78d6
commit 145a7a8bbf
10 changed files with 139 additions and 120 deletions

View File

@ -59,6 +59,7 @@ class Serverless {
this.cli = null;
this.state = new this.classes.State(this);
// If project
if (this.config.projectPath) {
@ -108,7 +109,7 @@ class Serverless {
* - Returns a Promise
*/
_init() {
init() {
return this.state.load();
}
@ -134,7 +135,7 @@ class Serverless {
options: extend(_this.cli.options, _this.cli.params)
};
if (_this.config.projectPath) return _this._init();
if (_this.config.projectPath) return _this.init();
} else {

View File

@ -288,9 +288,7 @@ class ServerlessFunction {
module: this._config.module
});
if (modules.length === 1) {
return modules[0];
}
if (modules.length === 1) return modules[0];
throw new SError('Could not find module for function');
}

View File

@ -21,19 +21,20 @@ class ServerlessProject {
constructor(Serverless) {
let _this = this;
this._S = Serverless;
this._S = Serverless;
// Default properties
_this.name = 'serverless' + SUtils.generateShortId(6);
_this.version = '0.0.1';
_this.profile = 'serverless-v' + require('../package.json').version;
_this.location = 'https://github.com/...';
_this.author = '';
_this.description = 'A Slick New Serverless Project';
_this.custom = {};
_this.components = {};
_this.plugins = [];
_this.cloudFormation = {
_this.name = 'serverless' + SUtils.generateShortId(6);
_this.version = '0.0.1';
_this.profile = 'serverless-v' + require('../package.json').version;
_this.location = 'https://github.com/...';
_this.author = '';
_this.description = 'A Slick New Serverless Project';
_this.custom = {};
_this.components = {};
_this.templates = {};
_this.plugins = [];
_this.cloudFormation = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
@ -121,27 +122,34 @@ class ServerlessProject {
throw new SError('Project could not be loaded because it does not exist');
}
projectJson = SUtils.readAndParseJsonSync(path.join(_this._S.config.projectPath, 's-project.json'));
projectJson.components = {};
projectContents = fs.readdirSync(_this._S.config.projectPath);
projectJson = SUtils.readAndParseJsonSync(path.join(_this._S.config.projectPath, 's-project.json'));
projectJson.components = {};
projectJson.templates = {};
projectContents = fs.readdirSync(_this._S.config.projectPath);
return projectContents;
})
.each(function (c, i) {
if (!SUtils.fileExistsSync(path.join(
_this._S.config.projectPath, projectContents[i],
's-component.json'))) return;
// If template, load template
if (c.indexOf('s-template') !== -1) {
projectJson.templates = _.assign(projectJson.templates, SUtils.readAndParseJsonSync(path.join(_this._S.config.projectPath, c)));
return;
}
let component = new _this._S.classes.Component(_this._S, {
component: c
});
// If component, load component
if (SUtils.fileExistsSync(path.join(_this._S.config.projectPath, c, 's-component.json'))) {
return component.load()
.then(function (instance) {
projectJson.components[c] = instance;
return projectJson.components[c];
let component = new _this._S.classes.Component(_this._S, {
component: c
});
return component.load()
.then(function (instance) {
projectJson.components[c] = instance;
return projectJson.components[c];
});
}
})
.then(function () {
@ -230,7 +238,7 @@ class ServerlessProject {
getTemplates() {
let templates = {
_project: {},
_project: this.templates || {},
_components: {}
};

View File

@ -22,8 +22,6 @@ class ServerlessState {
this.meta = new this._S.classes.Meta(this._S);
this.project = new this._S.classes.Project(this._S);
// If project path, load state
if (Serverless.config.projectPath) this.load();
}
/**

View File

@ -158,6 +158,7 @@ exports.getProjectPath = function(startDir) {
exports.getResources = function(projectData) {
let _this = this;
let cfTemplate = JSON.parse(JSON.stringify(projectData.cloudFormation));
// Helper function to aggregate resources
@ -169,7 +170,7 @@ exports.getResources = function(projectData) {
// Merge Lambda Policy Statements
if (cfData.cloudFormation.lambdaIamPolicyDocumentStatements &&
cfData.cloudFormation.lambdaIamPolicyDocumentStatements.length > 0) {
SCli.log('Merging in Lambda IAM Policy statements from: ' + cfData.name);
_this.sDebug('Merging in Lambda IAM Policy statements from: ' + cfData.name);
cfData.cloudFormation.lambdaIamPolicyDocumentStatements.forEach(function (policyStmt) {
cfTemplate.Resources.IamPolicyLambda.Properties.PolicyDocument.Statement.push(policyStmt);
@ -182,13 +183,13 @@ exports.getResources = function(projectData) {
let cfResourceKeys = Object.keys(cfData.cloudFormation.resources);
if (cfResourceKeys.length > 0) {
SCli.log('Merging in CF Resources from module: ' + cfData.name);
_this.sDebug('Merging in CF Resources from module: ' + cfData.name);
}
cfResourceKeys.forEach(function (resourceKey) {
if (cfTemplate.Resources[resourceKey]) {
SCli.log(
_this.log(
chalk.bgYellow.white(' WARN ') +
chalk.magenta(` Resource key ${resourceKey} already defined in CF template. Overwriting...`)
);
@ -623,19 +624,28 @@ exports.populate = function(S, data, stage, region) {
let templates = project.getTemplates();
// Helper function to find template
let _findTemplate = function(template) {
let tempArray = template.split('.');
let module = tempArray[0];
let templateKey = tempArray[1];
let _findTemplate = function(templateVariable) {
let val = null;
for (let prop in templates._components) {
if (templates._components[prop][module] &&
templates._components[prop][module][templateKey]) {
val = templates._components[prop][module][templateKey];
if (templateVariable.indexOf('.') !== -1) {
// Template is a Module Template
let tempArray = templateVariable.split('.');
let module = tempArray[0];
let templateKey = tempArray[1];
// Check module-level templates
for (let prop in templates._components) {
if (templates._components[prop][module] &&
templates._components[prop][module][templateKey]) {
val = templates._components[prop][module][templateKey];
}
}
} else {
// Template is a Project Template
if (templates._project[templateVariable]) val = templates._project[templateVariable];
}
return val;

View File

@ -10,23 +10,23 @@ describe('All Tests', function() {
});
after(function() {});
require('./tests/classes/ServerlessEndpointTest');
require('./tests/classes/ServerlessFunctionTest');
require('./tests/classes/ServerlessModuleTest');
require('./tests/classes/ServerlessComponentTest');
require('./tests/classes/ServerlessProjectTest');
require('./tests/classes/ServerlessStateTest');
//require('./tests/classes/ServerlessEndpointTest');
//require('./tests/classes/ServerlessFunctionTest');
//require('./tests/classes/ServerlessModuleTest');
//require('./tests/classes/ServerlessComponentTest');
//require('./tests/classes/ServerlessProjectTest');
//require('./tests/classes/ServerlessStateTest');
//require('./tests/actions/TestPluginCustom');
//require('./tests/actions/TestDefaultActionHook');
//require('./tests/actions/StageCreate');
//require('./tests/actions/RegionCreate');
require('./tests/actions/ComponentCreate');
require('./tests/actions/ModuleCreate');
require('./tests/actions/FunctionCreate');
//require('./tests/actions/ComponentCreate');
//require('./tests/actions/ModuleCreate');
//require('./tests/actions/FunctionCreate');
//require('./tests/actions/EnvList');
//require('./tests/actions/EnvGet');
//require('./tests/actions/EnvSetUnset');
//require('./tests/actions/ResourcesDeploy');
require('./tests/actions/ResourcesDeploy');
//require('./tests/actions/FunctionRun');
//require('./tests/actions/FunctionDeploy');
//require('./tests/actions/EndpointDeploy');

View File

@ -8,68 +8,5 @@
"custom": {},
"modules": {},
"plugins": [],
"cloudFormation": {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "${stage}-${project}-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${region}:*:*"
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}
"cloudFormation": "$${projectCloudFormation}"
}

View File

@ -0,0 +1,66 @@
{
"projectCloudFormation": {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "${stage}-${project}-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${region}:*:*"
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}
}

View File

@ -46,7 +46,8 @@ describe('Test action: Resources Deploy', function() {
projectPath: projPath
});
return serverless.state.load().then(function() {
return serverless.init()
.then(function() {
SUtils.sDebug('Adding test bucket resource');

View File

@ -59,7 +59,7 @@ describe('Test Serverless State Class', function() {
});
it('Get populated instance data', function(done) {
let data = instance.getPopulated({ stage: config.stage, region: config.region })
let data = instance.getPopulated({ stage: config.stage, region: config.region });
assert.equal(true, JSON.stringify(data).indexOf('$${') == -1);
assert.equal(true, JSON.stringify(data).indexOf('${') == -1);
done();