Skip to content

Commit

Permalink
feat: adapt to new Framework variables resolver
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
Drop support for old Serverless Framework variables resolver.
  • Loading branch information
medikoo committed Jul 16, 2021
1 parent 7d8c61d commit dc62243
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 234 deletions.
75 changes: 21 additions & 54 deletions lib/yamlParser.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,33 @@
'use strict';

const BbPromise = require('bluebird');
const path = require('path');
const _ = require('lodash');

module.exports = {
yamlParse() {
const servicePath = this.serverless.config.servicePath;
if (!servicePath) {
return BbPromise.resolve();
const parsedObject = this.serverless.configurationInput;

this.serverless.service.stepFunctions = {
validate: parsedObject.stepFunctions ? parsedObject.stepFunctions.validate : false,
noOutput: parsedObject.stepFunctions ? parsedObject.stepFunctions.noOutput : false,
};
this.serverless.service.stepFunctions.stateMachines = parsedObject.stepFunctions
&& parsedObject.stepFunctions.stateMachines
? parsedObject.stepFunctions.stateMachines : {};
this.serverless.service.stepFunctions.activities = parsedObject.stepFunctions
&& parsedObject.stepFunctions.activities
? parsedObject.stepFunctions.activities : [];

if (!this.serverless.pluginManager.cliOptions.stage) {
this.serverless.pluginManager.cliOptions.stage = this.options.stage
|| (this.serverless.service.provider && this.serverless.service.provider.stage)
|| 'dev';
}

const fromYamlFile = serverlessYmlPath => this.serverless.yamlParser.parse(serverlessYmlPath);

let parse = null;
const serviceFileName = this.options.config || this.serverless.config.serverless.service.serviceFilename || 'serverless.yml';
const serverlessYmlPath = path.join(servicePath, serviceFileName);

if (['.js', '.json', '.ts'].includes(path.extname(serverlessYmlPath))) {
parse = this.loadFromRequiredFile;
} else {
parse = fromYamlFile;
if (!this.serverless.pluginManager.cliOptions.region) {
this.serverless.pluginManager.cliOptions.region = this.options.region
|| (this.serverless.service.provider && this.serverless.service.provider.region)
|| 'us-east-1';
}
return parse(serverlessYmlPath)
.then(serverlessFileParam => this.serverless.variables.populateObject(serverlessFileParam)
.then((parsedObject) => {
this.serverless.service.stepFunctions = {
validate: parsedObject.stepFunctions ? parsedObject.stepFunctions.validate : false,
noOutput: parsedObject.stepFunctions ? parsedObject.stepFunctions.noOutput : false,
};
this.serverless.service.stepFunctions.stateMachines = parsedObject.stepFunctions
&& parsedObject.stepFunctions.stateMachines
? parsedObject.stepFunctions.stateMachines : {};
this.serverless.service.stepFunctions.activities = parsedObject.stepFunctions
&& parsedObject.stepFunctions.activities
? parsedObject.stepFunctions.activities : [];

if (!this.serverless.pluginManager.cliOptions.stage) {
this.serverless.pluginManager.cliOptions.stage = this.options.stage
|| (this.serverless.service.provider && this.serverless.service.provider.stage)
|| 'dev';
}

if (!this.serverless.pluginManager.cliOptions.region) {
this.serverless.pluginManager.cliOptions.region = this.options.region
|| (this.serverless.service.provider && this.serverless.service.provider.region)
|| 'us-east-1';
}

this.serverless.variables.populateService(this.serverless.pluginManager.cliOptions);
return BbPromise.resolve();
}));
},

// This function must be ignored since mocking the require system is more
// dangerous than beneficial
loadFromRequiredFile(serverlessYmlPath) {
/* istanbul ignore next */
// eslint-disable-next-line global-require, import/no-dynamic-require
const fileContents = require(serverlessYmlPath);
/* istanbul ignore next */
return BbPromise.resolve(fileContents);
},

getAllStateMachines() {
Expand Down
204 changes: 24 additions & 180 deletions lib/yamlParser.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
'use strict';

const expect = require('chai').expect;
const sinon = require('sinon');
const path = require('path');
const BbPromise = require('bluebird');
const Serverless = require('serverless/lib/Serverless');
const AwsProvider = require('serverless/lib/plugins/aws/provider');
const ServerlessStepFunctions = require('./index');
Expand All @@ -13,7 +10,19 @@ describe('#yamlParse', () => {
let serverlessStepFunctions;

beforeEach(() => {
serverless = new Serverless();
serverless = new Serverless({
configuration: {
service: 'test',
provider: 'aws',
},
serviceDir: __dirname,
configurationFilename: 'serverless.yml',
isConfigurationResolved: true,
hasResovledCommandsExternally: true,
isTelemetryReportedExternally: true,
commands: ['info'],
options: {},
});
serverless.servicePath = true;
serverless.service.service = 'step-functions';
serverless.configSchemaHandler = {
Expand All @@ -25,201 +34,36 @@ describe('#yamlParse', () => {
});

describe('#yamlParse()', () => {
let yamlParserStub;
let populateServiceStub;
let yamlObjectParserStub;
beforeEach(() => {
populateServiceStub = sinon.stub(serverlessStepFunctions.serverless.variables,
'populateService').returns(BbPromise.resolve());
yamlObjectParserStub = sinon.stub(serverlessStepFunctions.serverless.variables,
'populateObject').returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
yamlParserStub = sinon.stub(serverlessStepFunctions.serverless.yamlParser, 'parse')
.returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
serverlessStepFunctions.serverless.config.servicePath = 'servicePath';
});

afterEach(() => {
serverlessStepFunctions.serverless.yamlParser.parse.restore();
serverlessStepFunctions.serverless.variables.populateService.restore();
serverlessStepFunctions.serverless.variables.populateObject.restore();
});

it('should default to dev when stage and provider are not defined', () => {
serverlessStepFunctions.serverless.pluginManager.cliOptions.stage = null;
serverlessStepFunctions.serverless.service.provider = null;
serverlessStepFunctions.yamlParse()
.then(() => {
expect(serverless.pluginManager.cliOptions.stage).to.be.equal('dev');
});
serverlessStepFunctions.yamlParse();
expect(serverless.pluginManager.cliOptions.stage).to.be.equal('dev');
});

it('should default to us-east-1 when region and provider are not defined', () => {
serverlessStepFunctions.serverless.pluginManager.cliOptions.region = null;
serverlessStepFunctions.serverless.service.provider = null;
serverlessStepFunctions.yamlParse()
.then(() => {
expect(serverless.pluginManager.cliOptions.region).to.be.equal('us-east-1');
});
serverlessStepFunctions.yamlParse();
expect(serverless.pluginManager.cliOptions.region).to.be.equal('us-east-1');
});

it('should not default to dev when stage is defined', () => {
serverlessStepFunctions.serverless.pluginManager.cliOptions.stage = 'my-stage';
serverlessStepFunctions.yamlParse()
.then(() => {
expect(serverless.pluginManager.cliOptions.stage).to.be.equal('my-stage');
});
serverlessStepFunctions.yamlParse();
expect(serverless.pluginManager.cliOptions.stage).to.be.equal('my-stage');
});

it('should not default to us-east-1 when region is defined', () => {
serverlessStepFunctions.serverless.pluginManager.cliOptions.region = 'my-region';
serverlessStepFunctions.yamlParse()
.then(() => {
expect(serverless.pluginManager.cliOptions.region).to.be.equal('my-region');
});
});

it('should throw error if servicePath is not given', () => {
serverlessStepFunctions.serverless.config.servicePath = null;
serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledOnce).to.be.equal(false);
expect(yamlObjectParserStub.calledOnce).to.be.equal(false);
expect(populateServiceStub.calledOnce).to.be.equal(false);
expect(serverless.service.stepFunctions).to.be.undefined; // eslint-disable-line
});
});

it('should create corresponding when stepfunctions param are given', () => {
serverlessStepFunctions.serverless.variables.populateObject.restore();
yamlObjectParserStub = sinon.stub(serverlessStepFunctions.serverless.variables,
'populateObject').returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledOnce).to.be.equal(true);
expect(yamlObjectParserStub.calledOnce).to.be.equal(true);
expect(populateServiceStub.calledOnce).to.be.equal(true);
expect(serverless.service.stepFunctions.stateMachines).to.be.equal('stepFunctions');
expect(serverless.service.stepFunctions.activities).to.be.equal('my-activity');
});
});

it('should be able to load from a js file', () => {
serverless.config.serverless.service.serviceFilename = 'serverless.js';
const requireFileStub = sinon.stub(serverlessStepFunctions, 'loadFromRequiredFile')
.returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
serverlessStepFunctions.yamlParse()
.then(() => {
expect(requireFileStub.calledOnce).to.be.equal(true);
expect(serverless.service.stepFunctions.stateMachines).to.be.equal('stepFunctions');
expect(serverless.service.stepFunctions.activities).to.be.equal('my-activity');
});
});

it('should be able to load from a json file', () => {
serverless.config.serverless.service.serviceFilename = 'serverless.json';
const requireFileStub = sinon.stub(serverlessStepFunctions, 'loadFromRequiredFile')
.returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
serverlessStepFunctions.yamlParse()
.then(() => {
expect(requireFileStub.calledOnce).to.be.equal(true);
expect(serverless.service.stepFunctions.stateMachines).to.be.equal('stepFunctions');
expect(serverless.service.stepFunctions.activities).to.be.equal('my-activity');
});
});

it('should be able to load from a ts file', () => {
serverless.config.serverless.service.serviceFilename = 'serverless.ts';
const requireFileStub = sinon.stub(serverlessStepFunctions, 'loadFromRequiredFile')
.returns(BbPromise.resolve({
stepFunctions: {
stateMachines: 'stepFunctions',
activities: 'my-activity',
},
}));
serverlessStepFunctions.yamlParse()
.then(() => {
expect(requireFileStub.calledOnce).to.be.equal(true);
expect(serverless.service.stepFunctions.stateMachines).to.be.equal('stepFunctions');
expect(serverless.service.stepFunctions.activities).to.be.equal('my-activity');
});
serverlessStepFunctions.yamlParse();
expect(serverless.pluginManager.cliOptions.region).to.be.equal('my-region');
});

it('should create empty object when stepfunctions param are not given', () => {
serverlessStepFunctions.serverless.yamlParser.parse.restore();
serverlessStepFunctions.serverless.variables.populateObject.restore();
yamlParserStub = sinon.stub(serverlessStepFunctions.serverless.yamlParser, 'parse')
.returns(BbPromise.resolve({
stepFunctions: {},
}));
yamlObjectParserStub = sinon.stub(serverless.variables,
'populateObject').returns(BbPromise.resolve({
stepFunctions: {},
}));
serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledOnce).to.be.equal(true);
expect(yamlObjectParserStub.calledOnce).to.be.equal(true);
expect(populateServiceStub.calledOnce).to.be.equal(true);
expect(serverless.service.stepFunctions.stateMachines).to.be.deep.equal({});
expect(serverless.service.stepFunctions.activities).to.be.deep.equal([]);
});
});

it('should default to serverless.yml if serviceFileName (--config option) is not passed', () => {
const servicePath = serverlessStepFunctions.serverless.config.servicePath;
serverlessStepFunctions.serverless.config.serverless.service.serviceFilename = undefined;

serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledWith(`${servicePath}/serverless.yml`)).to.be.equal(true);
});
});

it('should read serviceFileName if passed as --config option', () => {
const servicePath = serverlessStepFunctions.serverless.config.servicePath;
const fileName = 'other_config.yml';
serverlessStepFunctions.serverless.config.serverless.service.serviceFilename = fileName;

serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledWith(`${servicePath}/${fileName}`)).to.be.equal(true);
});
});

it('should read relative serviceFileName path if passed as --config option', () => {
const servicePath = serverlessStepFunctions.serverless.config.servicePath;
const relativeFilename = './some_folder/other_config.yml';
serverlessStepFunctions.options.config = relativeFilename;
const serviceFilePath = path.normalize(`${servicePath}/${relativeFilename}`);
serverlessStepFunctions.yamlParse()
.then(() => {
expect(yamlParserStub.calledWith(serviceFilePath)).to.be.equal(true);
});
serverlessStepFunctions.yamlParse();
expect(serverless.service.stepFunctions.stateMachines).to.be.deep.equal({});
expect(serverless.service.stepFunctions.activities).to.be.deep.equal([]);
});
});

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
"chalk": "^1.1.1",
"lodash": "^4.17.11"
},
"peerDependencies": {
"serverless": "^2.32.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
Expand Down

0 comments on commit dc62243

Please sign in to comment.