Repository: serverless/serverless (JavaScript)
Date: 2019-02-02 13:51:45+00:00
Task type: Bug Fix

Issue:
Fallback value for unset variable is removing spaces
# This is a Bug Report

## Description

For bug reports:
* What went wrong?

Given the following variable fallback:
```yaml
events:
      - schedule: ${env:SCHEDULE, 'rate(2 hours)'}
```

If env `SCHEDULE` is not set I got this error when I run `sls deploy`:
```
An error occurred: ScheduleEventsRuleSchedule1 - Parameter ScheduleExpression is not valid. (Service: AmazonCloudWatchEvents;Status Code: 400; Error Code: ValidationException; Request ID: 996bca35-d0bb-11e8-92f7-2963d8953995).
```

And when I take a look at `serverless-state.json` I see this:
```json
"ScheduleExpression": "rate(2hours)",
```

So it looks like the fallback is removing the spaces. Is this expected?

* What did you expect should have happened?

I expect `sls deploy` to run sucessfully falling back to `rate(2 hours)`.

* What was the config you used?

See above

* What stacktrace or error message from your provider did you see?

See above
## Additional Data

* ***Serverless Framework Version you're using***:

1.32.0

* ***Operating System***:

Linux

* ***Stack Trace***:

n/a

* ***Provider Error messages***:

n/a


Issue discussion:
The culprit:
https://github.com/serverless/serverless/blob/33b7784bad10347767d447dd1c650e0d90931d49/lib/classes/Variables.js#L267-L271

If I just remove `.replace(/\s/g, '')` at line 71 and run tests nothing is broken but I'm afraid that this could have some side effect that tests are not covering?

Can I open a PR removing it?
<del>I think this is already fixed in #5571 and #5594, and released in v1.35.1 and later.</del>

This issue is still reproducible in `v1.36.3` 

Given 

```
service: aws-nodejs

provider:
  name: aws
  runtime: nodejs8.10

functions:
  hello:
    handler: handler.hello
    events:
      - schedule: ${env:SCHEDULE, 'rate(2 hours)'}
```

then 

```
$ sls print

service: aws-nodejs
provider:
  name: aws
  runtime: nodejs8.10
functions:
  hello:
    handler: handler.hello
    events:
      - schedule: rate(2hours)
```




Solution patch:
diff --git a/lib/classes/Variables.js b/lib/classes/Variables.js
index b5f6f406f37..aa52ac7a246 100644
--- a/lib/classes/Variables.js
+++ b/lib/classes/Variables.js
@@ -294,7 +294,7 @@ class Variables {
       this.variableSyntax,
       (context, contents) => contents.trim()
     );
-    if (!cleaned.match(/".*"/)) {
+    if (!cleaned.match(/".*"|'.*'/)) {
       cleaned = cleaned.replace(/\s/g, '');
     }
     return cleaned;


Test patch:
diff --git a/lib/classes/Variables.test.js b/lib/classes/Variables.test.js
index a90b7c2bf56..97f8a527b13 100644
--- a/lib/classes/Variables.test.js
+++ b/lib/classes/Variables.test.js
@@ -786,7 +786,7 @@ describe('Variables', () => {
         return serverless.variables.populateObject(service.custom)
           .should.become(expected);
       });
-      it('should preserve whitespace in literal fallback', () => {
+      it('should preserve whitespace in double-quote literal fallback', () => {
         service.custom = {
           val0: '${self:custom.val, "rate(3 hours)"}',
         };
@@ -796,6 +796,16 @@ describe('Variables', () => {
         return serverless.variables.populateObject(service.custom)
           .should.become(expected);
       });
+      it('should preserve whitespace in single-quote literal fallback', () => {
+        service.custom = {
+          val0: '${self:custom.val, \'rate(1 hour)\'}',
+        };
+        const expected = {
+          val0: 'rate(1 hour)',
+        };
+        return serverless.variables.populateObject(service.custom)
+          .should.become(expected);
+      });
       it('should accept whitespace in variables', () => {
         service.custom = {
           val0: '${self: custom.val}',