diff --git a/samcli/commands/validate/validate.py b/samcli/commands/validate/validate.py index cf317b8bfe..5efc1e9c17 100644 --- a/samcli/commands/validate/validate.py +++ b/samcli/commands/validate/validate.py @@ -81,38 +81,46 @@ def do_cli(ctx, template, lint): from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException from samcli.lib.translate.sam_template_validator import SamTemplateValidator + # Read the SAM Template from the file sam_template = _read_sam_file(template) if lint: + # Lint the template if --lint flag is set _lint(ctx, sam_template.serialized, template) else: iam_client = boto3.client("iam") + # Initialize the SAM template validator validator = SamTemplateValidator( sam_template.deserialized, ManagedPolicyLoader(iam_client), profile=ctx.profile, region=ctx.region ) try: + # Validate the SAM template validator.get_translated_template_if_valid() except InvalidSamDocumentException as e: - click.secho("Template provided at '{}' was invalid SAM Template.".format(template), bg="red") + click.secho(f"Template provided at '{template}' was invalid SAM Template.", bg="red") raise InvalidSamTemplateException(str(e)) from e except NoRegionFound as no_region_found_e: + # Handle missing region in the AWS profile or context raise UserException( "AWS Region was not found. Please configure your region through a profile or --region option", wrapped_from=no_region_found_e.__class__.__name__, ) from no_region_found_e except NoCredentialsError as e: + # Handle missing AWS credentials raise UserException( "AWS Credentials are required. Please configure your credentials.", wrapped_from=e.__class__.__name__ ) from e + # Success message after validation click.secho( - "{} is a valid SAM Template. This is according to basic SAM Validation, " - 'for additional validation, please run with "--lint" option'.format(template), + f"{template} is a valid SAM Template. This is according to basic SAM Validation, " + 'for additional validation, please run with "--lint" option.', fg="green", ) + def _read_sam_file(template) -> SamTemplate: """ Reads the file (json and yaml supported) provided and returns the dictionary representation of the file. diff --git a/samcli/lib/translate/sam_template_validator.py b/samcli/lib/translate/sam_template_validator.py index 5c2a9ed33d..6d1903b017 100644 --- a/samcli/lib/translate/sam_template_validator.py +++ b/samcli/lib/translate/sam_template_validator.py @@ -35,7 +35,7 @@ def __init__( Design Details: managed_policy_loader is injected into the `__init__` to allow future expansion - and overriding capabilities. A typically pattern is to pass the name of the class into + and overriding capabilities. A typical pattern is to pass the name of the class into the `__init__` as keyword args. As long as the class 'conforms' to the same 'interface'. This allows the class to be changed by the client and allowing customization of the class being initialized. Something I had in mind would be allowing a template to be run and checked @@ -64,14 +64,13 @@ def __init__( def get_translated_template_if_valid(self): """ Runs the SAM Translator to determine if the template provided is valid. This is similar to running a - ChangeSet in CloudFormation for a SAM Template + ChangeSet in CloudFormation for a SAM Template. Raises ------- InvalidSamDocumentException - If the template is not valid, an InvalidSamDocumentException is raised + If the template is not valid, an InvalidSamDocumentException is raised. """ - sam_translator = Translator( managed_policy_map=None, sam_parser=self.sam_parser, @@ -83,13 +82,20 @@ def get_translated_template_if_valid(self): self._replace_local_image() try: + # Translate the SAM template template = sam_translator.translate( sam_template=self.sam_template, parameter_values=self.parameter_overrides, get_managed_policy_map=self._get_managed_policy_map, ) + + # If translation returns None, raise an exception + if template is None: + raise InvalidSamDocumentException("The translated template is None. The SAM Template is invalid.") + LOG.debug("Translated template is:\n%s", yaml_dump(template)) return yaml_dump(template) + except InvalidDocumentException as e: raise InvalidSamDocumentException( functools.reduce(lambda message, error: message + " " + str(error), e.causes, str(e)) @@ -112,7 +118,7 @@ def _replace_local_codeuri(self): """ Replaces the CodeUri in AWS::Serverless::Function and DefinitionUri in AWS::Serverless::Api and AWS::Serverless::HttpApi to a fake S3 Uri. This is to support running the SAM Translator with - valid values for these fields. If this in not done, the template is invalid in the eyes of SAM + valid values for these fields. If this is not done, the template is invalid in the eyes of SAM Translator (the translator does not support local paths) """ @@ -183,7 +189,6 @@ def is_s3_uri(uri): ------- bool Returns True if the uri given is an S3 uri, otherwise False - """ return isinstance(uri, str) and uri.startswith("s3://") @@ -192,7 +197,7 @@ def _update_to_s3_uri(property_key, resource_property_dict, s3_uri_value="s3://b """ Updates the 'property_key' in the 'resource_property_dict' to the value of 's3_uri_value' - Note: The function will mutate the resource_property_dict that is pass in + Note: The function will mutate the resource_property_dict that is passed in Parameters ----------