Repository: serverless/serverless (JavaScript)
Task: Refactoring (2016-07-26 09:05:02+00:00)

Issue:
Plugins Are Being Loaded Twice
##### Serverless Framework Version: V.1 Alpha 1
##### Operating System:  OSX 10.11.2
##### Expected Behavior:
- Plugins should be loaded once, causing hooks and all else to be set only once.
##### Actual Behavior:
- Plugins are loaded twice
- This is because they are each instantiated twice in the PluginManager, due to the way the Plugin commands and shortcuts code is written.  That code needs to be refactored to solve this problem and it could be improved generally.



Discussion:
Thanks for reporting! This is really not intended behavior. Will look into it ASAP.


Patch:
diff --git a/lib/classes/PluginManager.js b/lib/classes/PluginManager.js
index 8bd9d73ea10..714fdab3365 100644
--- a/lib/classes/PluginManager.js
+++ b/lib/classes/PluginManager.js
@@ -129,13 +129,15 @@ class PluginManager {
   }
 
   addPlugin(Plugin) {
-    this.loadCommands(Plugin);
+    const pluginInstance = new Plugin(this.serverless, this.cliOptions);
+
+    this.loadCommands(pluginInstance);
 
     // shortcuts should be converted into options so that the plugin
     // author can use the option (instead of the shortcut)
     this.convertShortcutsIntoOptions(this.cliOptions, this.commands);
 
-    this.plugins.push(new Plugin(this.serverless, this.cliOptions));
+    this.plugins.push(pluginInstance);
   }
 
   loadCorePlugins() {
@@ -172,8 +174,8 @@ class PluginManager {
     }
   }
 
-  loadCommands(Plugin) {
-    this.commandsList.push((new Plugin(this.serverless)).commands);
+  loadCommands(pluginInstance) {
+    this.commandsList.push(pluginInstance.commands);
 
     // TODO: refactor ASAP as it slows down overall performance
     // rebuild the commands


Test patch:
diff --git a/tests/classes/PluginManager.js b/tests/classes/PluginManager.js
index 7dc65d6f4f7..79bfa8008b3 100644
--- a/tests/classes/PluginManager.js
+++ b/tests/classes/PluginManager.js
@@ -410,7 +410,8 @@ describe('PluginManager', () => {
 
   describe('#loadCommands()', () => {
     it('should load the plugin commands', () => {
-      pluginManager.loadCommands(SynchronousPluginMock);
+      const synchronousPluginMockInstance = new SynchronousPluginMock();
+      pluginManager.loadCommands(synchronousPluginMockInstance);
 
       expect(pluginManager.commandsList[0]).to.have.property('deploy');
     });
@@ -418,7 +419,8 @@ describe('PluginManager', () => {
 
   describe('#getEvents()', () => {
     beforeEach(() => {
-      pluginManager.loadCommands(SynchronousPluginMock);
+      const synchronousPluginMockInstance = new SynchronousPluginMock();
+      pluginManager.loadCommands(synchronousPluginMockInstance);
     });
 
     it('should get all the matching events for a root level command in the correct order', () => {