Skip to content

Commit

Permalink
Merge from aws/aws-sam-cli/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
aws-sam-cli-bot authored Apr 7, 2022
2 parents 3089a79 + 587ad2d commit 729bd1a
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 20 deletions.
2 changes: 1 addition & 1 deletion samcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
SAM CLI version
"""

__version__ = "1.45.0"
__version__ = "1.46.0"
30 changes: 29 additions & 1 deletion samcli/commands/init/init_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
from samcli.lib.utils.packagetype import IMAGE
from samcli.local.common.runtime_template import (
RUNTIME_DEP_TEMPLATE_MAPPING,
get_provided_runtime_from_custom_runtime,
get_local_lambda_images_location,
get_local_manifest_path,
is_custom_runtime,
)

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -179,7 +181,8 @@ def get_preprocessed_manifest(
# at the top of list template example displayed to the Customer.
preprocessed_manifest = {"Hello World Example": {}} # type: dict
for template_runtime in manifest_body:
if filter_value and filter_value != template_runtime:
if not filter_value_matches_template_runtime(filter_value, template_runtime):
LOG.debug("Template runtime %s does not match filter value %s", template_runtime, filter_value)
continue
template_list = manifest_body[template_runtime]
for template in template_list:
Expand Down Expand Up @@ -262,3 +265,28 @@ def template_does_not_meet_filter_criteria(
or (package_type and package_type != template.get("packageType"))
or (dependency_manager and dependency_manager != template.get("dependencyManager"))
)


def filter_value_matches_template_runtime(filter_value, template_runtime):
"""
Validate if the filter value matches template runtimes from the manifest file
Parameters
----------
filter_value : str
Lambda runtime used to filter through data generated from the manifest
template_runtime : str
Runtime of the template in view
Returns
-------
bool
True if there is a match else False
"""
if not filter_value:
return True
if is_custom_runtime(filter_value) and filter_value != get_provided_runtime_from_custom_runtime(template_runtime):
return False
if not is_custom_runtime(filter_value) and filter_value != template_runtime:
return False
return True
37 changes: 22 additions & 15 deletions samcli/commands/init/interactive_init_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
)
from samcli.commands.exceptions import SchemasApiException, InvalidInitOptionException
from samcli.lib.schemas.schemas_code_manager import do_download_source_code_binding, do_extract_and_merge_schemas_code
from samcli.local.common.runtime_template import INIT_RUNTIMES, LAMBDA_IMAGES_RUNTIMES_MAP
from samcli.local.common.runtime_template import (
INIT_RUNTIMES,
LAMBDA_IMAGES_RUNTIMES_MAP,
get_provided_runtime_from_custom_runtime,
is_custom_runtime,
)
from samcli.commands.init.init_generator import do_generate
from samcli.commands.init.init_templates import InitTemplates, InvalidInitTemplateError
from samcli.lib.utils.osutils import remove
Expand Down Expand Up @@ -163,9 +168,12 @@ def _generate_from_use_case(
location = templates.location_from_app_template(package_type, runtime, base_image, dependency_manager, app_template)

final_architecture = get_architectures(architecture)
lambda_supported_runtime = (
get_provided_runtime_from_custom_runtime(runtime) if is_custom_runtime(runtime) else runtime
)
extra_context = {
"project_name": name,
"runtime": runtime,
"runtime": lambda_supported_runtime,
"architectures": {"value": final_architecture},
}

Expand All @@ -192,10 +200,14 @@ def _generate_from_use_case(
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
"""
click.secho(next_commands_msg, fg="yellow")
do_generate(location, package_type, runtime, dependency_manager, output_dir, name, no_input, extra_context)
do_generate(
location, package_type, lambda_supported_runtime, dependency_manager, output_dir, name, no_input, extra_context
)
# executing event_bridge logic if call is for Schema dynamic template
if is_dynamic_schemas_template:
_package_schemas_code(runtime, schemas_api_caller, schema_template_details, output_dir, name, location)
_package_schemas_code(
lambda_supported_runtime, schemas_api_caller, schema_template_details, output_dir, name, location
)


