Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Update generation logic #5604

Merged
merged 3 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions schema/schema.py → schema/make_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import json
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Union

import click

Expand All @@ -20,6 +20,15 @@
PARAMS_TO_OMIT_DEFAULT_FIELD = [
"layer_cache_basedir" # sets default to root directory to that of machine the schema is generated on
]
EXCEPTION_OPTION_CLASS_MAPPER = { # for params without proper class names, map them uniquely
"parameter_overrides": ["array", "string"],
"image_repository": ["string"],
"image_repositories": ["array"],
"metadata": ["string"],
"signing_profiles": ["string"],
"tags": ["array"],
"parameter": ["array"],
}
CHARS_TO_CLEAN = [
"\b", # backspaces
"\u001b[0m", # ANSI start bold
Expand All @@ -43,7 +52,7 @@ class SamCliParameterSchema:
"""

name: str
type: str
type: Union[str, List[str]]
description: str = ""
default: Optional[Any] = None
items: Optional[str] = None
Expand Down Expand Up @@ -147,25 +156,27 @@ def format_param(param: click.core.Option) -> SamCliParameterSchema:
"""
if not param:
raise SchemaGenerationException("Expected to format a parameter that doesn't exist")
if not param.type.name:
raise SchemaGenerationException(f"Parameter {param} passed without a type")
if not param.type.name and param.name not in EXCEPTION_OPTION_CLASS_MAPPER.keys():
raise SchemaGenerationException(f"Parameter {param} passed without a type:\n{param.type}")

param_type = param.type.name.lower()
formatted_param_type = ""
formatted_param_types = []
# NOTE: Params do not have explicit "string" type; either "text" or "path".
# All choice options are from a set of strings.
if param_type in ["text", "path", "choice", "filename", "directory"]:
formatted_param_type = "string"
if param.name in EXCEPTION_OPTION_CLASS_MAPPER.keys():
formatted_param_types = EXCEPTION_OPTION_CLASS_MAPPER[param.name]
elif param_type in ["text", "path", "choice", "filename", "directory"]:
formatted_param_types = ["string"]
elif param_type == "list":
formatted_param_type = "array"
formatted_param_types = ["array"]
else:
formatted_param_type = param_type or "string"
formatted_param_types = [param_type] or ["string"]

formatted_param: SamCliParameterSchema = SamCliParameterSchema(
param.name or "",
formatted_param_type,
formatted_param_types if len(formatted_param_types) > 1 else formatted_param_types[0],
clean_text(param.help or ""),
items="string" if formatted_param_type == "array" else None,
items="string" if "array" in formatted_param_types else None,
)

if param.default and param.name not in PARAMS_TO_OMIT_DEFAULT_FIELD:
Expand Down
71 changes: 55 additions & 16 deletions schema/samcli.json
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,14 @@
},
"parameter_overrides": {
"title": "parameter_overrides",
"type": "string",
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs."
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"skip_pull_image": {
"title": "skip_pull_image",
Expand Down Expand Up @@ -396,8 +402,14 @@
},
"parameter_overrides": {
"title": "parameter_overrides",
"type": "string",
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs."
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"debug_port": {
"title": "debug_port",
Expand Down Expand Up @@ -548,8 +560,14 @@
},
"parameter_overrides": {
"title": "parameter_overrides",
"type": "string",
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs."
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"debug_port": {
"title": "debug_port",
Expand Down Expand Up @@ -723,8 +741,14 @@
},
"parameter_overrides": {
"title": "parameter_overrides",
"type": "string",
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs."
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"debug_port": {
"title": "debug_port",
Expand Down Expand Up @@ -871,8 +895,11 @@
},
"image_repositories": {
"title": "image_repositories",
"type": "string",
"description": "Mapping of Function Logical ID to AWS ECR Repository URI.\n\nExample: Function_Logical_ID=ECR_Repo_Uri\nThis option can be specified multiple times."
"type": "array",
"description": "Mapping of Function Logical ID to AWS ECR Repository URI.\n\nExample: Function_Logical_ID=ECR_Repo_Uri\nThis option can be specified multiple times.",
"items": {
"type": "string"
}
},
"s3_prefix": {
"title": "s3_prefix",
Expand Down Expand Up @@ -1010,8 +1037,11 @@
},
"image_repositories": {
"title": "image_repositories",
"type": "string",
"description": "Mapping of Function Logical ID to AWS ECR Repository URI.\n\nExample: Function_Logical_ID=ECR_Repo_Uri\nThis option can be specified multiple times."
"type": "array",
"description": "Mapping of Function Logical ID to AWS ECR Repository URI.\n\nExample: Function_Logical_ID=ECR_Repo_Uri\nThis option can be specified multiple times.",
"items": {
"type": "string"
}
},
"force_upload": {
"title": "force_upload",
Expand Down Expand Up @@ -1063,13 +1093,22 @@
},
"tags": {
"title": "tags",
"type": "string",
"description": "List of tags to associate with the stack."
"type": "array",
"description": "List of tags to associate with the stack.",
"items": {
"type": "string"
}
},
"parameter_overrides": {
"title": "parameter_overrides",
"type": "string",
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs."
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"signing_profiles": {
"title": "signing_profiles",
Expand Down
23 changes: 11 additions & 12 deletions tests/unit/schema/test_schema_logic.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from typing import List
from unittest.mock import MagicMock, Mock, patch
import click
from unittest.mock import MagicMock, patch
from parameterized import parameterized
from unittest import TestCase
from schema.exceptions import SchemaGenerationException

from schema.schema import (
from schema.make_schema import (
SamCliCommandSchema,
SamCliParameterSchema,
SchemaKeys,
Expand Down Expand Up @@ -121,7 +120,7 @@ def test_param_formatted_throws_error_when_none(self):
("choice", SamCliParameterSchema("p_name", "string", default=["default", "value"], choices=["1", "2"])),
]
)
@patch("schema.schema.isinstance")
@patch("schema.make_schema.isinstance")
def test_param_formatted_given_type(self, param_type, expected_param, isinstance_mock):
mock_param = MagicMock()
mock_param.name = "p_name"
Expand All @@ -135,8 +134,8 @@ def test_param_formatted_given_type(self, param_type, expected_param, isinstance

self.assertEqual(expected_param, formatted_param)

@patch("schema.schema.isinstance")
@patch("schema.schema.format_param")
@patch("schema.make_schema.isinstance")
@patch("schema.make_schema.format_param")
def test_getting_params_from_cli_object(self, format_param_mock, isinstance_mock):
mock_cli = MagicMock()
mock_cli.params = []
Expand All @@ -154,8 +153,8 @@ def test_getting_params_from_cli_object(self, format_param_mock, isinstance_mock
self.assertNotIn("config_file", params)
self.assertNotIn(None, params)

@patch("schema.schema.importlib.import_module")
@patch("schema.schema.get_params_from_command")
@patch("schema.make_schema.importlib.import_module")
@patch("schema.make_schema.get_params_from_command")
def test_command_structure_is_retrieved(self, get_params_mock, import_mock):
mock_module = self._setup_mock_module()
import_mock.side_effect = lambda _: mock_module
Expand All @@ -165,9 +164,9 @@ def test_command_structure_is_retrieved(self, get_params_mock, import_mock):

self._validate_retrieved_command_structure(commands)

@patch("schema.schema.importlib.import_module")
@patch("schema.schema.get_params_from_command")
@patch("schema.schema.isinstance")
@patch("schema.make_schema.importlib.import_module")
@patch("schema.make_schema.get_params_from_command")
@patch("schema.make_schema.isinstance")
def test_command_structure_is_retrieved_from_group_cli(self, isinstance_mock, get_params_mock, import_mock):
mock_module = self._setup_mock_module()
mock_module.cli.commands = {}
Expand All @@ -183,7 +182,7 @@ def test_command_structure_is_retrieved_from_group_cli(self, isinstance_mock, ge

self._validate_retrieved_command_structure(commands)

@patch("schema.schema.retrieve_command_structure")
@patch("schema.make_schema.retrieve_command_structure")
def test_schema_is_generated_properly(self, retrieve_commands_mock):
def mock_retrieve_commands(package_name, counter=[0]):
counter[0] += 1
Expand Down
Loading