Repository: aws-cloudformation/cfn-lint

Issue:
SAM transform is only applied by cfn-lint if not declared as a list
*cfn-lint version: (`cfn-lint --version`)*
0.22.0
*Description of issue.*
cfn-lint works as expected if the SAM transform is specified like this:
```
Transform: AWS::Serverless-2016-10-31
```
but if multiple transforms are needed (or just declared as a list) like:
```
Transform: 
  - AWS::Serverless-2016-10-31
```
the template is not transformed before the validation occurs and that causes an assortment of false positives.
Please provide as much information as possible:
Working Example:
```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
  Function:
    Timeout: 3
    Runtime: nodejs8.10
    Environment:
      Variables:
        VARIABLE: VALUE

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: index.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /
            Method: GET
```
Example that yells about `E1001 Top level item Globals isn't valid`:
```
AWSTemplateFormatVersion: '2010-09-09'
Transform: 
  - AWS::Serverless-2016-10-31
Globals:
  Function:
    Timeout: 3
    Runtime: nodejs8.10
    Environment:
      Variables:
        VARIABLE: VALUE

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: index.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /
            Method: GET
```


Cfn-lint uses the [CloudFormation Resource Specifications](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) as the base to do validation. These files are included as part of the application version. Please update to the latest version of `cfn-lint` or update the spec files manually (`cfn-lint -u`)



Discussion:
Thanks for submitting this.  Working on it.

Resolving patch:
diff --git a/src/cfnlint/__init__.py b/src/cfnlint/__init__.py
--- a/src/cfnlint/__init__.py
+++ b/src/cfnlint/__init__.py
@@ -1334,7 +1334,15 @@ def transform(self):
         # Don't call transformation if Transform is not specified to prevent
         # useless execution of the transformation.
         # Currently locked in to SAM specific
-        if transform_type == 'AWS::Serverless-2016-10-31':
+        if transform_type:
+            if isinstance(transform_type, list):
+                if len(transform_type) != 1:
+                    return matches
+                if transform_type[0] != 'AWS::Serverless-2016-10-31':
+                    return matches
+            if transform_type != 'AWS::Serverless-2016-10-31':
+                return matches
+
             # Save the Globals section so its available for rule processing
             self.cfn.transform_pre['Globals'] = self.cfn.template.get('Globals', {})
             transform = Transform(self.filename, self.cfn.template, self.cfn.regions[0])


Test patch:
diff --git a/test/fixtures/templates/good/transform/list_transform.yaml b/test/fixtures/templates/good/transform/list_transform.yaml
new file mode 100644
--- /dev/null
+++ b/test/fixtures/templates/good/transform/list_transform.yaml
@@ -0,0 +1,23 @@
+---
+AWSTemplateFormatVersion: '2010-09-09'
+Transform:
+  - AWS::Serverless-2016-10-31
+
+Parameters:
+  Stage1:
+    Description: Environment stage (deployment phase)
+    Type: String
+    AllowedValues:
+      - beta
+      - prod
+
+Resources:
+  SkillFunction:
+    Type: AWS::Serverless::Function
+    Properties:
+      CodeUri: '.'
+      Handler: main.handler
+      Runtime: python3.7
+      Timeout: 30
+      MemorySize: 128
+      AutoPublishAlias: !Ref Stage1
diff --git a/test/fixtures/templates/good/transform/list_transform_many.yaml b/test/fixtures/templates/good/transform/list_transform_many.yaml
new file mode 100644
--- /dev/null
+++ b/test/fixtures/templates/good/transform/list_transform_many.yaml
@@ -0,0 +1,24 @@
+---
+AWSTemplateFormatVersion: '2010-09-09'
+Transform:
+  - AWS::Serverless-2016-10-31
+  - TestTransform
+
+Parameters:
+  Stage1:
+    Description: Environment stage (deployment phase)
+    Type: String
+    AllowedValues:
+      - beta
+      - prod
+
+Resources:
+  SkillFunction:
+    Type: AWS::Serverless::Function
+    Properties:
+      CodeUri: '.'
+      Handler: main.handler
+      Runtime: python3.7
+      Timeout: 30
+      MemorySize: 128
+      AutoPublishAlias: !Ref Stage1
diff --git a/test/fixtures/templates/good/transform/list_transform_not_sam.yaml b/test/fixtures/templates/good/transform/list_transform_not_sam.yaml
new file mode 100644
--- /dev/null
+++ b/test/fixtures/templates/good/transform/list_transform_not_sam.yaml
@@ -0,0 +1,16 @@
+---
+AWSTemplateFormatVersion: '2010-09-09'
+Transform:
+  - TestTransform
+
+Resources:
+  SkillFunction:
+    Type: AWS::Lambda::Function
+    Properties:
+      Code:
+        ZipFile: '.'
+      Handler: main.handler
+      Runtime: python3.7
+      Timeout: 30
+      MemorySize: 128
+      Role: arn:aws:iam::123456789012:role/role-name
diff --git a/test/integration/test_good_templates.py b/test/integration/test_good_templates.py
--- a/test/integration/test_good_templates.py
+++ b/test/integration/test_good_templates.py
@@ -65,6 +65,18 @@ def setUp(self):
             'transform_serverless_globals': {
                 'filename': 'test/fixtures/templates/good/transform_serverless_globals.yaml',
                 'failures': 1
+            },
+            'transform_list': {
+                'filename': 'test/fixtures/templates/good/transform/list_transform.yaml',
+                'failures': 0
+            },
+            'transform_list_many': {
+                'filename': 'test/fixtures/templates/good/transform/list_transform_many.yaml',
+                'failures': 0
+            },
+            'transform_list_not_sam': {
+                'filename': 'test/fixtures/templates/good/transform/list_transform_not_sam.yaml',
+                'failures': 0
             }
         }