def _generate_default_hello_world_application(
Expand Down Expand Up @@ -265,6 +277,7 @@ def _get_app_template_properties(
"""
runtime, package_type, dependency_manager, pt_explicit = template_properties
runtime_options = preprocessed_options[use_case]
runtime = None if is_custom_runtime(runtime) else runtime
if not runtime and not base_image:
question = "Which runtime would you like to use?"
runtime = _get_choice_from_options(runtime, runtime_options, question, "Runtime")
Expand Down Expand Up @@ -336,16 +349,8 @@ def get_sorted_runtimes(runtime_option_list):
list
sorted list of possible runtime to be selected
"""
runtime_list = []
supported_runtime_list = get_supported_runtime(runtime_option_list)
for runtime in supported_runtime_list:
extractLanguageFromRuntime = re.split(r"\d", runtime)[0]
extractVersionFromRuntime = re.search(r"\d.*", runtime).group()
runtime_list.append((extractLanguageFromRuntime, extractVersionFromRuntime))

runtime_list = sorted(supported_runtime_list, key=functools.cmp_to_key(compare_runtimes))
sorted_runtime = ["".join(runtime_tuple) for runtime_tuple in runtime_list]
return sorted_runtime
return sorted(supported_runtime_list, key=functools.cmp_to_key(compare_runtimes))


def get_supported_runtime(runtime_list):
Expand All @@ -366,13 +371,14 @@ def get_supported_runtime(runtime_list):
supported_runtime_list = []
error_message = ""
for runtime in runtime_list:
if runtime not in INIT_RUNTIMES:
if runtime not in INIT_RUNTIMES and not is_custom_runtime(runtime):
if not error_message:
error_message = "Additional runtimes may be available in the latest SAM CLI version. \
Upgrade your SAM CLI to see the full list."
LOG.debug(error_message)
continue
supported_runtime_list.append(runtime)

return supported_runtime_list


Expand Down Expand Up @@ -453,7 +459,8 @@ def _get_version_number(runtime):
float
Runtime version number
"""
if "provided" in runtime:

if is_custom_runtime(runtime):
return 1.0
return float(re.search(r"\d+(\.\d+)?", runtime).group())

Expand Down
4 changes: 2 additions & 2 deletions samcli/lib/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from cookiecutter.exceptions import CookiecutterException, RepositoryNotFound, UnknownRepoType
from cookiecutter.main import cookiecutter

from samcli.local.common.runtime_template import RUNTIME_DEP_TEMPLATE_MAPPING
from samcli.local.common.runtime_template import RUNTIME_DEP_TEMPLATE_MAPPING, is_custom_runtime
from samcli.lib.utils.packagetype import ZIP
from samcli.lib.utils import osutils
from .exceptions import GenerateProjectFailedError, InvalidLocationError
Expand Down Expand Up @@ -64,7 +64,7 @@ def generate_project(
"""
template = None

if runtime and package_type == ZIP:
if runtime and not is_custom_runtime(runtime) and package_type == ZIP:
for mapping in list(itertools.chain(*(RUNTIME_DEP_TEMPLATE_MAPPING.values()))):
if runtime in mapping["runtimes"] or any([r.startswith(runtime) for r in mapping["runtimes"]]):
if not dependency_manager or dependency_manager == mapping["dependency_manager"]:
Expand Down
45 changes: 45 additions & 0 deletions samcli/local/common/runtime_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
All-in-one metadata about runtimes
"""

import re
import itertools
import os
import pathlib
Expand Down Expand Up @@ -103,6 +104,9 @@ def get_local_lambda_images_location(mapping, runtime):
# nodejs runtimes in descending order
"nodejs14.x",
"nodejs12.x",
# custom runtime in descending order
"provided.al2",
"provided",
# python runtimes in descending order
"python3.9",
"python3.8",
Expand Down Expand Up @@ -145,3 +149,44 @@ def get_local_lambda_images_location(mapping, runtime):
"dotnet6": "dotnetcore3.1",
"go1.x": "Go1",
}

PROVIDED_RUNTIMES = ["provided.al2", "provided"]


def is_custom_runtime(runtime):
"""
validated if a runtime is custom or not
Parameters
----------
runtime : str
runtime to be
Returns
-------
_type_
_description_
"""
if not runtime:
return False
provided_runtime = get_provided_runtime_from_custom_runtime(runtime)
return runtime in PROVIDED_RUNTIMES or bool(provided_runtime in PROVIDED_RUNTIMES)


def get_provided_runtime_from_custom_runtime(runtime):
"""
Gets the base lambda runtime for which a custom runtime is based on
Example:
rust (provided.al2) --> provided.al2
java11 --> None
Parameters
----------
runtime : str
Custom runtime or Lambda runtime
Returns
-------
str
returns the base lambda runtime for which a custom runtime is based on
"""
base_runtime_list = re.findall(r"\(([^()]+)\)", runtime)
return base_runtime_list[0] if base_runtime_list else None
156 changes: 155 additions & 1 deletion tests/unit/commands/init/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2535,4 +2535,158 @@ def test_must_remove_unsupported_runtime(self, init_runtime_mock):
init_runtime_mock.return_value = ["dotnetcore3.1", "go1.x", "java11", "python3.7", "ruby2.7"]
expect_result = ["dotnetcore3.1", "java11", "python3.7", "ruby2.7"]
actual_result = get_sorted_runtimes(runtime_option_list)
self.assertEquals(actual_result, expect_result)
self.assertEqual(actual_result, expect_result)

@patch("samcli.commands.init.init_templates.InitTemplates._get_manifest")
@patch("samcli.commands.init.init_templates.InitTemplates._init_options_from_manifest")
@patch("samcli.commands.init.init_generator.generate_project")
@patch.object(InitTemplates, "__init__", MockInitTemplates.__init__)
def test_init_cli_generate_app_template_with_custom_runtime(
self, generate_project_patch, init_options_from_manifest_mock, _get_manifest_mock
):
init_options_from_manifest_mock.return_value = [
{
"directory": "rust/cookiecutter-aws-sam-hello-rust",
"displayName": "Hello World Example",
"dependencyManager": "cargo",
"appTemplate": "hello-world",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
{
"directory": "java11/cookiecutter-aws-sam-eventbridge-schema-app-java-maven",
"displayName": "EventBridge App from scratch (100+ Event Schemas): Maven",
"dependencyManager": "maven",
"appTemplate": "eventBridge-schema-app",
"isDynamicTemplate": "True",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
]

_get_manifest_mock.return_value = {
"rust (provided.al2)": [
{
"directory": "rust/cookiecutter-aws-sam-hello-rust",
"displayName": "Hello World Example",
"dependencyManager": "cargo",
"appTemplate": "hello-world",
"packageType": "Zip",
"useCaseName": "Hello World Example",
}
],
"java11": [
{
"directory": "java11/cookiecutter-aws-sam-eventbridge-schema-app-java-maven",
"displayName": "EventBridge App from scratch (100+ Event Schemas): Maven",
"dependencyManager": "maven",
"appTemplate": "eventBridge-schema-app",
"isDynamicTemplate": "True",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
],
}

# WHEN the user follows interactive init prompts
# 1: AWS Quick Start Templates
# N: Do not select default application
# 2: rust runtime
# test-project: response to name
user_input = """
1
N
2
test-project
"""

runner = CliRunner()
result = runner.invoke(init_cmd, input=user_input)
self.assertFalse(result.exception)
generate_project_patch.assert_called_once_with(
ANY,
ZIP,
"provided.al2",
"cargo",
".",
"test-project",
True,
{"project_name": "test-project", "runtime": "provided.al2", "architectures": {"value": ["x86_64"]}},
)

@patch("samcli.commands.init.init_templates.InitTemplates._get_manifest")
@patch("samcli.commands.init.init_templates.InitTemplates._init_options_from_manifest")
@patch("samcli.commands.init.init_generator.generate_project")
@patch.object(InitTemplates, "__init__", MockInitTemplates.__init__)
def test_init_cli_generate_app_template_with_custom_runtime_using_options(
self, generate_project_patch, init_options_from_manifest_mock, _get_manifest_mock
):
init_options_from_manifest_mock.return_value = [
{
"directory": "rust/cookiecutter-aws-sam-hello-rust",
"displayName": "Hello World Example",
"dependencyManager": "cargo",
"appTemplate": "hello-world",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
{
"directory": "java11/cookiecutter-aws-sam-eventbridge-schema-app-java-maven",
"displayName": "EventBridge App from scratch (100+ Event Schemas): Maven",
"dependencyManager": "maven",
"appTemplate": "eventBridge-schema-app",
"isDynamicTemplate": "True",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
]

_get_manifest_mock.return_value = {
"rust (provided.al2)": [
{
"directory": "rust/cookiecutter-aws-sam-hello-rust",
"displayName": "Hello World Example",
"dependencyManager": "cargo",
"appTemplate": "hello-world",
"packageType": "Zip",
"useCaseName": "Hello World Example",
}
],
"java11": [
{
"directory": "java11/cookiecutter-aws-sam-eventbridge-schema-app-java-maven",
"displayName": "EventBridge App from scratch (100+ Event Schemas): Maven",
"dependencyManager": "maven",
"appTemplate": "eventBridge-schema-app",
"isDynamicTemplate": "True",
"packageType": "Zip",
"useCaseName": "Hello World Example",
},
],
}

# WHEN the user follows interactive init prompts
# 1: AWS Quick Start Templates
# test-project: response to name
user_input = """
1
test-project
"""
args = [
"--runtime",
"provided.al2",
]

runner = CliRunner()
result = runner.invoke(init_cmd, args=args, input=user_input)
self.assertFalse(result.exception)
generate_project_patch.assert_called_once_with(
ANY,
ZIP,
"provided.al2",
"cargo",
".",
"test-project",
True,
{"project_name": "test-project", "runtime": "provided.al2", "architectures": {"value": ["x86_64"]}},
)

0 comments on commit 729bd1a

Please sign in to comment.