diff --git a/bin/serverless b/bin/serverless index 8a3d357de16..1cb1c1f07ed 100755 --- a/bin/serverless +++ b/bin/serverless @@ -5,14 +5,9 @@ // Note: TestsPlugin is only used for tests const TestsPlugin = require('../lib/plugins/tests/tests'); -let SUtils = require('../lib/classes/Utils'); -SUtils = new SUtils(); - const Serverless = require('../lib/Serverless'); const serverless = new Serverless({ - // TODO: update config accordingly - // servicePath: SUtils.findServicePath(process.cwd()), interactive: typeof process.env.CI === 'undefined', }); @@ -21,4 +16,4 @@ if (process.argv.indexOf('--serverless-integration-test') > -1) { serverless.pluginManager.addPlugin(TestsPlugin); } -serverless.run(); +serverless.init().then(() => serverless.run()); diff --git a/lib/Serverless.js b/lib/Serverless.js index 7e20ba18e82..b67667834d5 100644 --- a/lib/Serverless.js +++ b/lib/Serverless.js @@ -13,17 +13,20 @@ const Version = require('./../package.json').version; class Serverless { constructor(config) { - let configObj = config; - configObj = configObj || {}; + let configObject = config; + configObject = configObject || {}; this.version = Version; - this.config = new Config(this, config); this.yamlParser = new YamlParser(this); this.pluginManager = new PluginManager(this); this.utils = new Utils(this); this.service = new Service(this); - this.cli = new CLI(this, configObj.interactive); + + // use the servicePath from the options or try to find it in the CWD + configObject.servicePath = configObject.servicePath || this.utils.findServicePath(); + + this.config = new Config(this, configObject); this.classes = {}; this.classes.CLI = CLI; @@ -32,19 +35,29 @@ class Serverless { this.classes.Utils = Utils; this.classes.Service = Service; this.classes.Error = SError; + } - this.pluginManager.loadAllPlugins(); + init() { + return this.service.load() + .then(() => { + this.pluginManager.loadAllPlugins(); - this.cli = new CLI(this, configObj.interactive, - this.pluginManager.getPlugins()); + this.cli = new CLI( + this, + this.config.interactive, + this.pluginManager.getPlugins() + ); - this.inputToBeProcessed = this.cli.processInput(); + this.inputToBeProcessed = this.cli.processInput(); + }); } run() { if (this.inputToBeProcessed.commands.length) { - this.pluginManager.run(this.inputToBeProcessed.commands, - this.inputToBeProcessed.options); + this.pluginManager.run( + this.inputToBeProcessed.commands, + this.inputToBeProcessed.options + ); } } diff --git a/lib/classes/Service.js b/lib/classes/Service.js index cfa92a08bc6..24b4afc7a2f 100644 --- a/lib/classes/Service.js +++ b/lib/classes/Service.js @@ -29,8 +29,10 @@ class Service { const options = opts || {}; const servicePath = that.serverless.config.servicePath; + // skip if the service path is not found + // because the user might want to create a new service if (!servicePath) { - throw new Error('ServicePath is not configured.'); + return BbPromise.resolve(); } return that.serverless.yamlParser diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js index 9b688192bf0..d0d631ce47b 100644 --- a/lib/classes/Utils.js +++ b/lib/classes/Utils.js @@ -86,6 +86,38 @@ class Utils { return Math.random().toString(36).substr(2, length); } + findServicePath() { + const that = this; + + // Helper function + const isServiceDir = (dir) => { + // TODO: add support for serverless.yml + const yamlName = 'serverless.yaml'; + const yamlFilePath = path.join(dir, yamlName); + + return that.fileExistsSync(yamlFilePath); + }; + + // Check up to 10 parent levels + let previous = '.'; + let servicePath = null; + let i = 10; + + while (i >= 0) { + const fullPath = path.resolve(process.cwd(), previous); + + if (isServiceDir(fullPath)) { + servicePath = fullPath; + break; + } + + previous = path.join(previous, '..'); + i--; + } + + return servicePath; + } + } module.exports = Utils; diff --git a/lib/plugins/awsResourcesDeploy/tests/awsResourcesDeploy.js b/lib/plugins/awsResourcesDeploy/tests/awsResourcesDeploy.js index ebbb978aad4..c45dc430397 100644 --- a/lib/plugins/awsResourcesDeploy/tests/awsResourcesDeploy.js +++ b/lib/plugins/awsResourcesDeploy/tests/awsResourcesDeploy.js @@ -15,6 +15,7 @@ describe('AwsResourcesDeploy', () => { before(() => { awsResourcesDeploy = new AwsResourcesDeploy(serverless); + awsResourcesDeploy.serverless.init(); }); describe('#constructor()', () => { diff --git a/lib/plugins/create/tests/create.js b/lib/plugins/create/tests/create.js index ec9f05012b4..8b35e4220a6 100644 --- a/lib/plugins/create/tests/create.js +++ b/lib/plugins/create/tests/create.js @@ -6,13 +6,15 @@ const path = require('path'); const os = require('os'); const Create = require('../create'); const Serverless = require('../../../Serverless'); -const S = new Serverless(); describe('Create', () => { let create; before(() => { - create = new Create(S); + const serverless = new Serverless(); + serverless.init(); + + create = new Create(serverless); }); describe('#constructor()', () => { diff --git a/package.json b/package.json index 006fdbd6f7f..e306a202b1a 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "mocha": "^2.2.5", "mocha-lcov-reporter": "^1.2.0", "node-uuid": "^1.4.2", - "rimraf": "^2.4.3" + "rimraf": "^2.4.3", + "sinon": "^1.17.4" }, "dependencies": { "async": "^1.5.2", @@ -72,7 +73,6 @@ "replaceall": "^0.1.6", "shelljs": "^0.6.0", "shortid": "^2.2.2", - "traverse": "^0.6.6", - "sinon": "^1.17.4" + "traverse": "^0.6.6" } } diff --git a/tests/classes/Service.js b/tests/classes/Service.js index e8cfbd0035d..f89d9bd2fae 100644 --- a/tests/classes/Service.js +++ b/tests/classes/Service.js @@ -114,10 +114,11 @@ describe('Service', () => { serviceInstance = new Service(serverless); }); - it('should throw error if servicePath not configured', () => { + it('should resolve if no servicePath is found', (done) => { const serverless = new Serverless(); - const invalidService = new Service(serverless); - expect(() => invalidService.load()).to.throw(Error); + const noService = new Service(serverless); + + return noService.load().then(() => done()); }); /* diff --git a/tests/classes/Utils.js b/tests/classes/Utils.js index 395ad3a775c..07c134aab8e 100644 --- a/tests/classes/Utils.js +++ b/tests/classes/Utils.js @@ -109,5 +109,39 @@ describe('Utils', () => { }); }); }); + + describe('#findServicePath()', () => { + const testDir = process.cwd(); + + it('should detect if the CWD is a service directory', () => { + const tmpDirPath = path.join(os.tmpdir(), (new Date).getTime().toString()); + const tmpFilePath = path.join(tmpDirPath, 'serverless.yaml'); + + serverless.utils.writeFileSync(tmpFilePath, 'foo'); + process.chdir(tmpDirPath); + + const servicePath = serverless.utils.findServicePath(); + + expect(servicePath).to.not.equal(null); + }); + + it('should detect if the CWD is not a service directory', () => { + // just use the root of the tmpdir because findServicePath will + // also check parent directories (and may find matching tmp dirs + // from old tests) + const tmpDirPath = os.tmpdir(); + process.chdir(tmpDirPath); + + const servicePath = serverless.utils.findServicePath(); + + expect(servicePath).to.equal(null); + }); + + afterEach(() => { + // always switch back to the test directory + // so that we have a clean state + process.chdir(testDir); + }); + }); });