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

Commits since 0.19.0 branch freeze #1315

Merged
merged 13 commits into from
Aug 7, 2019
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: 33 additions & 0 deletions DEVELOPMENT_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,39 @@ conventions are best practices that we have learnt over time.
- Do not catch the broader `Exception`, unless you have a really
strong reason to do. You must explain the reason in great detail in
comments.


Testing
-------

We need thorough test coverage to ensure the code change works today,
and continues to work in future. When you make a code change, use the
following framework to decide the kinds of tests to write:

- When you adds/removed/modifies code paths (aka branches/arcs),
write **unit tests** with goal of making sure the flow works. Focus
on verifying the flow and use mocks to isolate from as many
external dependencies as you can. "External dependencies"
includes system calls, libraries, other classes/methods you wrote
but logically outside of the system-under-test.

> Aim to test with complete isolation

- When your code uses external dependencies, write **functional tests**
to verify some flows by including as many external dependencies as
possible. Focus on verifying the flows that directly use the dependencies.

> Aim to test one or more logically related components. Includes docker,
file system, API server, but might still mock some things like AWS API
calls.

- When your code adds/removes/modifies a customer facing behavior,
write **integration tests**. Focus on verifying the customer experience
works as expected.

> Aim to test how a customer will use the feature/command. Includes
calling AWS APIs, spinning up Docker containers, mutating files etc.


Design Document
---------------
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
8 changes: 4 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
six~=1.11.0
chevron~=0.12
click~=6.7
click~=7.0
enum34~=1.1.6; python_version<"3.4"
Flask~=1.0.2
boto3~=1.9, >=1.9.56
PyYAML~=3.12
PyYAML~=5.1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

cookiecutter~=1.6.0
aws-sam-translator==1.10.0
docker~=3.7.0
docker~=4.0
dateparser~=0.7
python-dateutil~=2.6
pathlib2~=2.3.2; python_version<"3.4"
requests==2.22.0
serverlessrepo==0.1.8
serverlessrepo==0.1.9
aws_lambda_builders==0.3.0
3 changes: 2 additions & 1 deletion samcli/cli/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def debug(self, value):

if self._debug:
# Turn on debug logging
logging.getLogger().setLevel(logging.DEBUG)
logging.getLogger('samcli').setLevel(logging.DEBUG)
logging.getLogger('aws_lambda_builders').setLevel(logging.DEBUG)

@property
def region(self):
Expand Down
9 changes: 8 additions & 1 deletion samcli/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from samcli import __version__
from samcli.lib.telemetry.metrics import send_installed_metric
from samcli.lib.utils.sam_logging import SamCliLogger
from .options import debug_option, region_option, profile_option
from .context import Context
from .command import BaseCommand
Expand Down Expand Up @@ -79,7 +80,6 @@ def cli(ctx):
You can find more in-depth guide about the SAM specification here:
https://github.com/awslabs/serverless-application-model.
"""

if global_cfg.telemetry_enabled is None:
enabled = True

Expand All @@ -95,3 +95,10 @@ def cli(ctx):

except (IOError, ValueError) as ex:
LOG.debug("Unable to write telemetry flag", exc_info=ex)

sam_cli_logger = logging.getLogger('samcli')
sam_cli_formatter = logging.Formatter('%(message)s')
lambda_builders_logger = logging.getLogger('aws_lambda_builders')

SamCliLogger.configure_logger(sam_cli_logger, sam_cli_formatter, logging.INFO)
SamCliLogger.configure_logger(lambda_builders_logger, sam_cli_formatter, logging.INFO)
4 changes: 2 additions & 2 deletions samcli/commands/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from samcli.cli.main import pass_context, common_options
from samcli.commands.exceptions import UserException
from samcli.local.common.runtime_template import INIT_RUNTIMES, SUPPORTED_DEP_MANAGERS
from samcli.local.common.runtime_template import INIT_RUNTIMES, SUPPORTED_DEP_MANAGERS, DEFAULT_RUNTIME
from samcli.local.init import generate_project
from samcli.local.init.exceptions import GenerateProjectFailedError
from samcli.lib.telemetry.metrics import track_command
Expand All @@ -19,7 +19,7 @@

@click.command(context_settings=dict(help_option_names=[u'-h', u'--help']))
@click.option('-l', '--location', help="Template location (git, mercurial, http(s), zip, path)")
@click.option('-r', '--runtime', type=click.Choice(INIT_RUNTIMES), default="nodejs8.10",
@click.option('-r', '--runtime', type=click.Choice(INIT_RUNTIMES), default=DEFAULT_RUNTIME,
help="Lambda Runtime of your app")
@click.option('-d', '--dependency-manager', type=click.Choice(SUPPORTED_DEP_MANAGERS), default=None,
help="Dependency manager of your Lambda runtime", required=False)
Expand Down
2 changes: 1 addition & 1 deletion samcli/lib/samlib/cloudformation_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ def find_executable(execname):
except OSError as ex:
LOG.debug("Unable to find executable %s", name, exc_info=ex)

raise OSError("Unable to find AWS CLI installation under following names: {}".format(options))
raise OSError("Cannot find AWS CLI installation, was looking at executables with names: {}".format(options))
31 changes: 31 additions & 0 deletions samcli/lib/utils/sam_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Configures a logger
"""
import logging


