From 0b88cf232bdfd52bb0df2f9cb5473140d655b84f Mon Sep 17 00:00:00 2001 From: ac360 Date: Sat, 16 Jan 2016 10:54:14 -0800 Subject: [PATCH] ServerlessState: Enhance get methods to use more than serverless paths to query serverless assets --- lib/ServerlessState.js | 355 +++++++++++---------- lib/actions/FunctionDeploy.js | 40 +-- tests/all.js | 4 +- tests/tests/classes/ServerlessStateTest.js | 42 +++ 4 files changed, 249 insertions(+), 192 deletions(-) diff --git a/lib/ServerlessState.js b/lib/ServerlessState.js index 44a353244..db50788b6 100644 --- a/lib/ServerlessState.js +++ b/lib/ServerlessState.js @@ -98,10 +98,10 @@ class ServerlessState { }; return this.project.getPopulated(options) - .then(function(data) { - populatedData.project = data; - return populatedData; - }); + .then(function(data) { + populatedData.project = data; + return populatedData; + }); } /** @@ -134,8 +134,8 @@ class ServerlessState { if (options.populate) { return this.getPopulated(options) .then(function(populatedData) { - return SUtils.getResources(populatedData.project); - }); + return SUtils.getResources(populatedData.project); + }); } else { return Promise.resolve(SUtils.getResources(this.project.get())); } @@ -161,248 +161,261 @@ class ServerlessState { /** * Get Components - * - returns an array of this state's project component instances + * - Returns an array of this state's project component instances + * - Options: component * - options.paths is an array of serverless paths like this: ['component', 'component'] */ getComponents(options) { - let _this = this, - pathsObj = {}, - components = []; - - options = options || {}; - - // If paths, create temp obj for easy referencing - if (options.paths && options.paths.length) { - options.paths.forEach(function (path) { - let component = path.split('/')[0]; - if (!pathsObj[component]) pathsObj[component] = {}; - }); - } + let _this = this, + allComponents = [], + foundComponents = []; + // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { - - let component = _this.project.components[Object.keys(_this.project.components)[i]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name, false)) continue; - - components.push(component); + allComponents.push(_this.project.components[Object.keys(_this.project.components)[i]]); } - if (options.paths && !components.length) { - throw new SError('No components found in the paths you provided'); + // Return if no options specified + if (!options) return allComponents; + + // If options specified, loop through and find the ones specified + for (let i = 0; i < allComponents.length; i++) { + let component = allComponents[i]; + + if (options.component) { + if (component._config.component == options.component) { + foundComponents.push(component); + } + continue; + } + if (options.paths && options.paths.indexOf(component._config.sPath) !== -1) { + foundComponents.push(component); + continue; + } } - return components; + if (!foundComponents.length) { + throw new SError('No components found via the options you provided'); + } + + return foundComponents; } /** * Get Modules - * - returns an array of this state's modules instances + * - Returns an array of this state's modules instances + * - Options: component, module * - options.paths is an array of serverless paths like this: ['component/moduleOne', 'component/moduleTwo'] */ getModules(options) { - let _this = this, - pathsObj = {}, - modules = []; - - options = options || {}; - - // If paths, create temp obj for easy referencing - if (options.paths && options.paths.length) { - options.paths.forEach(function (path) { - - let component = path.split('/')[0]; - let module = path.split('/')[1]; - - if (!pathsObj[component]) pathsObj[component] = {}; - if (!pathsObj[component][module]) pathsObj[component][module] = {}; - }); - } + let _this = this, + allModules = [], + foundModules = []; + // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { - let component = _this.project.components[Object.keys(_this.project.components)[i]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name, false)) continue; - + if (!component.modules) continue; for (let j = 0; j < Object.keys(component.modules).length; j++) { - - let module = component.modules[Object.keys(component.modules)[j]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name + '.' + module.name, false)) continue; - - modules.push(module); + allModules.push(component.modules[Object.keys(component.modules)[j]]); } } - if (options.paths && !modules.length) { - throw new SError('No modules found in the paths you provided'); + // Return if no options specified + if (!options) return allModules; + + // If options specified, loop through and find the ones specified + for (let i = 0; i < allModules.length; i++) { + let module = allModules[i]; + + if (options.component && options.module) { + if (module._config.component == options.component && module._config.module == options.module) { + foundModules.push(module); + } + continue; + } + if (options.component) { + if (module._config.component == options.component) { + foundModules.push(module); + } + continue; + } + if (options.paths && options.paths.indexOf(module._config.sPath) !== -1) { + foundModules.push(module); + continue; + } } - return modules; + if (!foundModules.length) { + throw new SError('No modules found via the options you provided'); + } + + return foundModules; } /** * Get Functions - * - returns an array of this state's function instances + * - Returns an array of this state's function instances + * - Options: paths, component, module, function * - options.paths is an array of Serverless paths like this: ['component/moduleOne/functionOne', 'component/moduleOne/functionOne'] */ getFunctions(options) { - let _this = this, - functions = [], - pathsObj = {}; - - options = options || {}; - - // If paths, create temp obj for easy referencing - if (options.paths && options.paths.length) { - options.paths.forEach(function (path) { - - // Validate Path - SUtils.validateSPath(_this._S.config.projectPath, path, 'function'); - - var parsed = SUtils.parseSPath(path); - - if (!pathsObj[parsed.component]) pathsObj[parsed.component] = {}; - if (!pathsObj[parsed.component][parsed.module]) pathsObj[parsed.component][parsed.module] = {}; - pathsObj[parsed.component][parsed.module][parsed.function] = true; - }); - } + let _this = this, + allFunctions = [], + foundFunctions = []; + // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { - let component = _this.project.components[Object.keys(_this.project.components)[i]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name, false)) continue; - if (!component.modules) continue; - for (let j = 0; j < Object.keys(component.modules).length; j++) { - let module = component.modules[Object.keys(component.modules)[j]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name + '.' + module.name, false)) continue; - if (!module.functions) continue; - for (let k = 0; k < Object.keys(module.functions).length; k++) { - - let func = module.functions[Object.keys(module.functions)[k]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name + '.' + module.name + '.' + func.name, false)) continue; - - functions.push(func); + allFunctions.push(module.functions[Object.keys(module.functions)[k]]); } } } - if (options.paths && !functions.length) { - throw new SError('No functions found in the paths you provided'); + // Return if no options specified + if (!options) return allFunctions; + + // If options specified, loop through and find the ones specified + for (let i = 0; i < allFunctions.length; i++) { + let func = allFunctions[i]; + + if (options.component && options.module && options.function) { + if (func._config.component == options.component && func._config.module == options.module && func.name == options.function) { + foundFunctions.push(func); + } + continue; + } + if (options.component && options.module) { + if (func._config.component == options.component && func._config.module == options.module) { + foundFunctions.push(func); + } + continue; + } + if (options.component) { + if (func._config.component == options.component) { + foundFunctions.push(func); + } + continue; + } + if (options.paths && options.paths.indexOf(func._config.sPath) !== -1) { + foundFunctions.push(func); + continue; + } } - return functions; + if (!foundFunctions.length) { + throw new SError('No functions found via the options you provided'); + } + + return foundFunctions; } /** * Get Endpoints + * - Returns an array of this state's function instances + * - Options: paths, component, module, function, endpointPath, endpointMethod + * - options.paths is an array of Serverless paths like this: ['component/moduleOne/functionOne@moduleOne/functionOne~GET'] */ getEndpoints(options) { - let _this = this, - endpoints = [], - pathsObj = {}; - - options = options || {}; - - // Get Project Data - let project = options.populate ? _this.getPopulated(options) : _this.get(); - - // If paths, create temp obj for easy referencing - if (options.paths && options.paths.length) { - options.paths.forEach(function (path) { - SUtils.validateSPath(_this._S.projectPath, path, 'endpoint'); - - let parsed = SUtils.parseSPath(path); - - if (!pathsObj[parsed.component]) pathsObj[parsed.component] = {}; - if (!pathsObj[parsed.component][parsed.module]) pathsObj[parsed.component][parsed.module] = {}; - if (!pathsObj[parsed.component][parsed.module][parsed.function]) pathsObj[parsed.component][parsed.module][parsed.function] = {}; - if (!pathsObj[parsed.component][parsed.module][parsed.function][parsed.urlPath]) pathsObj[parsed.component][parsed.module][parsed.function][parsed.urlPath] = {}; - if (!pathsObj[parsed.component][parsed.module][parsed.function][parsed.urlPath][parsed.urlMethod]) pathsObj[parsed.component][parsed.module][parsed.function][parsed.urlPath][parsed.urlMethod] = true; - }); - } + let _this = this, + allEndpoints = [], + foundEndpoints = []; + // Get all functions for (let i = 0; i < Object.keys(_this.project.components).length; i++) { - let component = _this.project.components[Object.keys(_this.project.components)[i]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name, false)) continue; - if (!component.modules) continue; - for (let j = 0; j < Object.keys(component.modules).length; j++) { - let module = component.modules[Object.keys(component.modules)[j]]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name + '.' + module.name, false)) continue; - if (!module.functions) continue; - for (let k = 0; k < Object.keys(module.functions).length; k++) { - let func = module.functions[Object.keys(module.functions)[k]]; - for (let l = 0; l < func.endpoints.length; l++) { - - let endpoint = func.endpoints[l]; - - // If paths, and this component is not included, skip - if (options.paths && - options.paths.length && - !_.get(pathsObj, component.name + '.' + module.name + '.' + func.name + '.' + endpoint.path + '.' + endpoint.method, false)) continue; - - endpoints.push(endpoint); + allEndpoints.push(func.endpoints[l]); } } } } - if (options.paths && !endpoints.length) { - throw new SError('No endpoints found in the paths you provided'); + // Return if no options specified + if (!options) return allEndpoints; + + // If options specified, loop through functions and find the ones specified + for (let i = 0; i < allEndpoints.length; i++) { + let endpoint = allEndpoints[i]; + + if (options.component && options.module && options.function && options.endpointPath && options.endpointMethod) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.path == options.endpointPath && endpoint.method == options.endpointMethod) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.module && options.function && options.endpointPath && !options.endpointMethod) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.path == options.endpointPath) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.module && options.function && options.endpointMethod && !options.endpointPath) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.method == options.endpointMethod) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.module && options.function && !options.endpointPath && !options.endpointMethod) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.module && options.endpointMethod && !options.function && !options.endpointPath) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint.method == options.endpointMethod) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.module && !options.function && !options.endpointPath && !options.endpointMethod) { + if (endpoint._config.component == options.component && endpoint._config.module == options.module) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && options.endpointMethod && !options.module && !options.function && !options.endpointPath) { + if (endpoint._config.component == options.component && endpoint.method == options.endpointMethod) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.component && !options.module && !options.function && !options.endpointPath && !options.endpointMethod) { + if (endpoint._config.component == options.component) { + foundEndpoints.push(endpoint); + } + continue; + } + if (options.paths && options.paths.indexOf(endpoint._config.sPath) !== -1) { + foundEndpoints.push(endpoint); + continue; + } } - return endpoints; + if (!foundEndpoints.length) { + throw new SError('No endpoints found via the options you provided'); + } + + return foundEndpoints; } /** diff --git a/lib/actions/FunctionDeploy.js b/lib/actions/FunctionDeploy.js index 7d86ff6a7..42f308e6f 100644 --- a/lib/actions/FunctionDeploy.js +++ b/lib/actions/FunctionDeploy.js @@ -167,26 +167,27 @@ module.exports = function(SPlugin, serverlessPath) { _this.evt.options.aliasFunction = _this.evt.options.aliasFunction ? _this.evt.options.aliasFunction : null; // Instantiate Classes - _this.project = new _this.S.classes.Project(_this.S); - _this.meta = new _this.S.classes.Meta(_this.S); + _this.project = new _this.S.state.getProject(); + _this.meta = new _this.S.state.getMeta(); // Set Deploy Regions - _this.regions = _this.evt.options.region ? [_this.evt.options.region] : Object.keys(_this.meta.data.stages[_this.evt.options.stage].regions); + _this.regions = _this.evt.options.region ? [_this.evt.options.region] : _this.S.state.getRegions(_this.evt.options.stage); if (!_this.evt.options.paths.length) { - let CWD = process.cwd(), + let CWD = process.cwd(), isComponent = SUtils.fileExistsSync(path.join(CWD, 's-component.json')), - isModule = SUtils.fileExistsSync(path.join(CWD, 's-module.json')), - isFunction = SUtils.fileExistsSync(path.join(CWD, 's-function.json')); + isModule = SUtils.fileExistsSync(path.join(CWD, 's-module.json')), + isFunction = SUtils.fileExistsSync(path.join(CWD, 's-function.json')); + + if (isComponent) { - if (isComponent){ let componentName = SUtils.readAndParseJsonSync(path.join(CWD, '..', 's-component.json')).name, - component = new _this.S.classes.Component(_this.S, {component: componentName}); + component = _this.S.state.getComponents({ paths: [componentName] }); - Object.keys(component.data.modules).forEach(function(moduleName) { + Object.keys(component.modules).forEach(function(moduleName) { - Object.keys(component.data.modules[moduleName].functions).forEach(function(functionName) { + Object.keys(component.modules[moduleName].functions).forEach(function(functionName) { _this.evt.options.paths.push(componentName + path.sep + moduleName + path.sep + functionName); @@ -194,11 +195,12 @@ module.exports = function(SPlugin, serverlessPath) { }); } else if (isModule) { + let moduleName = SUtils.readAndParseJsonSync(path.join(CWD, 's-module.json')).name, - componentName = SUtils.readAndParseJsonSync(path.join(CWD, '..', 's-component.json')).name, + componentName = SUtils.readAndParseJsonSync(path.join(CWD, '..', 's-component.json')).name, component = new _this.S.classes.Component(_this.S, {component: componentName}); - Object.keys(component.data.modules[moduleName].functions).forEach(function(functionName) { + Object.keys(component.modules[moduleName].functions).forEach(function(functionName) { _this.evt.options.paths.push(componentName + path.sep + moduleName + path.sep + functionName); @@ -279,7 +281,7 @@ module.exports = function(SPlugin, serverlessPath) { return BbPromise.try(function() { // Nodejs - if (func.data.runtime = 'nodejs') { + if (func.runtime = 'nodejs') { let newEvt = { options: { @@ -287,7 +289,7 @@ module.exports = function(SPlugin, serverlessPath) { region: region, component: func.config.component, module: func.config.module, - function: func.data.name + function: func.name } }; @@ -303,8 +305,8 @@ module.exports = function(SPlugin, serverlessPath) { component: result.options.component, module: result.options.module, function: result.options.function, - pathDist: result.data.pathDist, - pathsPackaged: result.data.pathsPackaged + pathDist: result.pathDist, + pathsPackaged: result.pathsPackaged } }; @@ -321,8 +323,8 @@ module.exports = function(SPlugin, serverlessPath) { _this.deployed[region].push({ component: func.config.component, module: func.config.module, - function: func.data.name, - Arn: result.data.lambdaAliasArn + function: func.name, + Arn: result.lambdaAliasArn }); return cb(); @@ -336,7 +338,7 @@ module.exports = function(SPlugin, serverlessPath) { _this.failed[region].push({ component: func.config.component, module: func.config.module, - function: func.data.name, + function: func.name, message: e.message, stack: e.stack }); diff --git a/tests/all.js b/tests/all.js index f11767812..6bd1194a0 100644 --- a/tests/all.js +++ b/tests/all.js @@ -15,7 +15,7 @@ describe('All Tests', function() { //require('./tests/classes/ServerlessModuleTest'); //require('./tests/classes/ServerlessComponentTest'); //require('./tests/classes/ServerlessProjectTest'); - //require('./tests/classes/ServerlessStateTest'); + require('./tests/classes/ServerlessStateTest'); //require('./tests/actions/TestPluginCustom'); //require('./tests/actions/TestDefaultActionHook'); //require('./tests/actions/ProjectCreate'); @@ -27,7 +27,7 @@ describe('All Tests', function() { //require('./tests/actions/EnvList'); //require('./tests/actions/EnvGet'); //require('./tests/actions/EnvSetUnset'); - require('./tests/actions/ResourcesDeploy'); + //require('./tests/actions/ResourcesDeploy'); //require('./tests/actions/FunctionRun'); //require('./tests/actions/FunctionDeploy'); //require('./tests/actions/EndpointDeploy'); diff --git a/tests/tests/classes/ServerlessStateTest.js b/tests/tests/classes/ServerlessStateTest.js index c341e9ef8..87564594d 100644 --- a/tests/tests/classes/ServerlessStateTest.js +++ b/tests/tests/classes/ServerlessStateTest.js @@ -147,6 +147,12 @@ describe('Test Serverless State Class', function() { done(); }); + it('Get components by component', function(done) { + let components = instance.getComponents({ component: 'nodejscomponent' }); + assert.equal(true, components[0].name === 'nodejscomponent'); + done(); + }); + it('Get modules w/o paths', function(done) { let modules = instance.getModules(); assert.equal(true, modules[0].name === 'module1'); @@ -159,6 +165,18 @@ describe('Test Serverless State Class', function() { done(); }); + it('Get modules by component and module', function(done) { + let modules = instance.getModules({ component: 'nodejscomponent', module: 'module1' }); + assert.equal(true, modules[0].name === 'module1'); + done(); + }); + + it('Get modules by component', function(done) { + let modules = instance.getModules({ component: 'nodejscomponent' }); + assert.equal(true, modules.length === 1); + done(); + }); + it('Get functions w/o paths', function(done) { let functions = instance.getFunctions(); assert.equal(true, functions.length === 3); @@ -171,6 +189,12 @@ describe('Test Serverless State Class', function() { done(); }); + it('Get functions by component, module and function', function(done) { + let functions = instance.getFunctions({ component: 'nodejscomponent', module: 'module1', function: 'function1' }); + assert.equal(true, functions.length === 1); + done(); + }); + it('Get endpoints w/o paths', function(done) { let endpoints = instance.getEndpoints(); assert.equal(true, endpoints.length === 4); @@ -183,6 +207,24 @@ describe('Test Serverless State Class', function() { done(); }); + it('Get endpoints by component, module, function, path and method', function(done) { + let endpoints = instance.getEndpoints({ component: 'nodejscomponent', module: 'module1', function: 'function3', endpointPath: 'module1/function3', endpointMethod: 'POST' }); + assert.equal(true, endpoints.length === 1); + done(); + }); + + it('Get endpoints by component, module and function', function(done) { + let endpoints = instance.getEndpoints({ component: 'nodejscomponent', module: 'module1', function: 'function1' }); + assert.equal(true, endpoints.length === 1); + done(); + }); + + it('Get endpoints by component and method', function(done) { + let endpoints = instance.getEndpoints({ component: 'nodejscomponent', endpointMethod: 'GET' }); + assert.equal(true, endpoints.length === 3); + done(); + }); + it('Validate stage exists', function(done) { assert.equal(true, instance.validateStageExists(config.stage)); assert.equal(false, instance.validateStageExists('invalid'));