mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
basic new variable system
This commit is contained in:
parent
2bc3ac38bb
commit
5dafeee388
@ -54,7 +54,7 @@ class Serverless {
|
||||
.then(() => {
|
||||
// set the provider of the service (so that the PluginManager takes care to
|
||||
// execute the correct provider specific plugins)
|
||||
this.pluginManager.setProvider(this.service.provider.name || this.service.provider);
|
||||
this.pluginManager.setProvider(this.service.provider.name);
|
||||
|
||||
// load all plugins
|
||||
this.pluginManager.loadAllPlugins(this.service.plugins);
|
||||
@ -62,6 +62,9 @@ class Serverless {
|
||||
// give the CLI the plugins so that it can print out plugin information
|
||||
// such as options when the user enters --help
|
||||
this.cli.setLoadedPlugins(this.pluginManager.getPlugins());
|
||||
|
||||
// populate variables after processing options
|
||||
return this.service.populate(this.pluginManager.cliOptions);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ class Service {
|
||||
this.defaults = {
|
||||
stage: 'dev',
|
||||
region: 'us-east-1',
|
||||
variableSyntax: null,
|
||||
variableSyntax: '\\${([a-zA-Z0-9._\\-\\/\\(\\)]+?)}',
|
||||
};
|
||||
this.custom = {};
|
||||
this.plugins = [];
|
||||
@ -30,9 +30,9 @@ class Service {
|
||||
if (data) this.update(data);
|
||||
}
|
||||
|
||||
load(opts) {
|
||||
load(rawOptions) {
|
||||
const that = this;
|
||||
const options = opts || {};
|
||||
const options = rawOptions || {};
|
||||
options.stage = options.stage || options.s;
|
||||
options.region = options.region || options.r;
|
||||
const servicePath = that.serverless.config.servicePath;
|
||||
@ -50,279 +50,321 @@ class Service {
|
||||
.join(this.serverless.config.servicePath, 'serverless.yaml');
|
||||
}
|
||||
|
||||
let serverlessEnvYmlPath = path.join(servicePath, 'serverless.env.yml');
|
||||
// change to serverless.env.yaml if the file could not be found
|
||||
if (!this.serverless.utils.fileExistsSync(serverlessEnvYmlPath)) {
|
||||
serverlessEnvYmlPath = path
|
||||
.join(this.serverless.config.servicePath, 'serverless.env.yaml');
|
||||
}
|
||||
|
||||
return that.serverless.yamlParser
|
||||
.parse(serverlessYmlPath)
|
||||
.then((serverlessYmlParam) => {
|
||||
const serverlessYml = serverlessYmlParam;
|
||||
.then((serverlessFileParam) => {
|
||||
const serverlessFile = serverlessFileParam;
|
||||
// basic service level validation
|
||||
if (!serverlessYml.service) {
|
||||
if (!serverlessFile.service) {
|
||||
throw new SError('"service" property is missing in serverless.yml');
|
||||
}
|
||||
if (!serverlessYml.provider) {
|
||||
if (!serverlessFile.provider) {
|
||||
throw new SError('"provider" property is missing in serverless.yml');
|
||||
}
|
||||
if (!serverlessYml.functions) {
|
||||
if (!serverlessFile.functions) {
|
||||
throw new SError('"functions" property is missing in serverless.yml');
|
||||
}
|
||||
|
||||
if (typeof serverlessYml.provider !== 'object') {
|
||||
const providerName = serverlessYml.provider;
|
||||
serverlessYml.provider = {
|
||||
if (typeof serverlessFile.provider !== 'object') {
|
||||
const providerName = serverlessFile.provider;
|
||||
serverlessFile.provider = {
|
||||
name: providerName,
|
||||
};
|
||||
}
|
||||
|
||||
if (['aws', 'azure', 'google', 'ibm'].indexOf(serverlessYml.provider.name)) {
|
||||
if (['aws', 'azure', 'google', 'ibm'].indexOf(serverlessFile.provider.name)) {
|
||||
const errorMessage = [
|
||||
`Provider "${serverlessYml.provider.name}" is not supported.`,
|
||||
`Provider "${serverlessFile.provider.name}" is not supported.`,
|
||||
' Valid values for provider are: aws, azure, google, ibm.',
|
||||
' Please provide one of those values to the "provider" property in serverless.yml.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
|
||||
that.service = serverlessYml.service;
|
||||
that.provider = serverlessYml.provider;
|
||||
that.custom = serverlessYml.custom;
|
||||
that.plugins = serverlessYml.plugins;
|
||||
that.resources = serverlessYml.resources;
|
||||
that.functions = serverlessYml.functions;
|
||||
|
||||
_.forEach(that.functions, (functionObj, index) => {
|
||||
if (!functionObj.events) {
|
||||
that.functions[index].events = [];
|
||||
}
|
||||
});
|
||||
|
||||
if (serverlessYml.package && serverlessYml.package.artifact) {
|
||||
that.package.artifact = serverlessYml.package.artifact;
|
||||
}
|
||||
if (serverlessYml.package && serverlessYml.package.exclude) {
|
||||
that.package.exclude = serverlessYml.package.exclude;
|
||||
}
|
||||
if (serverlessYml.package && serverlessYml.package.include) {
|
||||
that.package.include = serverlessYml.package.include;
|
||||
}
|
||||
|
||||
if (serverlessYml.defaults && serverlessYml.defaults.stage) {
|
||||
this.defaults.stage = serverlessYml.defaults.stage;
|
||||
}
|
||||
if (serverlessYml.defaults && serverlessYml.defaults.region) {
|
||||
this.defaults.region = serverlessYml.defaults.region;
|
||||
}
|
||||
if (serverlessYml.defaults && serverlessYml.defaults.variableSyntax) {
|
||||
this.defaults.variableSyntax = serverlessYml.defaults.variableSyntax;
|
||||
}
|
||||
})
|
||||
.then(() => that.serverless.yamlParser
|
||||
.parse(serverlessEnvYmlPath))
|
||||
.then((serverlessEnvYmlParam) => {
|
||||
const serverlessEnvYml = serverlessEnvYmlParam;
|
||||
|
||||
// safely load serverless.env.yml while avoiding
|
||||
// reference errors
|
||||
serverlessEnvYml.vars = serverlessEnvYml.vars || {};
|
||||
serverlessEnvYml.stages = serverlessEnvYml.stages || {};
|
||||
Object.keys(serverlessEnvYml.stages).forEach(stage => {
|
||||
serverlessEnvYml.stages[stage] = serverlessEnvYml.stages[stage] || {};
|
||||
serverlessEnvYml.stages[stage].vars = serverlessEnvYml.stages[stage].vars || {};
|
||||
serverlessEnvYml.stages[stage].regions = serverlessEnvYml.stages[stage].regions || {};
|
||||
Object.keys(serverlessEnvYml.stages[stage].regions).forEach(region => {
|
||||
serverlessEnvYml.stages[stage].regions[region] =
|
||||
serverlessEnvYml.stages[stage].regions[region] || {};
|
||||
serverlessEnvYml.stages[stage].regions[region].vars =
|
||||
serverlessEnvYml.stages[stage].regions[region].vars || {};
|
||||
});
|
||||
});
|
||||
|
||||
that.environment = serverlessEnvYml;
|
||||
|
||||
return BbPromise.resolve(that);
|
||||
})
|
||||
.then(() => {
|
||||
if (!options.stage) {
|
||||
options.stage = this.defaults.stage;
|
||||
}
|
||||
|
||||
if (!options.region) {
|
||||
options.region = this.defaults.region;
|
||||
}
|
||||
|
||||
// Validate: Check stage exists
|
||||
this.getStage(options.stage);
|
||||
|
||||
// Validate: Check region exists in stage
|
||||
this.getRegionInStage(options.stage, options.region);
|
||||
that.service = serverlessFile.service;
|
||||
that.provider = serverlessFile.provider;
|
||||
that.custom = serverlessFile.custom;
|
||||
that.plugins = serverlessFile.plugins;
|
||||
that.resources = serverlessFile.resources;
|
||||
that.functions = serverlessFile.functions;
|
||||
|
||||
// setup function.name property
|
||||
_.forEach(that.functions, (functionObj, functionName) => {
|
||||
if (!functionObj.events) {
|
||||
that.functions[functionName].events = [];
|
||||
}
|
||||
|
||||
if (!functionObj.name) {
|
||||
that.functions[functionName].name = `${that.service}-${options.stage}-${functionName}`;
|
||||
}
|
||||
});
|
||||
|
||||
let varTemplateSyntax = /\${([\s\S]+?)}/g;
|
||||
|
||||
if (this.defaults && this.defaults.variableSyntax) {
|
||||
varTemplateSyntax = RegExp(this.defaults.variableSyntax, 'g');
|
||||
|
||||
// temporally remove variable syntax from service otherwise it'll match
|
||||
this.defaults.variableSyntax = true;
|
||||
if (serverlessFile.package && serverlessFile.package.artifact) {
|
||||
that.package.artifact = serverlessFile.package.artifact;
|
||||
}
|
||||
if (serverlessFile.package && serverlessFile.package.exclude) {
|
||||
that.package.exclude = serverlessFile.package.exclude;
|
||||
}
|
||||
if (serverlessFile.package && serverlessFile.package.include) {
|
||||
that.package.include = serverlessFile.package.include;
|
||||
}
|
||||
|
||||
const commonVars = this.getVariables();
|
||||
const stageVars = this.getVariables(options.stage);
|
||||
const regionVars = this.getVariables(options.stage, options.region);
|
||||
if (serverlessFile.defaults && serverlessFile.defaults.stage) {
|
||||
this.defaults.stage = serverlessFile.defaults.stage;
|
||||
}
|
||||
if (serverlessFile.defaults && serverlessFile.defaults.region) {
|
||||
this.defaults.region = serverlessFile.defaults.region;
|
||||
}
|
||||
if (serverlessFile.defaults && serverlessFile.defaults.variableSyntax) {
|
||||
this.defaults.variableSyntax = serverlessFile.defaults.variableSyntax;
|
||||
}
|
||||
|
||||
// temporally remove environment obj. Doesn't make sense to
|
||||
// populate environment (stages, regions, vars)
|
||||
const environment = _.cloneDeep(this.environment);
|
||||
this.environment = null;
|
||||
if (serverlessFile.defaults) {
|
||||
const warningMessage = [
|
||||
'Deprecation Notice: the "defaults" property in serverless.yml',
|
||||
' is deprecated. The "stage", "region" & "variableSyntax" properties',
|
||||
' has been moved to the "provider" property instead. Please update',
|
||||
' your serverless.yml file asap. For more info, you can check our docs.',
|
||||
].join('');
|
||||
this.serverless.cli.log(warningMessage);
|
||||
|
||||
/*
|
||||
* we can't use an arrow function in this case cause that would
|
||||
* change the lexical scoping required by the traverse module
|
||||
*/
|
||||
traverse(this).forEach(function (valParam) {
|
||||
const t = this;
|
||||
let val = valParam;
|
||||
|
||||
// check if the current string is a variable
|
||||
if (typeof (val) === 'string' && val.match(varTemplateSyntax)) {
|
||||
// get all ${variable} in the string
|
||||
val.match(varTemplateSyntax).forEach((variableSyntax) => {
|
||||
const variableString = variableSyntax
|
||||
.replace(varTemplateSyntax, (match, varName) => varName.trim());
|
||||
|
||||
const variableName = (variableString
|
||||
.split('.').length > 1) ? variableString
|
||||
.split('.')[0] : variableString;
|
||||
|
||||
let value;
|
||||
|
||||
/*
|
||||
* we will manipulate the value later
|
||||
* so we gotta clone otherwise we will
|
||||
* corrupt the passed-by-reference variables object
|
||||
*/
|
||||
if (variableName in commonVars) {
|
||||
value = _.cloneDeep(commonVars[variableName]);
|
||||
}
|
||||
|
||||
if (variableName in stageVars) {
|
||||
value = _.cloneDeep(stageVars[variableName]);
|
||||
}
|
||||
|
||||
if (variableName in regionVars) {
|
||||
value = _.cloneDeep(regionVars[variableName]);
|
||||
}
|
||||
|
||||
// Populate
|
||||
if (typeof value === 'undefined') {
|
||||
const errorMessage = [
|
||||
`Variable "${variableName}" doesn't exist in serverless.env.yml.`,
|
||||
' Please add it to serverless.env.yml.',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
} else if (typeof value === 'string') {
|
||||
if (variableString.split('.').length > 1) {
|
||||
const errorMessage = [
|
||||
`Trying to access sub properties of a string variable "${variableName}".`,
|
||||
' Please make sure the variable in serverless.env.yml',
|
||||
' is an object, otherwise you cannot use the',
|
||||
' dot notation for that variable in serverless.yml',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
// for string variables, we use replaceall in case the user
|
||||
// includes the variable as a substring (ie. "hello ${name}")
|
||||
val = replaceall(variableSyntax, value, val);
|
||||
} else {
|
||||
// populate objects recursively
|
||||
/* eslint no-lonely-if: "off" */
|
||||
if (typeof value === 'object') {
|
||||
const subProperties = variableString.split('.');
|
||||
// remove first element. It's the variableName
|
||||
subProperties.splice(0, 1);
|
||||
subProperties.forEach(subProperty => {
|
||||
if (!value[subProperty]) {
|
||||
const errorMessage = [
|
||||
`Variable "${variableName}" doesn't have sub property "${subProperty}".`,
|
||||
' Please make sure the variable is',
|
||||
' the intended object in serverless.env.yml,',
|
||||
' or reference the correct sub property in serverless.yml',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
value = value[subProperty];
|
||||
});
|
||||
|
||||
if (typeof value === 'string') {
|
||||
val = replaceall(variableSyntax, value, val);
|
||||
} else {
|
||||
if (val !== variableSyntax) {
|
||||
const errorMessage = [
|
||||
'Trying to populate non string variables into',
|
||||
` a string for variable "${variableName}".`,
|
||||
' Please make sure the variable value in',
|
||||
' serverless.env.yml is a string',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
val = value;
|
||||
}
|
||||
} else if (variableString.split('.').length > 1) {
|
||||
const errorMessage = [
|
||||
`Trying to access sub properties of a non-object variable "${variableName}"`,
|
||||
' Please make sure the variable is an object in serverless.env.yml,',
|
||||
' otherwise, you cannot use the dot notation',
|
||||
' for that variable in serverless.yml',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
} else {
|
||||
if (val !== variableSyntax) {
|
||||
const errorMessage = [
|
||||
'Trying to populate non string variables',
|
||||
` into a string for variable "${variableName}".`,
|
||||
' Please make sure the variable value in serverless.env.yml is a string',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
val = value; // not string nor object
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Replace
|
||||
t.update(val);
|
||||
if (serverlessFile.defaults.stage) {
|
||||
this.defaults.stage = serverlessFile.defaults.stage;
|
||||
}
|
||||
});
|
||||
if (serverlessFile.defaults.region) {
|
||||
this.defaults.region = serverlessFile.defaults.region;
|
||||
}
|
||||
if (serverlessFile.defaults.variableSyntax) {
|
||||
this.defaults.variableSyntax = serverlessFile.defaults.variableSyntax;
|
||||
}
|
||||
}
|
||||
|
||||
// put back environment that we temporally removed earlier
|
||||
this.environment = environment;
|
||||
|
||||
// put back variable syntax if we removed it for processing
|
||||
if (this.defaults && this.defaults.variableSyntax) {
|
||||
this.defaults.variableSyntax = varTemplateSyntax;
|
||||
// Moving defaults into provider obj
|
||||
if (serverlessFile.provider.stage) {
|
||||
this.defaults.stage = serverlessFile.provider.stage;
|
||||
}
|
||||
if (serverlessFile.provider.region) {
|
||||
this.defaults.region = serverlessFile.provider.region;
|
||||
}
|
||||
if (serverlessFile.provider.variableSyntax) {
|
||||
this.defaults.variableSyntax = serverlessFile.provider.variableSyntax;
|
||||
}
|
||||
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
populate(processedOptions) {
|
||||
const that = this;
|
||||
const options = processedOptions || {};
|
||||
const variableSyntaxProperty = this.defaults.variableSyntax;
|
||||
const variableSyntax = RegExp(variableSyntaxProperty, 'g');
|
||||
const fileRefSyntax = RegExp(/^file\(([a-zA-Z0-9._\-\/]+?)\)/g);
|
||||
// const fileRefSyntax = RegExp('^file\\(([a-zA-Z0-9._\\-\\/]+?)\\)', 'g');
|
||||
|
||||
// temporally remove variable syntax from service otherwise it'll match
|
||||
this.defaults.variableSyntax = true;
|
||||
this.serverless.service.defaults.variableSyntax = true;
|
||||
|
||||
|
||||
/*
|
||||
* we can't use an arrow function in this case cause that would
|
||||
* change the lexical scoping required by the traverse module
|
||||
*/
|
||||
traverse(this).forEach(function (property) {
|
||||
const t = this;
|
||||
|
||||
if (typeof property === 'string') {
|
||||
const nestedPopulate = (updatedPropertyParam) => {
|
||||
let updatedProperty = updatedPropertyParam;
|
||||
if (typeof updatedProperty === 'string' && updatedProperty.match(variableSyntax)) {
|
||||
updatedProperty.match(variableSyntax).forEach((matchedString) => {
|
||||
const variableString = matchedString
|
||||
.replace(variableSyntax, (match, varName) => varName.trim());
|
||||
|
||||
/*
|
||||
* File Reference
|
||||
*/
|
||||
if (variableString.match(fileRefSyntax)) {
|
||||
const matchedFileRefString = variableString.match(fileRefSyntax)[0];
|
||||
const referencedFileRelativePath = matchedFileRefString
|
||||
.replace(fileRefSyntax, (match, varName) => varName.trim());
|
||||
const referencedFileFullPath = path.join(that.serverless.config.servicePath,
|
||||
referencedFileRelativePath);
|
||||
|
||||
let value = that.serverless.utils.readFileSync(referencedFileFullPath);
|
||||
if (matchedFileRefString !== variableString) {
|
||||
let deepProperties = variableString
|
||||
.replace(matchedFileRefString, '');
|
||||
if (deepProperties.substring(0, 1) !== '.') {
|
||||
const errorMessage = [
|
||||
'Invalid variable syntax when referencing',
|
||||
` file "${referencedFileRelativePath}"`,
|
||||
' Please use valid dot notation when referencing sub properties.',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
deepProperties = deepProperties.slice(1);
|
||||
const selfSubProperties = deepProperties.split('.');
|
||||
selfSubProperties.forEach(selfSubProperty => {
|
||||
if (!value[selfSubProperty]) {
|
||||
const errorMessage = [
|
||||
`file "${referencedFileRelativePath}" doesn't`,
|
||||
` have sub property "${selfSubProperty}".`,
|
||||
' Please make sure you are referencing the correct sub property',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
value = value[selfSubProperty];
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
updatedProperty = replaceall(matchedString, value, updatedProperty);
|
||||
} else {
|
||||
if (updatedProperty !== matchedString) {
|
||||
const errorMessage = [
|
||||
'Trying to populate non string value into',
|
||||
` a string when referencing file "${referencedFileRelativePath}".`,
|
||||
' Please make sure the value of the property',
|
||||
' is a string',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
updatedProperty = value;
|
||||
}
|
||||
/*
|
||||
* Env Var Reference
|
||||
*/
|
||||
} else if (variableString.split('.')[0] === 'env') {
|
||||
if (variableString.split('.').length !== 2) {
|
||||
const errorMessage = [
|
||||
'Trying to access sub properties of environment',
|
||||
' variable strings, or trying to reference all environment variable.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
const requestedEnvVar = variableString.split('.')[1];
|
||||
const propertyValue = process.env[requestedEnvVar];
|
||||
if (typeof propertyValue === 'undefined') {
|
||||
const errorMessage = [
|
||||
`Environment variable ${requestedEnvVar} is not set on your machine.`,
|
||||
' Please set this env var before referencing it as a variable.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
updatedProperty = replaceall(matchedString, propertyValue, updatedProperty);
|
||||
|
||||
/*
|
||||
* Options Reference
|
||||
*/
|
||||
} else if (variableString.split('.')[0] === 'opt') {
|
||||
if (variableString.split('.').length === 1) {
|
||||
// load all options object
|
||||
if (updatedProperty === matchedString) {
|
||||
updatedProperty = options;
|
||||
} else {
|
||||
const errorMessage = [
|
||||
'Trying to reference all options object as a substring.',
|
||||
' Please make sure the string referencing the variable',
|
||||
' Does not contain any other sub-strings,',
|
||||
' or reference a specific option string.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
} else if (variableString.split('.').length === 2) {
|
||||
// load specific option
|
||||
const requestedOption = variableString.split('.')[1];
|
||||
const propertyValue = options[requestedOption];
|
||||
if (typeof propertyValue === 'undefined') {
|
||||
const errorMessage = [
|
||||
`Option ${requestedOption} was not passed in the CLI.`,
|
||||
' Please pass this variable in the CLI to use in serverless.yml.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
updatedProperty = replaceall(matchedString, propertyValue, updatedProperty);
|
||||
} else {
|
||||
const errorMessage = [
|
||||
'Trying to reference a specific option sub properties.',
|
||||
' Each passed option can only be a string, not objects.',
|
||||
' Please make sure you only reference the option string',
|
||||
' without any other dot notation.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Self Reference
|
||||
*/
|
||||
} else if (variableString.split('.')[0] === 'self') {
|
||||
if (variableString.split('.').length === 1) {
|
||||
const errorMessage = [
|
||||
'You can\'t reference the entire "self" serverless.yml file.',
|
||||
' Please reference a sub property with ${self.subProp}',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
let value = _.cloneDeep(that);
|
||||
const selfSubProperties = variableString.split('.');
|
||||
// remove first element. It's the "self" keyword
|
||||
selfSubProperties.splice(0, 1);
|
||||
selfSubProperties.forEach(selfSubProperty => {
|
||||
if (!value[selfSubProperty]) {
|
||||
const errorMessage = [
|
||||
`serverless.yml doesn't have sub property "${selfSubProperty}".`,
|
||||
' Please make sure you are referencing the correct sub property',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
value = value[selfSubProperty];
|
||||
});
|
||||
|
||||
if (typeof value === 'string') {
|
||||
updatedProperty = replaceall(matchedString, value, updatedProperty);
|
||||
} else {
|
||||
if (updatedProperty !== matchedString) {
|
||||
const errorMessage = [
|
||||
'Trying to populate non string value into',
|
||||
' a string when referencing "self".',
|
||||
' Please make sure the value of the property',
|
||||
' is a string',
|
||||
].join('');
|
||||
throw new that.serverless.classes
|
||||
.Error(errorMessage);
|
||||
}
|
||||
updatedProperty = value;
|
||||
}
|
||||
} else {
|
||||
const errorMessage = [
|
||||
`Invalid variable reference syntax for variable ${matchedString}.`,
|
||||
' You can only reference env vars, options, & files.',
|
||||
' You can check our docs for more info.',
|
||||
].join('');
|
||||
throw new SError(errorMessage);
|
||||
}
|
||||
});
|
||||
|
||||
return nestedPopulate(updatedProperty);
|
||||
}
|
||||
return updatedProperty;
|
||||
};
|
||||
const updatedProperty = nestedPopulate(property);
|
||||
t.update(updatedProperty);
|
||||
}
|
||||
});
|
||||
|
||||
// put back variable syntax that we removed earlier
|
||||
this.defaults.variableSyntax = variableSyntaxProperty;
|
||||
this.serverless.service.defaults.variableSyntax = variableSyntaxProperty;
|
||||
return this;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
return _.merge(this, data);
|
||||
}
|
||||
@ -348,37 +390,6 @@ class Service {
|
||||
getAllEventsInFunction(functionName) {
|
||||
return Object.keys(this.getFunction(functionName).events);
|
||||
}
|
||||
|
||||
getStage(stageName) {
|
||||
if (stageName in this.environment.stages) {
|
||||
return this.environment.stages[stageName];
|
||||
}
|
||||
throw new SError(`Stage "${stageName}" doesn't exist in this service.`);
|
||||
}
|
||||
|
||||
getAllStages() {
|
||||
return Object.keys(this.environment.stages);
|
||||
}
|
||||
|
||||
getRegionInStage(stageName, regionName) {
|
||||
if (regionName in this.getStage(stageName).regions) {
|
||||
return this.getStage(stageName).regions[regionName];
|
||||
}
|
||||
throw new SError(`Region "${regionName}" doesn't exist in stage "${stageName}"`);
|
||||
}
|
||||
|
||||
getAllRegionsInStage(stageName) {
|
||||
return Object.keys(this.getStage(stageName).regions);
|
||||
}
|
||||
|
||||
getVariables(stageName, regionName) {
|
||||
if (stageName && regionName) {
|
||||
return this.getRegionInStage(stageName, regionName).vars || {};
|
||||
} else if (stageName) {
|
||||
return this.getStage(stageName).vars || {};
|
||||
}
|
||||
return this.environment.vars || {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Service;
|
||||
|
||||
@ -89,8 +89,7 @@ class SDK {
|
||||
prefix = 'AWS';
|
||||
}
|
||||
|
||||
const profile = process.env[`${prefix}_PROFILE`]
|
||||
|| this.serverless.service.getVariables(stage).profile;
|
||||
const profile = process.env[`${prefix}_PROFILE`];
|
||||
|
||||
credentials.profile = profile;
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ module.exports = {
|
||||
.Error('This command can only be run inside a service directory');
|
||||
}
|
||||
|
||||
console.log(this.serverless.service.custom)
|
||||
|
||||
this.options.stage = this.options.stage
|
||||
|| (this.serverless.service.defaults && this.serverless.service.defaults.stage)
|
||||
|| 'dev';
|
||||
@ -16,10 +18,6 @@ module.exports = {
|
||||
|| (this.serverless.service.defaults && this.serverless.service.defaults.region)
|
||||
|| 'us-east-1';
|
||||
|
||||
// validate stage / region exists in service
|
||||
this.serverless.service.getStage(this.options.stage);
|
||||
this.serverless.service.getRegionInStage(this.options.stage, this.options.region);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
@ -87,46 +87,20 @@ describe('AWS SDK', () => {
|
||||
describe('#getCredentials()', () => {
|
||||
it('should get credentials', () => {
|
||||
const serverless = new Serverless();
|
||||
serverless.service.environment = {
|
||||
vars: {
|
||||
profile: 'default',
|
||||
},
|
||||
stages: {
|
||||
dev: {
|
||||
vars: {},
|
||||
regions: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
serverless.service.environment.stages.dev.regions['us-east-1'] = {
|
||||
vars: {},
|
||||
};
|
||||
process.env.AWS_PROFILE = 'default';
|
||||
const awsSdk = new AwsSdk(serverless);
|
||||
const credentials = awsSdk.getCredentials();
|
||||
expect(credentials.profile).to.equal('default');
|
||||
delete process.env.AWS_PROFILE;
|
||||
});
|
||||
|
||||
it('should get stage credentials', () => {
|
||||
const serverless = new Serverless();
|
||||
serverless.service.environment = {
|
||||
vars: {},
|
||||
stages: {
|
||||
dev: {
|
||||
vars: {
|
||||
profile: 'default',
|
||||
},
|
||||
regions: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
serverless.service.environment.stages.dev.regions['us-east-1'] = {
|
||||
vars: {},
|
||||
};
|
||||
process.env.AWS_DEV_PROFILE = 'default';
|
||||
const awsSdk = new AwsSdk(serverless);
|
||||
const credentials = awsSdk.getCredentials('dev');
|
||||
expect(credentials.profile).to.deep.equal('default');
|
||||
delete process.env.AWS_DEV_PROFILE;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -15,43 +15,11 @@ describe('#validate()', () => {
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
awsPlugin.serverless.service.environment = {
|
||||
vars: {},
|
||||
stages: {
|
||||
dev: {
|
||||
vars: {},
|
||||
regions: {
|
||||
'us-east-1': {
|
||||
vars: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
awsPlugin.serverless.config.servicePath = true;
|
||||
|
||||
Object.assign(awsPlugin, validate);
|
||||
});
|
||||
|
||||
it('should succeed if region exists in service', () => {
|
||||
expect(() => awsPlugin.validate()).to.not.throw(Error);
|
||||
});
|
||||
|
||||
it('should throw error if region does not exist in service', () => {
|
||||
awsPlugin.options.region = 'us-west-2';
|
||||
expect(() => awsPlugin.validate()).to.throw(Error);
|
||||
});
|
||||
|
||||
it('should succeed if stage exists in service', () => {
|
||||
expect(() => awsPlugin.validate()).to.not.throw(Error);
|
||||
});
|
||||
|
||||
it('should throw error if stage does not exist in service', () => {
|
||||
awsPlugin.options.stage = 'prod';
|
||||
expect(() => awsPlugin.validate()).to.throw(Error);
|
||||
});
|
||||
|
||||
it('should succeed if inside service (servicePath defined)', () => {
|
||||
expect(() => awsPlugin.validate()).to.not.throw(Error);
|
||||
});
|
||||
@ -76,20 +44,6 @@ describe('#validate()', () => {
|
||||
stage: 'some-stage',
|
||||
};
|
||||
|
||||
awsPlugin.serverless.service.environment = {
|
||||
vars: {},
|
||||
stages: {
|
||||
'some-stage': {
|
||||
vars: {},
|
||||
regions: {
|
||||
'us-east-1': {
|
||||
vars: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return awsPlugin.validate().then(() => {
|
||||
expect(awsPlugin.options.stage).to.equal('some-stage');
|
||||
});
|
||||
@ -108,20 +62,6 @@ describe('#validate()', () => {
|
||||
region: 'some-region',
|
||||
};
|
||||
|
||||
awsPlugin.serverless.service.environment = {
|
||||
vars: {},
|
||||
stages: {
|
||||
dev: {
|
||||
vars: {},
|
||||
regions: {
|
||||
'some-region': {
|
||||
vars: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return awsPlugin.validate().then(() => {
|
||||
expect(awsPlugin.options.region).to.equal('some-region');
|
||||
});
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
# This is the Serverless Environment File
|
||||
#
|
||||
# It contains listing of your stages, and their regions
|
||||
# It also manages serverless variables at 3 levels:
|
||||
# - common variables: variables that apply to all stages/regions
|
||||
# - stage variables: variables that apply to a specific stage
|
||||
# - region variables: variables that apply to a specific region
|
||||
|
||||
vars:
|
||||
stages:
|
||||
dev:
|
||||
vars:
|
||||
regions:
|
||||
us-east-1:
|
||||
vars:
|
||||
@ -1,15 +0,0 @@
|
||||
# This is the Serverless Environment File
|
||||
#
|
||||
# It contains listing of your stages, and their regions
|
||||
# It also manages serverless variables at 3 levels:
|
||||
# - common variables: variables that apply to all stages/regions
|
||||
# - stage variables: variables that apply to a specific stage
|
||||
# - region variables: variables that apply to a specific region
|
||||
|
||||
vars:
|
||||
stages:
|
||||
dev:
|
||||
vars:
|
||||
regions:
|
||||
us-east-1:
|
||||
vars:
|
||||
@ -49,13 +49,13 @@ functions:
|
||||
handler: hello.Handler
|
||||
|
||||
# you can add any of the following events
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${bucket}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${env.BUCKET}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
|
||||
# you can add CloudFormation resource templates here
|
||||
#resources:
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
# This is the Serverless Environment File
|
||||
#
|
||||
# It contains listing of your stages and their regions
|
||||
# It also manages serverless variables at 3 levels:
|
||||
# - common variables: variables that apply to all stages/regions
|
||||
# - stage variables: variables that apply to a specific stage
|
||||
# - region variables: variables that apply to a specific region
|
||||
|
||||
vars:
|
||||
stages:
|
||||
dev:
|
||||
vars:
|
||||
regions:
|
||||
us-east-1:
|
||||
vars:
|
||||
@ -48,14 +48,14 @@ functions:
|
||||
hello:
|
||||
handler: handler.hello
|
||||
|
||||
# you can add any of the following events
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${bucket}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
# you can add any of the following events
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${env.BUCKET}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
|
||||
# you can add CloudFormation resource templates here
|
||||
#resources:
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
# This is the Serverless Environment File
|
||||
#
|
||||
# It contains listing of your stages, and their regions
|
||||
# It also manages serverless variables at 3 levels:
|
||||
# - common variables: variables that apply to all stages/regions
|
||||
# - stage variables: variables that apply to a specific stage
|
||||
# - region variables: variables that apply to a specific region
|
||||
|
||||
vars:
|
||||
stages:
|
||||
dev:
|
||||
vars:
|
||||
regions:
|
||||
us-east-1:
|
||||
vars:
|
||||
@ -49,13 +49,13 @@ functions:
|
||||
handler: handler.hello
|
||||
|
||||
# you can add any of the following events
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${bucket}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
# events:
|
||||
# - http:
|
||||
# path: users/create
|
||||
# method: get
|
||||
# - s3: ${env.BUCKET}
|
||||
# - schedule: rate(10 minutes)
|
||||
# - sns: greeter-topic
|
||||
|
||||
# you can add CloudFormation resource templates here
|
||||
#resources:
|
||||
|
||||
@ -74,8 +74,6 @@ describe('Create', () => {
|
||||
return create.create().then(() => {
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.env.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'handler.js')))
|
||||
.to.be.equal(true);
|
||||
|
||||
@ -92,8 +90,6 @@ describe('Create', () => {
|
||||
return create.create().then(() => {
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.env.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'handler.py')))
|
||||
.to.be.equal(true);
|
||||
|
||||
@ -110,8 +106,6 @@ describe('Create', () => {
|
||||
return create.create().then(() => {
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.env.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'event.json')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'pom.xml')))
|
||||
@ -142,8 +136,6 @@ describe('Create', () => {
|
||||
return create.create().then(() => {
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'serverless.env.yml')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'event.json')))
|
||||
.to.be.equal(true);
|
||||
expect(create.serverless.utils.fileExistsSync(path.join(tmpDir, 'build.gradle')))
|
||||
|
||||
@ -688,8 +688,6 @@ describe('PluginManager', () => {
|
||||
|
||||
expect(serverlessInstance.utils
|
||||
.fileExistsSync(path.join(tmpDir, 'serverless.yml'))).to.equal(true);
|
||||
expect(serverlessInstance.utils
|
||||
.fileExistsSync(path.join(tmpDir, 'serverless.env.yml'))).to.equal(true);
|
||||
expect(serverlessInstance.utils
|
||||
.fileExistsSync(path.join(tmpDir, 'handler.js'))).to.equal(true);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user