Repository: serverless/serverless (JavaScript)
Date: 2017-06-18 01:53:33+00:00
Task type: Feature

Issue:
Allow to provide a default value for plugin options
I believe it would be useful to allow a default value for plugin options.

``` js
options: {
  mode: {
    // eslint-disable-next-line max-len
    usage: 'Specifies the mode: "local", "remote", "both"',
    shortcut: 'm',
    default: 'remote'
  },
},
```

This has two benefits:
- a default is not hidden in code
- the help command can provide this information on the help command & hints



Issue discussion:

Solution patch:
diff --git a/docs/providers/aws/guide/plugins.md b/docs/providers/aws/guide/plugins.md
index ce15147aeee..bf02dd37373 100644
--- a/docs/providers/aws/guide/plugins.md
+++ b/docs/providers/aws/guide/plugins.md
@@ -195,7 +195,7 @@ Option Shortcuts are passed in with a single dash (`-`) like this: `serverless f
 
 The `options` object will be passed in as the second parameter to the constructor of your plugin.
 
-In it, you can optionally add a `shortcut` property, as well as a `required` property.  The Framework will return an error if a `required` Option is not included.
+In it, you can optionally add a `shortcut` property, as well as a `required` property.  The Framework will return an error if a `required` Option is not included. You can also set a `default` property if your option is not required.
 
 **Note:** At this time, the Serverless Framework does not use parameters.
 
@@ -217,6 +217,11 @@ class Deploy {
             usage: 'Specify the function you want to deploy (e.g. "--function myFunction")',
             shortcut: 'f',
             required: true
+          },
+          stage: {
+            usage: 'Specify the stage you want to deploy to. (e.g. "--stage prod")',
+            shortcut: 's',
+            default: 'dev'
           }
         }
       },
diff --git a/lib/classes/PluginManager.js b/lib/classes/PluginManager.js
index 53c96615c8f..cd89f4f0e49 100644
--- a/lib/classes/PluginManager.js
+++ b/lib/classes/PluginManager.js
@@ -241,6 +241,7 @@ class PluginManager {
     const command = this.getCommand(commandsArray, allowEntryPoints);
 
     this.convertShortcutsIntoOptions(command);
+    this.assignDefaultOptions(command);
     this.validateOptions(command);
 
     const events = this.getEvents(command);
@@ -352,6 +353,13 @@ class PluginManager {
     });
   }
 
+  assignDefaultOptions(command) {
+    _.forEach(command.options, (value, key) => {
+      if (value.default && (!this.cliOptions[key] || this.cliOptions[key] === true)) {
+        this.cliOptions[key] = value.default;
+      }
+    });
+  }
 }
 
 module.exports = PluginManager;


Test patch:
diff --git a/lib/classes/PluginManager.test.js b/lib/classes/PluginManager.test.js
index d3ebcfc01fc..c74bf3aff6a 100644
--- a/lib/classes/PluginManager.test.js
+++ b/lib/classes/PluginManager.test.js
@@ -888,6 +888,45 @@ describe('PluginManager', () => {
     });
   });
 
+  describe('#assignDefaultOptions()', () => {
+    it('should assign default values to empty options', () => {
+      pluginManager.commands = {
+        foo: {
+          options: {
+            bar: {
+              required: true,
+              default: 'foo',
+            },
+          },
+        },
+      };
+
+      const foo = pluginManager.commands.foo;
+      pluginManager.assignDefaultOptions(foo);
+
+      expect(pluginManager.cliOptions.bar).to.equal(foo.options.bar.default);
+    });
+
+    it('should not assign default values to non-empty options', () => {
+      pluginManager.commands = {
+        foo: {
+          options: {
+            bar: {
+              required: true,
+              default: 'foo',
+            },
+          },
+        },
+      };
+
+      const foo = pluginManager.commands.foo;
+      pluginManager.setCliOptions({ bar: 100 });
+      pluginManager.assignDefaultOptions(foo);
+
+      expect(pluginManager.cliOptions.bar).to.equal(100);
+    });
+  });
+
   describe('#validateOptions()', () => {
     it('should throw an error if a required option is not set', () => {
       pluginManager.commands = {