class SamCliLogger(object):

@staticmethod
def configure_logger(logger, formatter, level):
"""
Configure a Logger with the formatter provided.

Parameters
----------
logger logging.getLogger
Logger to configure
formatter logging.formatter
Formatter for the logger

Returns
-------
None
"""
log_stream_handler = logging.StreamHandler()
log_stream_handler.setLevel(logging.DEBUG)
log_stream_handler.setFormatter(formatter)

logger.setLevel(level)
logger.propagate = False
logger.addHandler(log_stream_handler)
11 changes: 8 additions & 3 deletions samcli/local/common/runtime_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
_init_path = str(pathlib.Path(os.path.dirname(__file__)).parent)
_templates = os.path.join(_init_path, 'init', 'templates')


# Note(TheSriram): The ordering of the runtimes list per language is based on the latest to oldest.
RUNTIME_DEP_TEMPLATE_MAPPING = {
"python": [
{
"runtimes": ["python2.7", "python3.6", "python3.7"],
"runtimes": ["python3.7", "python3.6", "python2.7"],
"dependency_manager": "pip",
"init_location": os.path.join(_templates, "cookiecutter-aws-sam-hello-python"),
"build": True
Expand All @@ -32,7 +34,7 @@
],
"nodejs": [
{
"runtimes": ["nodejs8.10", "nodejs10.x"],
"runtimes": ["nodejs10.x", "nodejs8.10"],
"dependency_manager": "npm",
"init_location": os.path.join(_templates, "cookiecutter-aws-sam-hello-nodejs"),
"build": True
Expand All @@ -46,7 +48,7 @@
],
"dotnet": [
{
"runtimes": ["dotnetcore", "dotnetcore1.0", "dotnetcore2.0", "dotnetcore2.1"],
"runtimes": ["dotnetcore2.1", "dotnetcore2.0", "dotnetcore1.0", "dotnetcore"],
"dependency_manager": "cli-package",
"init_location": os.path.join(_templates, "cookiecutter-aws-sam-hello-dotnet"),
"build": True
Expand Down Expand Up @@ -81,3 +83,6 @@
RUNTIMES = set(itertools.chain(*[c['runtimes'] for c in list(
itertools.chain(*(RUNTIME_DEP_TEMPLATE_MAPPING.values())))]))
INIT_RUNTIMES = RUNTIMES.union(RUNTIME_DEP_TEMPLATE_MAPPING.keys())

# NOTE(TheSriram): Default Runtime Choice when runtime is not chosen
DEFAULT_RUNTIME = RUNTIME_DEP_TEMPLATE_MAPPING['nodejs'][0]['runtimes'][0]
6 changes: 2 additions & 4 deletions samcli/local/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


def generate_project(
location=None, runtime="nodejs", dependency_manager=None,
location=None, runtime="nodejs10.x", dependency_manager=None,
output_dir=".", name='sam-sample-app', no_input=False):
"""Generates project using cookiecutter and options given

Expand Down Expand Up @@ -51,11 +51,9 @@ def generate_project(

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:
if not dependency_manager or dependency_manager == mapping['dependency_manager']:
template = mapping['init_location']
break
elif dependency_manager == mapping['dependency_manager']:
template = mapping['init_location']

if not template:
msg = "Lambda Runtime {} does not support dependency manager: {}".format(runtime, dependency_manager)
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/cli/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def test_must_set_get_debug_flag(self):

ctx.debug = True
self.assertEquals(ctx.debug, True, "debug must be set to True")
self.assertEquals(logging.getLogger().getEffectiveLevel(), logging.DEBUG)
self.assertEquals(logging.getLogger('samcli').getEffectiveLevel(), logging.DEBUG)
self.assertEquals(logging.getLogger('aws_lambda_builders').getEffectiveLevel(), logging.DEBUG)

def test_must_unset_get_debug_flag(self):
ctx = Context()
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/lib/samlib/test_cloudformation_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def test_must_raise_error_if_executable_not_found(self, platform_system_mock, po
with self.assertRaises(OSError) as ctx:
find_executable(execname)

expected = "Unable to find AWS CLI installation under following names: {}".format(["foo.cmd", "foo.exe", "foo"])
expected = "Cannot find AWS CLI installation, was looking at executables with names: {}".format(
["foo.cmd", "foo.exe", "foo"])
self.assertEquals(expected, str(ctx.exception))

self.assertEquals(popen_mock.mock_calls, [
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/lib/utils/test_sam_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from unittest import TestCase
from mock import patch, Mock

from samcli.lib.utils.sam_logging import SamCliLogger


class TestSamCliLogger(TestCase):

@patch("samcli.lib.utils.sam_logging.logging")
def test_configure_samcli_logger(self, logging_patch):
formatter_mock = Mock()
logger_mock = Mock()
logging_patch.DEBUG = 2

stream_handler_mock = Mock()
logging_patch.StreamHandler.return_value = stream_handler_mock

SamCliLogger.configure_logger(logger_mock, formatter_mock, level=1)

self.assertFalse(logger_mock.propagate)

logger_mock.setLevel.assert_called_once_with(1)
logger_mock.addHandler.assert_called_once_with(stream_handler_mock)
stream_handler_mock.setLevel.assert_called_once_with(2)
stream_handler_mock.setFormatter.assert_called_once_with(formatter_mock)