Skip to content

Commit

Permalink
feat(Variables): Support boolean and integer fallbacks (#7632)
Browse files Browse the repository at this point in the history
Additionally improved string related regex
  • Loading branch information
fredericbarthelet authored May 4, 2020
1 parent a1fde35 commit f22bffc
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
2 changes: 2 additions & 0 deletions docs/providers/aws/guide/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,8 @@ provider:
custom:
myStage: ${opt:stage, self:provider.stage}
myRegion: ${opt:region, 'us-west-1'}
myCfnRole: ${opt:role, false}
myLambdaMemory: ${opt:memory, 1024}
functions:
hello:
Expand Down
23 changes: 19 additions & 4 deletions lib/classes/Variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ class Variables {
this.envRefSyntax = RegExp(/^env:/g);
this.optRefSyntax = RegExp(/^opt:/g);
this.selfRefSyntax = RegExp(/^self:/g);
this.stringRefSyntax = RegExp(/(?:('|").*?\1)/g);
this.stringRefSyntax = RegExp(/(?:^('|").*?\1$)/g);
this.boolRefSyntax = RegExp(/(?:^(true|false)$)/g);
this.intRefSyntax = RegExp(/(?:^\d+$)/g);
this.s3RefSyntax = RegExp(/^(?:\${)?s3:(.+?)\/(.+)$/);
this.cfRefSyntax = RegExp(/^(?:\${)?cf(?:\.([a-zA-Z0-9-]+))?:(.+?)\.(.+)$/);
this.ssmRefSyntax = RegExp(
Expand All @@ -80,6 +82,8 @@ class Variables {
serviceName: 'S3',
},
{ regex: this.stringRefSyntax, resolver: this.getValueFromString.bind(this) },
{ regex: this.boolRefSyntax, resolver: this.getValueFromBool.bind(this) },
{ regex: this.intRefSyntax, resolver: this.getValueFromInt.bind(this) },
{
regex: this.ssmRefSyntax,
resolver: this.getValueFromSsm.bind(this),
Expand Down Expand Up @@ -476,15 +480,16 @@ class Variables {
* @param string The string to split by comma.
*/
splitByComma(string) {
const quotedWordSyntax = RegExp(/(?:('|").*?\1)/g);
const input = string.trim();
const stringMatches = [];
let match = this.stringRefSyntax.exec(input);
let match = quotedWordSyntax.exec(input);
while (match) {
stringMatches.push({
start: match.index,
end: this.stringRefSyntax.lastIndex,
end: quotedWordSyntax.lastIndex,
});
match = this.stringRefSyntax.exec(input);
match = quotedWordSyntax.exec(input);
}
const commaReplacements = [];
const contained = (
Expand Down Expand Up @@ -621,6 +626,16 @@ class Variables {
return BbPromise.resolve(valueToPopulate);
}

getValueFromBool(variableString) {
const valueToPopulate = variableString === 'true';
return BbPromise.resolve(valueToPopulate);
}

getValueFromInt(variableString) {
const valueToPopulate = parseInt(variableString, 10);
return BbPromise.resolve(valueToPopulate);
}

getValueFromOptions(variableString) {
const requestedOption = variableString.split(':')[1];
let valueToPopulate;
Expand Down
54 changes: 51 additions & 3 deletions lib/classes/Variables.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,54 @@ module.exports = {
.should.eventually.eql('my stage is prod');
});

it('should not allow partially double-quoted string', () => {
const property = '${opt:stage, prefix"prod"suffix}';
serverless.variables.options = {};
const warnIfNotFoundSpy = sinon.spy(serverless.variables, 'warnIfNotFound');
return serverless.variables
.populateProperty(property)
.should.become(undefined)
.then(() => {
expect(warnIfNotFoundSpy.callCount).to.equal(1);
})
.finally(() => {
warnIfNotFoundSpy.restore();
});
});

it('should allow a boolean with value true if overwrite syntax provided', () => {
const property = '${opt:stage, true}';
serverless.variables.options = {};
return serverless.variables.populateProperty(property).should.eventually.eql(true);
});

it('should allow a boolean with value false if overwrite syntax provided', () => {
const property = '${opt:stage, false}';
serverless.variables.options = {};
return serverless.variables.populateProperty(property).should.eventually.eql(false);
});

it('should not match a boolean with value containing word true or false if overwrite syntax provided', () => {
const property = '${opt:stage, foofalsebar}';
serverless.variables.options = {};
const warnIfNotFoundSpy = sinon.spy(serverless.variables, 'warnIfNotFound');
return serverless.variables
.populateProperty(property)
.should.become(undefined)
.then(() => {
expect(warnIfNotFoundSpy.callCount).to.equal(1);
})
.finally(() => {
warnIfNotFoundSpy.restore();
});
});

it('should allow an integer if overwrite syntax provided', () => {
const property = '${opt:quantity, 123}';
serverless.variables.options = {};
return serverless.variables.populateProperty(property).should.eventually.eql(123);
});

it('should call getValueFromSource if no overwrite syntax provided', () => {
// eslint-disable-next-line no-template-curly-in-string
const property = 'my stage is ${opt:stage}';
Expand Down Expand Up @@ -1520,7 +1568,7 @@ module.exports = {
.stub(serverless.variables.variableResolvers[6], 'resolver')
.resolves('variableValue');
getValueFromSsmStub = sinon
.stub(serverless.variables.variableResolvers[8], 'resolver')
.stub(serverless.variables.variableResolvers[10], 'resolver')
.resolves('variableValue');
});

Expand All @@ -1532,7 +1580,7 @@ module.exports = {
serverless.variables.variableResolvers[4].resolver.restore();
serverless.variables.variableResolvers[5].resolver.restore();
serverless.variables.variableResolvers[6].resolver.restore();
serverless.variables.variableResolvers[8].resolver.restore();
serverless.variables.variableResolvers[10].resolver.restore();
});

it('should call getValueFromSls if referencing sls var', () =>
Expand Down Expand Up @@ -1630,7 +1678,7 @@ module.exports = {
variableString: 's3:test-bucket/path/to/ke',
},
{
functionIndex: 8,
functionIndex: 10,
function: 'getValueFromSsm',
variableString: 'ssm:/test/path/to/param',
},
Expand Down

0 comments on commit f22bffc

Please sign in to comment.