Merge pull request #3604 from serverless/files-with-vars

Fixed bug when referencing variables from other variable object values
This commit is contained in:
Eslam λ Hefnawy 2017-05-12 13:52:59 +07:00 committed by GitHub
commit d768f2d52d
2 changed files with 93 additions and 10 deletions

View File

@ -37,24 +37,29 @@ class Variables {
this.service.provider.variableSyntax = true;
this.serverless.service.serverless = null;
return this.populateObject(this.service).then(() => {
this.service.provider.variableSyntax = variableSyntaxProperty;
this.serverless.service.serverless = this.serverless;
return BbPromise.resolve(this.service);
});
}
populateObject(objectToPopulate) {
const populateAll = [];
_.deepMapValues(this.service, (property, propertyPath) => {
_.deepMapValues(objectToPopulate, (property, propertyPath) => {
if (typeof property === 'string') {
const populateSingleProperty = new Promise((resolve) => this
.populateProperty(property, true).then(newProperty => {
_.set(this.service, propertyPath, newProperty);
_.set(objectToPopulate, propertyPath, newProperty);
return resolve();
}));
populateAll.push(populateSingleProperty);
}
});
return BbPromise.all(populateAll).then(() => {
this.service.provider.variableSyntax = variableSyntaxProperty;
this.serverless.service.serverless = this.serverless;
return BbPromise.resolve(this.service);
});
return BbPromise.all(populateAll).then(() => objectToPopulate);
}
populateProperty(propertyParam, populateInPlace) {
@ -78,7 +83,12 @@ class Variables {
.then(valueToPopulate => resolve(valueToPopulate));
}
return this.getValueFromSource(variableString)
.then(valueToPopulate => resolve(valueToPopulate));
.then(valueToPopulate => {
if (typeof valueToPopulate === 'object') {
return resolve(this.populateObject(valueToPopulate));
}
return resolve(valueToPopulate);
});
});
singleValueToPopulate.then(valueToPopulate => {
@ -252,6 +262,7 @@ class Variables {
return this.getDeepValue(deepProperties, valueToPopulate);
}
}
return BbPromise.resolve(valueToPopulate);
}

View File

@ -43,11 +43,11 @@ describe('Variables', () => {
const serverless = new Serverless();
const populatePropertyStub = sinon
.stub(serverless.variables, 'populateProperty').resolves();
.stub(serverless.variables, 'populateObject').resolves();
return serverless.variables.populateService().then(() => {
expect(populatePropertyStub.called).to.equal(true);
serverless.variables.populateProperty.restore();
serverless.variables.populateObject.restore();
});
});
@ -77,6 +77,40 @@ describe('Variables', () => {
});
});
describe('#populateObject()', () => {
it('should call populateProperty method', () => {
const serverless = new Serverless();
const object = {
stage: '${opt:stage}',
};
const populatePropertyStub = sinon
.stub(serverless.variables, 'populateProperty').resolves('prod');
return serverless.variables.populateObject(object).then(() => {
expect(populatePropertyStub.called).to.equal(true);
serverless.variables.populateProperty.restore();
});
});
it('should populate object and return it', () => {
const serverless = new Serverless();
const object = {
stage: '${opt:stage}',
};
const expectedPopulatedObject = {
stage: 'prod',
};
sinon.stub(serverless.variables, 'populateProperty').resolves('prod');
return serverless.variables.populateObject(object).then(populatedObject => {
expect(populatedObject).to.deep.equal(expectedPopulatedObject);
serverless.variables.populateProperty.restore();
});
});
});
describe('#populateProperty()', () => {
it('should call overwrite if overwrite syntax provided', () => {
const serverless = new Serverless();
@ -123,6 +157,44 @@ describe('Variables', () => {
});
});
it('should call populateObject if variable value is an object', () => {
const serverless = new Serverless();
serverless.variables.options = {
stage: 'prod',
};
const property = '${opt:stage}';
const variableValue = {
stage: '${opt:stage}',
};
const variableValuePopulated = {
stage: 'prod',
};
serverless.variables.loadVariableSyntax();
const populateObjectStub = sinon
.stub(serverless.variables, 'populateObject')
.resolves(variableValuePopulated);
const getValueFromSourceStub = sinon
.stub(serverless.variables, 'getValueFromSource')
.resolves(variableValue);
const populateVariableStub = sinon
.stub(serverless.variables, 'populateVariable')
.resolves(variableValuePopulated);
return serverless.variables.populateProperty(property).then(newProperty => {
expect(populateObjectStub.called).to.equal(true);
expect(getValueFromSourceStub.called).to.equal(true);
expect(populateVariableStub.called).to.equal(true);
expect(newProperty).to.deep.equal(variableValuePopulated);
serverless.variables.populateObject.restore();
serverless.variables.getValueFromSource.restore();
serverless.variables.populateVariable.restore();
return Promise.resolve();
});
});
it('should run recursively if nested variables provided', () => {
const serverless = new Serverless();
const property = 'my stage is ${env:${opt.name}}';