diff --git a/samcli/lib/samlib/resource_metadata_normalizer.py b/samcli/lib/samlib/resource_metadata_normalizer.py index d12a930be9..e6560da69e 100644 --- a/samcli/lib/samlib/resource_metadata_normalizer.py +++ b/samcli/lib/samlib/resource_metadata_normalizer.py @@ -5,6 +5,7 @@ import json import logging import re +from copy import deepcopy from pathlib import Path from typing import Dict @@ -61,10 +62,8 @@ def normalize(template_dict, normalize_parameters=False): resources = template_dict.get(RESOURCES_KEY, {}) for logical_id, resource in resources.items(): - resource_metadata = resource.get(METADATA_KEY) - if resource_metadata is None: - resource_metadata = {} - resource[METADATA_KEY] = resource_metadata + # copy metadata to another variable, change its values and assign it back in the end + resource_metadata = deepcopy(resource.get(METADATA_KEY)) or {} is_normalized = resource_metadata.get(SAM_IS_NORMALIZED, False) if not is_normalized: @@ -97,6 +96,7 @@ def normalize(template_dict, normalize_parameters=False): resource_metadata, {SAM_RESOURCE_ID_KEY: ResourceMetadataNormalizer.get_resource_id(resource, logical_id)}, ) + resource[METADATA_KEY] = resource_metadata # This is a work around to allow the customer to use sam deploy or package commands without the need to provide # values for the CDK auto generated asset parameters. The suggested solution is to let CDK add some metadata to diff --git a/tests/unit/lib/samlib/test_resource_metadata_normalizer.py b/tests/unit/lib/samlib/test_resource_metadata_normalizer.py index 7c60be1124..8942496bea 100644 --- a/tests/unit/lib/samlib/test_resource_metadata_normalizer.py +++ b/tests/unit/lib/samlib/test_resource_metadata_normalizer.py @@ -3,6 +3,7 @@ from unittest import TestCase from samcli.lib.samlib.resource_metadata_normalizer import ResourceMetadataNormalizer +from samcli.yamlhelper import yaml_parse class TestResourceMetadataNormalizer(TestCase): @@ -456,6 +457,50 @@ def test_skip_normalizing_already_normalized_resource(self): self.assertEqual("new path", template_data["Resources"]["Function1"]["Properties"]["Code"]) self.assertEqual("Function1", template_data["Resources"]["Function1"]["Metadata"]["SamResourceId"]) + def test_with_referenced_metadata(self): + input_template = """ + Resources: + FirstFunction: + Type: AWS::Serverless::Function + Metadata: &GoFunctionMetadata + BuildMethod: go1.x + BuildProperties: + TrimGoPath: true + Properties: + CodeUri: dummy + Handler: bootstrap + Runtime: provided.al2 + SecondFunction: + Type: AWS::Serverless::Function + Metadata: *GoFunctionMetadata + Properties: + CodeUri: dummy + Handler: bootstrap + Runtime: provided.al2 + ThirdFunction: + Type: AWS::Serverless::Function + Metadata: *GoFunctionMetadata + Properties: + CodeUri: dummy + Handler: bootstrap + Runtime: provided.al2 + """ + template_dict = yaml_parse(input_template) + ResourceMetadataNormalizer.normalize(template_dict) + + self.assertEqual( + template_dict.get("Resources", {}).get("FirstFunction", {}).get("Metadata", {}).get("SamResourceId"), + "FirstFunction", + ) + self.assertEqual( + template_dict.get("Resources", {}).get("SecondFunction", {}).get("Metadata", {}).get("SamResourceId"), + "SecondFunction", + ) + self.assertEqual( + template_dict.get("Resources", {}).get("ThirdFunction", {}).get("Metadata", {}).get("SamResourceId"), + "ThirdFunction", + ) + class TestResourceMetadataNormalizerGetResourceId(TestCase): @parameterized.expand(