Repository: serverless/serverless (JavaScript) — Bug Fix

Issue:
Didn't skip deployment if unchanged function has event
<!--
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?
When the function doesn't have event

```
functions:
  hello:
    handler: handler.hello
```
The deployment will be skipped if code unchanged.
```
sls deploy                                                                        10:48:56 
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Service files not changed. Skipping deployment...
```

but if functions have event like http
```
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
```
sls never skip the deployment regardless code unchanged
```
sls deploy                                                                             10:49:06 
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
```

* What did you expect should have happened?
The deployment should be skipped if nothing changed

## Additional Data

* ***Serverless Framework Version you're using***:
1.38.0
* ***Operating System***: macOS Mojave 10.14.3




Discussion:

Resolving patch:
diff --git a/lib/plugins/aws/lib/normalizeFiles.js b/lib/plugins/aws/lib/normalizeFiles.js
index a8df6ac3bbf..e0150cc18ca 100644
--- a/lib/plugins/aws/lib/normalizeFiles.js
+++ b/lib/plugins/aws/lib/normalizeFiles.js
@@ -6,8 +6,11 @@ module.exports = {
   normalizeCloudFormationTemplate(template) {
     const normalizedTemplate = _.cloneDeep(template);
 
-    // reset all the S3Keys for AWS::Lambda::Function resources
-    _.forEach(normalizedTemplate.Resources, (value) => {
+    _.forEach(normalizedTemplate.Resources, (value, key) => {
+      if (key.startsWith('ApiGatewayDeployment')) {
+        delete Object.assign(normalizedTemplate.Resources,
+          { ApiGatewayDeployment: normalizedTemplate.Resources[key] })[key];
+      }
       if (value.Type && value.Type === 'AWS::Lambda::Function') {
         const newVal = value;
         newVal.Properties.Code.S3Key = '';


Test patch:
diff --git a/lib/plugins/aws/lib/normalizeFiles.test.js b/lib/plugins/aws/lib/normalizeFiles.test.js
index de1020f09b5..8f1f25dd34c 100644
--- a/lib/plugins/aws/lib/normalizeFiles.test.js
+++ b/lib/plugins/aws/lib/normalizeFiles.test.js
@@ -35,6 +35,64 @@ describe('normalizeFiles', () => {
       });
     });
 
+    it('should reset the S3 content keys for Lambda layer versions', () => {
+      const input = {
+        Resources: {
+          MyLambdaLayer: {
+            Type: 'AWS::Lambda::LayerVersion',
+            Properties: {
+              Content: {
+                S3Key: 'some-s3-key-for-the-layer',
+              },
+            },
+          },
+        },
+      };
+
+      const result = normalizeFiles.normalizeCloudFormationTemplate(input);
+
+      expect(result).to.deep.equal({
+        Resources: {
+          MyLambdaLayer: {
+            Type: 'AWS::Lambda::LayerVersion',
+            Properties: {
+              Content: {
+                S3Key: '',
+              },
+            },
+          },
+        },
+      });
+    });
+
+    it('should remove the API Gateway Deployment random id', () => {
+      const input = {
+        Resources: {
+          ApiGatewayDeploymentR4ND0M: {
+            Type: 'AWS::ApiGateway::Deployment',
+            Properties: {
+              RestApiId: 'rest-api-id',
+              StageName: 'dev',
+            },
+          },
+        },
+      };
+
+      const result = normalizeFiles.normalizeCloudFormationTemplate(input);
+
+      expect(result).to.deep.equal({
+        Resources: {
+          ApiGatewayDeployment: {
+            Type: 'AWS::ApiGateway::Deployment',
+            Properties: {
+              RestApiId: 'rest-api-id',
+              StageName: 'dev',
+            },
+          },
+        },
+      });
+    });
+
     it('should keep other resources untouched', () => {
       const input = {
         Resources: {