New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw an error if plugin is executed outside of a serverless directory #5636

Merged
merged 7 commits into from Jan 31, 2019
Copy path View file
@@ -57,6 +57,9 @@ class Serverless {
// get an array of commands and options that should be processed // get an array of commands and options that should be processed
this.processedInput = this.cli.processInput(); this.processedInput = this.cli.processInput();


// make the serverless config file available to the PluginManager
this.pluginManager.loadConfigFile();

// set the options and commands which were processed by the CLI // set the options and commands which were processed by the CLI
this.pluginManager.setCliOptions(this.processedInput.options); this.pluginManager.setCliOptions(this.processedInput.options);
this.pluginManager.setCliCommands(this.processedInput.commands); this.pluginManager.setCliCommands(this.processedInput.commands);
Copy path View file
@@ -29,6 +29,7 @@ class TerminateHookChain extends Error {
class PluginManager { class PluginManager {
constructor(serverless) { constructor(serverless) {
this.serverless = serverless; this.serverless = serverless;
this.serverlessConfigFile = null;


this.cliOptions = {}; this.cliOptions = {};
this.cliCommands = []; this.cliCommands = [];
@@ -40,6 +41,12 @@ class PluginManager {
this.deprecatedEvents = {}; this.deprecatedEvents = {};
} }


loadConfigFile() {
getServerlessConfigFile(this.serverless.config.servicePath).then((serverlessConfigFile) => {
this.serverlessConfigFile = serverlessConfigFile;
});
}

setCliOptions(options) { setCliOptions(options) {
this.cliOptions = options; this.cliOptions = options;
} }
@@ -436,19 +443,12 @@ class PluginManager {
*/ */
validateServerlessConfigDependency(command) { validateServerlessConfigDependency(command) {
if ('configDependent' in command && command.configDependent) { if ('configDependent' in command && command.configDependent) {
return getServerlessConfigFile().then((serverlessConfigFile) => { if (!this.serverlessConfigFile) {
if (!serverlessConfigFile) { throw new this.serverless.classes.Error(
const error = new this.serverless.classes.Error( 'This command can only be run in a Serverless service directory'
'This command can only be run in a Serverless service directory' );
); }
return BbPromise.reject(error);
}

return BbPromise.resolve();
});
} }

return BbPromise.resolve();
} }


validateOptions(command) { validateOptions(command) {
@@ -497,15 +497,12 @@ class PluginManager {
.concat(Object.keys(command.commands)); .concat(Object.keys(command.commands));
}); });


return getServerlessConfigFile(this.serverless.config.servicePath) const serverlessConfigFileHash = crypto.createHash('sha256')
.then((serverlessConfigFile) => { .update(JSON.stringify(this.serverlessConfigFile)).digest('hex');
const serverlessConfigFileHash = crypto.createHash('sha256') cacheFile.validationHash = serverlessConfigFileHash;
.update(JSON.stringify(serverlessConfigFile)).digest('hex'); const cacheFilePath = getCacheFilePath(this.serverless.config.servicePath);
cacheFile.validationHash = serverlessConfigFileHash;
const cacheFilePath = getCacheFilePath(this.serverless.config.servicePath); return writeFile(cacheFilePath, cacheFile);
return writeFile(cacheFilePath, cacheFile);
})
.catch((e) => null); // eslint-disable-line
} }


convertShortcutsIntoOptions(command) { convertShortcutsIntoOptions(command) {
@@ -1170,33 +1170,28 @@ describe('PluginManager', () => {


describe('#validateServerlessConfigDependency()', () => { describe('#validateServerlessConfigDependency()', () => {
let serverlessInstance; let serverlessInstance;
let getServerlessConfigFileStub;
let pluginManagerInstance; let pluginManagerInstance;


beforeEach(() => { beforeEach(() => {
getServerlessConfigFileStub = sinon.stub();
PluginManager = proxyquire('./PluginManager.js', {
'../utils/getServerlessConfigFile': getServerlessConfigFileStub,
});
serverlessInstance = new Serverless(); serverlessInstance = new Serverless();
serverlessInstance.config.servicePath = 'my-service'; serverlessInstance.config.servicePath = 'my-service';
pluginManagerInstance = new PluginManager(serverlessInstance); pluginManagerInstance = new PluginManager(serverlessInstance);
}); });


it('should continue loading if the configDependent property is absent', () => { it('should continue loading if the configDependent property is absent', () => {
getServerlessConfigFileStub.resolves({ service: 'my-service' }); pluginManagerInstance.serverlessConfigFile = null;


pluginManagerInstance.commands = { pluginManagerInstance.commands = {
foo: {}, foo: {},
}; };


const foo = pluginManagerInstance.commands.foo; const foo = pluginManagerInstance.commands.foo;


return expect(pluginManagerInstance.validateServerlessConfigDependency(foo)).to.be.fulfilled; expect(pluginManagerInstance.validateServerlessConfigDependency(foo)).to.be.undefined;
}); });


it('should load if the configDependent property has a false value', () => { it('should load if the configDependent property is false and config is null', () => {
getServerlessConfigFileStub.resolves(''); pluginManagerInstance.serverlessConfigFile = null;


pluginManagerInstance.commands = { pluginManagerInstance.commands = {
foo: { foo: {
@@ -1206,11 +1201,11 @@ describe('PluginManager', () => {


const foo = pluginManagerInstance.commands.foo; const foo = pluginManagerInstance.commands.foo;


return expect(pluginManagerInstance.validateServerlessConfigDependency(foo)).to.be.fillfilled; expect(pluginManagerInstance.validateServerlessConfigDependency(foo)).to.be.undefined;
}); });


it('should load if the configDependent property has a true value, and config is found', () => { it('should throw an error if configDependent is true and no config is found', () => {
getServerlessConfigFileStub.resolves({ service: 'my-service' }); pluginManagerInstance.serverlessConfigFile = null;


pluginManagerInstance.commands = { pluginManagerInstance.commands = {
foo: { foo: {
@@ -1220,15 +1215,11 @@ describe('PluginManager', () => {


const foo = pluginManagerInstance.commands.foo; const foo = pluginManagerInstance.commands.foo;


return expect( expect(() => { pluginManager.validateServerlessConfigDependency(foo); }).to.throw(Error);
pluginManagerInstance.validateServerlessConfigDependency(foo)
).to.be.fulfilled.then(() => {
expect(getServerlessConfigFileStub).to.have.been.calledOnce;
});
}); });


it('should error if configDependent has a true value and no config is found', () => { it('should throw an error if configDependent is true and config is an empty string', () => {
getServerlessConfigFileStub.resolves(''); pluginManagerInstance.serverlessConfigFile = '';


pluginManagerInstance.commands = { pluginManagerInstance.commands = {
foo: { foo: {
@@ -1238,11 +1229,23 @@ describe('PluginManager', () => {


const foo = pluginManagerInstance.commands.foo; const foo = pluginManagerInstance.commands.foo;


return expect( expect(() => { pluginManager.validateServerlessConfigDependency(foo); }).to.throw(Error);
pluginManagerInstance.validateServerlessConfigDependency(foo) });
).to.be.rejected.then(() => {
expect(getServerlessConfigFileStub).to.have.been.calledOnce; it('should load if the configDependent property is true and config exists', () => {
}); pluginManagerInstance.serverlessConfigFile = {
servicePath: 'foo',
};

pluginManagerInstance.commands = {
foo: {
configDependent: true,
},
};

const foo = pluginManagerInstance.commands.foo;

expect(pluginManagerInstance.validateServerlessConfigDependency(foo)).to.be.undefined;
}); });
}); });


ProTip! Use n and p to navigate between commits in a pull request.