mirror of
https://github.com/serverless/serverless.git
synced 2026-01-25 15:07:39 +00:00
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:
parent
e2d4fc78d6
commit
145a7a8bbf
@ -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 {
|
||||
|
||||
|
||||
@ -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');
|
||||
}
|
||||
|
||||
@ -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: {}
|
||||
};
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
20
tests/all.js
20
tests/all.js
@ -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');
|
||||
|
||||
@ -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}"
|
||||
}
|
||||
66
tests/test-prj/s-templates.json
Normal file
66
tests/test-prj/s-templates.json
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user