diff --git a/lib/actions/CodePackageLambdaNodejs.js b/lib/actions/CodePackageLambdaNodejs.js
index abb36d992..ba28c6436 100644
--- a/lib/actions/CodePackageLambdaNodejs.js
+++ b/lib/actions/CodePackageLambdaNodejs.js
@@ -104,36 +104,24 @@ class Packager {
_validateAndPrepare(evt) {
- let _this = this;
+ // Skip Function if it does not have a lambda
+ if (!evt.function.cloudFormation ||
+ !evt.function.cloudFormation.lambda ||
+ !evt.function.cloudFormation.lambda.Function) {
+ throw new SError(evt.function.name + 'does not have a lambda property');
+ }
- // Get Function JSON
- return SUtils.getFunctions(
- path.join(_this.S._projectRootPath, 'back', 'modules'),
- [evt.function])
- .then(function(functionJsons) {
+ // Validate lambda attributes
+ let lambda = evt.function.cloudFormation.lambda;
+ if (!lambda.Function.Type
+ || !lambda.Function
+ || !lambda.Function.Properties
+ || !lambda.Function.Properties.Runtime
+ || !lambda.Function.Properties.Handler) {
+ throw new SError('Missing required lambda attributes');
+ }
- // Attach to evt
- evt.function = functionJsons[0];
-
- // Skip Function if it does not have a lambda
- if (!evt.function.cloudFormation ||
- !evt.function.cloudFormation.lambda ||
- !evt.function.cloudFormation.lambda.Function) {
- throw new SError(evt.function.name + 'does not have a lambda property');
- }
-
- // Validate lambda attributes
- let lambda = evt.function.cloudFormation.lambda;
- if (!lambda.Function.Type
- || !lambda.Function
- || !lambda.Function.Properties
- || !lambda.Function.Properties.Runtime
- || !lambda.Function.Properties.Handler) {
- throw new SError('Missing required lambda attributes');
- }
-
- return evt;
- });
+ return BbPromise.resolve(evt);
}
/**
@@ -250,8 +238,7 @@ class Packager {
_optimize(evt) {
- let _this = this,
- lambda = evt.function.cloudFormation.lambda;
+ let _this = this;
if (!evt.function.package.optimize
|| !evt.function.package.optimize.builder) {
@@ -368,6 +355,7 @@ class Packager {
return new BbPromise(function(resolve, reject) {
b.bundle(function(err, bundledBuf) {
+
if (err) {
console.error('Error running browserify bundle');
reject(err);
diff --git a/lib/actions/EndpointPrepareApiGateway.js b/lib/actions/EndpointPrepareApiGateway.js
index ac6bda531..ce8ab4799 100644
--- a/lib/actions/EndpointPrepareApiGateway.js
+++ b/lib/actions/EndpointPrepareApiGateway.js
@@ -69,53 +69,41 @@ class EndpointPackageApiGateway extends SPlugin {
_validateAndPrepare(evt) {
- let _this = this;
+ // If endpoint properties are missing, skip
+ if (!evt.function.cloudFormation ||
+ !evt.function.cloudFormation.apiGateway ||
+ !evt.function.cloudFormation.apiGateway.Endpoint) {
+ throw new SError(evt.function.name + ' does not have required apiGateway properties');
+ }
- // Get Function JSON and validate Endpoint(s)
- return SUtils.getFunctions(
- _this.S._projectRootPath,
- [evt.function])
- .then(function(functionJsons) {
+ evt.endpoints = evt.function.cloudFormation.apiGateway.Endpoint;
- // Attach to evt
- evt.function = functionJsons[0];
+ // Endpoint property can be an array to support multiple endpoints per function
+ // Convert endpointJson to array, if it's not already
+ if (!Array.isArray(evt.endpoints)) evt.endpoints = [evt.endpoints];
- // If endpoint properties are missing, skip
- if (!evt.function.cloudFormation ||
- !evt.function.cloudFormation.apiGateway ||
- !evt.function.cloudFormation.apiGateway.Endpoint) {
- throw new SError(evt.function.name + ' does not have required apiGateway properties');
- }
+ // Validate all evt.endpoints
+ for (let i = 0; i < evt.endpoints.length;i++) {
- evt.endpoints = evt.function.cloudFormation.apiGateway.Endpoint;
+ let e = evt.endpoints[i];
- // Endpoint property can be an array to support multiple endpoints per function
- // Convert endpointJson to array, if it's not already
- if (!Array.isArray(evt.endpoints)) evt.endpoints = [evt.endpoints];
+ // Validate and sanitize endpoint attributes
+ if (!e.Type
+ || !e.Path
+ || !e.Method
+ || !e.AuthorizationType
+ || typeof e.ApiKeyRequired === 'undefined') {
+ return BbPromise.reject(new SError('Missing one of many required endpoint attributes: Type, Path, Method, AuthorizationType, ApiKeyRequired'));
+ }
- // Validate all evt.endpoints
- for (let i = 0; i < evt.endpoints.length;i++) {
+ // Sanitize path
+ if (e.Path.charAt(0) === '/') e.Path = e.Path.substring(1);
- let e = evt.endpoints[i];
+ // Sanitize method
+ e.Method = e.Method.toUpperCase();
+ }
- // Validate and sanitize endpoint attributes
- if (!e.Type
- || !e.Path
- || !e.Method
- || !e.AuthorizationType
- || typeof e.ApiKeyRequired === 'undefined') {
- return BbPromise.reject(new SError('Missing one of many required endpoint attributes: Type, Path, Method, AuthorizationType, ApiKeyRequired'));
- }
-
- // Sanitize path
- if (e.Path.charAt(0) === '/') e.Path = e.Path.substring(1);
-
- // Sanitize method
- e.Method = e.Method.toUpperCase();
- }
-
- return evt;
- });
+ return BbPromise.resolve(evt);
}
/**
diff --git a/lib/actions/FunctionDeploy.js b/lib/actions/FunctionDeploy.js
index 311d2b2d6..4d3618094 100644
--- a/lib/actions/FunctionDeploy.js
+++ b/lib/actions/FunctionDeploy.js
@@ -101,15 +101,37 @@ class FunctionDeploy extends SPlugin {
functionDeploy(event) {
- let _this = this;
- let evt = {};
- evt.type = event.type ? event.type : null;
- evt.stage = event.stage ? event.stage : null;
- evt.regions = event.region ? [event.region] : [];
- evt.paths = event.paths ? event.paths : [];
- evt.all = event.all ? event.all : null;
- evt.aliasEndpoint = event.aliasEndpoint ? event.aliasEndpoint : null;
- evt.aliasFunction = event.aliasFunction ? event.aliasFunction : null;
+ let _this = this,
+ evt = {};
+
+ // If CLI, parse options
+ if (_this.S.cli) {
+
+ // Options
+ evt = this.S.cli.options;
+
+ // Option - Non-interactive
+ if (_this.S.cli.options.nonInteractive) _this.S._interactive = false
+
+ // Type - Should be first in array
+ if (_this.S.cli.params.length) evt.type = _this.S.cli.params[0];
+
+ // Function paths - They should be all other array items
+ _this.S.cli.params.splice(0,1);
+ evt.paths = _this.S.cli.params;
+ }
+
+ // If NO-CLI, add options
+ if (event) evt = event;
+
+ // Add defaults
+ evt.type = evt.type ? evt.type : 'code';
+ evt.stage = evt.stage ? evt.stage : null;
+ evt.regions = evt.region ? [evt.region] : [];
+ evt.paths = evt.paths ? evt.paths : [];
+ evt.all = evt.all ? true : false;
+ evt.aliasEndpoint = evt.aliasEndpoint ? evt.aliasEndpoint : null;
+ evt.aliasFunction = evt.aliasFunction ? evt.aliasFunction : null;
evt.functions = [];
evt.deployed = {};
evt.failed = {};
@@ -118,6 +140,7 @@ class FunctionDeploy extends SPlugin {
return _this._validateAndPrepare(evt)
.bind(_this)
.then(_this._promptStage)
+ .then(_this._prepareRegions)
.then(_this._processDeployment)
.then(function(evt) {
return evt;
@@ -133,27 +156,18 @@ class FunctionDeploy extends SPlugin {
let _this = this;
- // If CLI, parse command line input and validate
- if (_this.S.cli) {
-
- // Add Options
- evt = _this.S.cli.options;
-
- // Add type. Should be first in array
- evt.type = _this.S.cli.params[0];
-
- // Add function paths. Should be all other array items
- _this.S.cli.params.splice(0,1);
- evt.paths = _this.S.cli.params;
- }
-
- // If NO-CLI, validate
+ // If NO-CLI, validate paths
if (!_this.S.cli) {
- // Check if paths or all is not used
+ // Validate Paths
if (!evt.paths.length && !evt.all) {
throw new SError(`One or multiple paths are required`);
}
+
+ // Validate Stage
+ if (!evt.stage) {
+ throw new SError(`Stage is required`);
+ }
}
// Validate type
@@ -164,46 +178,38 @@ class FunctionDeploy extends SPlugin {
throw new SError(`Invalid type. Must be "code", "endpoint", or "both" `);
}
- // Validate stage
- if (!evt.stage) {
- throw new SError(`Stage is required`);
- }
+ // Get Functions From Paths
- // If no region specified, deploy to all regions in stage
- if (!evt.regions.length) {
- evt.regions = _this.S._projectJson.stages[evt.stage].map(rCfg => {
- return rCfg.region;
- });
- }
-
- SUtils.sDebug('Queued regions: ' + evt.regions);
-
- // If CLI and paths are missing, get paths from CWD, and return
if (_this.S.cli) {
- if (!evt.paths || !evt.paths.length) {
- // If CLI and no paths, get full paths from CWD
- return SUtils.getFunctions(
- evt.all ? _this.S._projectRootPath : process.cwd(),
- null)
- .then(function(functions) {
+ // If CLI & paths, get functions
+ // If CLI & no paths, get full paths from CWD
- if (!functions.length) throw new SError(`No functions found`);
+ return SUtils.getFunctions(
+ evt.all ? _this.S._projectRootPath : process.cwd(),
+ evt.paths && evt.paths.length ? evt.paths : null)
+ .then(function(functions) {
+ if (!functions.length) throw new SError(`No functions found`);
+ evt.functions = functions;
+ // Delete Paths
+ if (evt.paths) delete evt.paths;
+ return evt;
+ });
+
+ } else {
+
+ // If NO-CLI, resolve full paths from submitted paths
+ return SUtils.getFunctions(
+ _this.S._projectRootPath,
+ evt.all ? null : evt.paths)
+ .then(function(functions) {
+ evt.functions = functions;
+ // Delete Paths
+ if (evt.paths) delete evt.paths;
+ return evt;
+ });
- evt.functions = functions;
- return evt;
- });
- }
}
-
- // Otherwise, resolve full paths
- return SUtils.getFunctions(
- _this.S._projectRootPath,
- evt.all ? null : evt.paths)
- .then(function(functions) {
- evt.functions = functions;
- return evt;
- });
}
/**
@@ -212,19 +218,17 @@ class FunctionDeploy extends SPlugin {
_promptStage(evt) {
- let _this = this,
- stages = [];
+ let _this = this;
- if (!evt.stage) {
+ // If user provided stage, skip prompt
+ if (evt.stage) return BbPromise.resolve(evt);
- stages = Object.keys(_this.S._projectJson.stage);
+ // Collect project stages
+ let stages = Object.keys(_this.S._projectJson.stages);
- // If project only has 1 stage, skip prompt
- if (stages.length === 1) evt.stage = stages[0];
-
- } else {
-
- // If user provided stage, skip prompt
+ // If project only has 1 stage, skip prompt
+ if (stages.length === 1) {
+ evt.stage = stages[0];
return BbPromise.resolve(evt);
}
@@ -246,6 +250,22 @@ class FunctionDeploy extends SPlugin {
});
}
+ /**
+ * Prepare Regions
+ */
+
+ _prepareRegions(evt) {
+
+ // If no region specified, deploy to all regions in stage
+ if (!evt.regions.length) {
+ evt.regions = this.S._projectJson.stages[evt.stage].map(rCfg => {
+ return rCfg.region;
+ });
+ }
+
+ return evt;
+ }
+
/**
* Process Deployment
*/
@@ -254,6 +274,9 @@ class FunctionDeploy extends SPlugin {
let _this = this;
+ // Status
+ SCli.log('Deploying in "' + evt.stage + '" to the following regions: ' + evt.regions);
+
return BbPromise.try(function() {
return evt.regions;
})
@@ -270,9 +293,11 @@ class FunctionDeploy extends SPlugin {
endpoints: [],
};
- //Deploy Function Code in each region
+ // Deploy Function Code in each region
if (['code', 'both'].indexOf(evt.type) > -1) {
+ // Status
+ SCli.log('"' + evt.stage + ' - ' + region + '": Deploying function code...');
return _this._deployCodeByRegion(evt, region);
}
})
@@ -281,11 +306,11 @@ class FunctionDeploy extends SPlugin {
})
.each(function(region) {
- /**
- * Deploy Function Endpoints in each region
- */
+ // Deploy Function Endpoints in each region
if (['endpoint', 'both'].indexOf(evt.type) > -1) {
+ // Status
+ SCli.log('"' + evt.stage + ' - ' + region + '" - Deploying function endpoints...');
return _this._deployEndpointsByRegion(evt, region)
}
})
@@ -318,7 +343,7 @@ class FunctionDeploy extends SPlugin {
_this.S._projectJson,
evt.stage,
region),
- function: func.path,
+ function: func,
};
// Process sub-Actions
@@ -368,7 +393,7 @@ class FunctionDeploy extends SPlugin {
_this.S._projectJson,
evt.stage,
region),
- function: func.path,
+ function: func,
aliasEndpoint: evt.aliasEndpoint,
};
diff --git a/lib/actions/ModuleCreate.js b/lib/actions/ModuleCreate.js
index 9e4d1e9c3..9a4319c1f 100644
--- a/lib/actions/ModuleCreate.js
+++ b/lib/actions/ModuleCreate.js
@@ -125,8 +125,7 @@ usage: serverless module create`,
.then(_this._createModuleSkeleton)
.then(_this._installFunctionDependencies)
.then(function() {
- SCli.log('Successfully created ' + _this.evt.module + '/' + _this.evt.function);
-
+ SCli.log('Successfully created new serverless module "' + _this.evt.module + '" with its first function "' + _this.evt.function + '"');
// Return Event
return _this.evt;
});
@@ -243,29 +242,21 @@ usage: serverless module create`,
// Save Paths
_this.evt.modulePath = path.join(this.S._projectRootPath, 'back', 'modules', _this.evt.module);
- _this.evt.functionPath = path.join(_this.evt.modulePath, _this.evt.function);
+ _this.evt.functionPath = path.join(_this.evt.modulePath, _this.evt.function);
// Prep package.json
packageJsonTemplate.name = _this.evt.module;
- packageJsonTemplate.description = 'A serverless module';
- packageJsonTemplate.dependencies = {};
-
+ packageJsonTemplate.description = 'Dependencies for a Serverless Module written in Node.js';
+
// Write base module structure
writeDeferred.push(
fs.mkdirSync(_this.evt.modulePath),
fs.mkdirSync(path.join(_this.evt.modulePath, 'lib')),
fs.mkdirSync(path.join(_this.evt.modulePath, 'package')),
fs.mkdirSync(path.join(_this.evt.modulePath, 'package', 'functions')),
- fs.mkdirSync(path.join(_this.evt.modulePath, 'node_modules')),
SUtils.writeFile(path.join(_this.evt.modulePath, 'package.json'), JSON.stringify(packageJsonTemplate, null, 2)),
SUtils.writeFile(path.join(_this.evt.modulePath, 's-module.json'), JSON.stringify(moduleJsonTemplate, null, 2))
);
-
- // Copy NPM Dependencies
- wrench.copyDirSyncRecursive(
- path.join(_this._templatesDir, 'nodejs', 'dotenv'),
- path.join(_this.evt.modulePath, 'node_modules', 'dotenv')
- );
// Write module/function structure
writeDeferred.push(
@@ -295,6 +286,7 @@ usage: serverless module create`,
*/
_generateFunctionJson() {
+
let _this = this;
let functionJsonTemplate = SUtils.readAndParseJsonSync(path.join(this._templatesDir, 's-function.json'));
@@ -330,7 +322,9 @@ usage: serverless module create`,
};
_installFunctionDependencies() {
- return SUtils.npmInstall(this.evt.modulePath);
+ SCli.log('Installing "serverless-helpers" for this module via NPM...');
+ SUtils.npmInstall(this.evt.modulePath);
+ return BbPromise.resolve();
}
}
diff --git a/lib/serverless.js b/lib/serverless.js
index 59a953d1e..532928d25 100644
--- a/lib/serverless.js
+++ b/lib/serverless.js
@@ -124,7 +124,11 @@ class Serverless {
command(argv) {
- SUtils.sDebug('command argv', argv);
+ // Set Debug to True
+ if (argv && argv.d) process.env.DEBUG = true;
+
+ SUtils.sDebug('Command raw argv: ', argv);
+
// Handle version command
if (argv._[0] === 'version') {
console.log(this._version);
@@ -134,7 +138,7 @@ class Serverless {
let cmdContext = argv._[0],
cmdContextAction = argv._[1];
- this.cli = {}; //options and args that the command was called with on the CLI so plugins can leverage
+ this.cli = {}; // Options and args that the command was called with on the CLI so plugins can leverage
if (argv._.length === 0 || argv._[0] === 'help' || argv._[0] === 'h') {
if (!this.commands[cmdContext]) {
diff --git a/lib/templates/nodejs/dotenv/README.md b/lib/templates/nodejs/dotenv/README.md
deleted file mode 100644
index de324261a..000000000
--- a/lib/templates/nodejs/dotenv/README.md
+++ /dev/null
@@ -1,198 +0,0 @@
-# dotenv
-
-
-
-Dotenv loads environment variables from `.env` into `ENV` (process.env).
-
-[](https://travis-ci.org/motdotla/dotenv)
-[](https://www.npmjs.com/package/dotenv)
-[](https://github.com/feross/standard)
-
-> "Storing [configuration in the environment](http://www.12factor.net/config)
-> is one of the tenets of a [twelve-factor app](http://www.12factor.net/).
-> Anything that is likely to change between deployment environments–such as
-> resource handles for databases or credentials for external services–should be
-> extracted from the code into environment variables.
->
-> But it is not always practical to set environment variables on development
-> machines or continuous integration servers where multiple projects are run.
-> Dotenv loads variables from a `.env` file into ENV when the environment is
-> bootstrapped."
->
-> [Brandon Keepers' Dotenv in Ruby](https://github.com/bkeepers/dotenv)
-
-## Install
-
-```bash
-npm install dotenv --save
-```
-
-## Usage
-
-As early as possible in your application, require and load dotenv.
-
-```javascript
-require('dotenv').load();
-```
-
-Create a `.env` file in the root directory of your project. Add
-environment-specific variables on new lines in the form of `NAME=VALUE`.
-For example:
-
-```
-DB_HOST=localhost
-DB_USER=root
-DB_PASS=s1mpl3
-```
-
-That's it.
-
-`process.env` now has the keys and values you defined in your `.env` file.
-
-```javascript
-db.connect({
- host: process.env.DB_HOST,
- username: process.env.DB_USER,
- password: process.env.DB_PASS
-});
-```
-
-### Preload
-
-If you are using iojs-v1.6.0 or later, you can use the `--require` (`-r`) command line option to preload dotenv. By doing this, you do not need to require and load dotenv in your application code.
-
-
-```bash
-$ node -r dotenv/config your_script.js
-```
-
-The configuration options below are supported as command line arguments in the format `dotenv_config_