Repository: serverless/serverless (JavaScript)
Date: 2019-01-20 07:17:33+00:00
Task type: Bug Fix

Issue:
'sls print' contains Warnings.
<!--
1. If you have a question and not a bug report please ask first at http://forum.serverless.com
2. Please check if an issue already exists. This bug may have already been documented
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description

* What went wrong?

It came to occur since 1.36.0.
Output of `sls print` contains Warnings.

The reproduction code is as follows.

My serverless.yml:
```yaml
service: servicename

provider:
  name: aws
  runtime: nodejs8.10

functions:
  function1:
    handler: lib/proxy.handler
  function2:
    handler: lib/proxy.handler
```

Yes, We have multiple functions having same handler.
The difference between the two functions is environment variables and so on.

shell script:
```bash
sls print
```

stdout:
```
Serverless: Warning: A handler "lib/proxy.handler" is duplicated in functions: function1, function2.
service: servicename
provider:
  name: aws
  runtime: nodejs8.10
functions:
  function1:
    handler: lib/proxy.handler
  function2:
    handler: lib/proxy.handler
```


* What did you expect should have happened?

`sls print` should output valid yaml.
Warnings should be written to stderr. Otherwise, `sls print` should not output warnings.

* What was the config you used?

As mentioned above.

* What stacktrace or error message from your provider did you see?

Similar or dependent issues:

Add warning for multiple functions having same handler: https://github.com/serverless/serverless/issues/4414 https://github.com/serverless/serverless/pull/5638

// I think that this warning itself is useful.

## Additional Data

* ***Serverless Framework Version you're using***: 1.36.0
* ***Operating System***: darwin
* ***Stack Trace***:
* ***Provider Error messages***:



Issue discussion:

Solution patch:
diff --git a/lib/Serverless.js b/lib/Serverless.js
index b501a8fa733..3fbd527fd4b 100644
--- a/lib/Serverless.js
+++ b/lib/Serverless.js
@@ -81,6 +81,7 @@ class Serverless {
     if (this.cli.displayHelp(this.processedInput)) {
       return BbPromise.resolve();
     }
+    this.cli.suppressLogIfPrintCommand(this.processedInput);
 
     // make sure the command exists before doing anything else
     this.pluginManager.validateCommand(this.processedInput.commands);
diff --git a/lib/classes/CLI.js b/lib/classes/CLI.js
index 53fca5073fd..bcfde70dd3f 100644
--- a/lib/classes/CLI.js
+++ b/lib/classes/CLI.js
@@ -79,6 +79,30 @@ class CLI {
     return { commands, options };
   }
 
+  suppressLogIfPrintCommand(processedInput) {
+    const commands = processedInput.commands;
+    const options = processedInput.options;
+
+    // if "-help" or "-h" was entered
+    if (options.help || options.h) {
+      return;
+    }
+
+    // if "print" was NOT entered
+    if (commands.indexOf('print') === -1) {
+      return;
+    }
+
+    // if other command was combined with "print"
+    if (commands.length !== 1) {
+      return;
+    }
+
+    // Make "log" no-op to suppress warnings.
+    // But preserve "consoleLog" which "print" command use to print config.
+    this.log = function () {};
+  }
+
   displayHelp(processedInput) {
     const commands = processedInput.commands;
     const options = processedInput.options;


Test patch:
diff --git a/lib/classes/CLI.test.js b/lib/classes/CLI.test.js
index ac966027964..f99ea3228da 100644
--- a/lib/classes/CLI.test.js
+++ b/lib/classes/CLI.test.js
@@ -72,6 +72,86 @@ describe('CLI', () => {
     });
   });
 
+  describe('#suppressLogIfPrintCommand()', () => {
+    let logStub;
+    let consoleLogStub;
+
+    beforeEach(() => {
+      logStub = sinon.stub();
+      consoleLogStub = sinon.stub();
+    });
+
+    it('should do nothing when no command is given', () => {
+      cli = new CLI(serverless, []);
+      cli.log = logStub;
+      cli.consoleLog = consoleLogStub;
+
+      const processedInput = cli.processInput();
+      cli.suppressLogIfPrintCommand(processedInput);
+      cli.log('logged');
+      cli.consoleLog('logged');
+
+      expect(logStub.calledOnce).to.equal(true);
+      expect(consoleLogStub.calledOnce).to.equal(true);
+    });
+
+    it('should do nothing when "print" is given with "-h"', () => {
+      cli = new CLI(serverless, ['print', '-h']);
+      cli.log = logStub;
+      cli.consoleLog = consoleLogStub;
+
+      const processedInput = cli.processInput();
+      cli.suppressLogIfPrintCommand(processedInput);
+      cli.log('logged');
+      cli.consoleLog('logged');
+
+      expect(logStub.calledOnce).to.equal(true);
+      expect(consoleLogStub.calledOnce).to.equal(true);
+    });
+
+    it('should do nothing when "print" is given with "-help"', () => {
+      cli = new CLI(serverless, ['print', '-help']);
+      cli.log = logStub;
+      cli.consoleLog = consoleLogStub;
+
+      const processedInput = cli.processInput();
+      cli.suppressLogIfPrintCommand(processedInput);
+      cli.log('logged');
+      cli.consoleLog('logged');
+
+      expect(logStub.calledOnce).to.equal(true);
+      expect(consoleLogStub.calledOnce).to.equal(true);
+    });
+
+    it('should do nothing when "print" is combined with other command.', () => {
+      cli = new CLI(serverless, ['other', 'print']);
+      cli.log = logStub;
+      cli.consoleLog = consoleLogStub;
+
+      const processedInput = cli.processInput();
+      cli.suppressLogIfPrintCommand(processedInput);
+      cli.log('logged');
+      cli.consoleLog('logged');
+
+      expect(logStub.calledOnce).to.equal(true);
+      expect(consoleLogStub.calledOnce).to.equal(true);
+    });
+
+    it('should suppress log when "print" is given', () => {
+      cli = new CLI(serverless, ['print', '-myvar', '123']);
+      cli.log = logStub;
+      cli.consoleLog = consoleLogStub;
+
+      const processedInput = cli.processInput();
+      cli.suppressLogIfPrintCommand(processedInput);
+      cli.log('NOT LOGGED');
+      cli.consoleLog('logged');
+
+      expect(logStub.calledOnce).to.equal(false);
+      expect(consoleLogStub.calledOnce).to.equal(true);
+    });
+  });
+
   describe('#displayHelp()', () => {
     it('should return true when no command is given', () => {
       cli = new CLI(serverless, []);