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

refactor(build): Move workflow config information into its own file #1001

Merged
merged 3 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions samcli/commands/build/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from samcli.commands._utils.options import template_option_without_build, docker_common_options, \
parameter_override_option
from samcli.commands.build.build_context import BuildContext
from samcli.lib.build.app_builder import ApplicationBuilder, UnsupportedRuntimeException, \
BuildError, UnsupportedBuilderLibraryVersionError
from samcli.lib.build.app_builder import ApplicationBuilder, BuildError, UnsupportedBuilderLibraryVersionError
from samcli.lib.build.workflow_config import UnsupportedRuntimeException
from samcli.commands._utils.template import move_template

LOG = logging.getLogger(__name__)
Expand Down
35 changes: 2 additions & 33 deletions samcli/lib/build/app_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io
import json
import logging
from collections import namedtuple

try:
import pathlib
Expand All @@ -20,15 +19,12 @@
from aws_lambda_builders.builder import LambdaBuilder
from aws_lambda_builders.exceptions import LambdaBuilderError
from aws_lambda_builders import RPC_PROTOCOL_VERSION as lambda_builders_protocol_version
from .workflow_config import get_workflow_config


LOG = logging.getLogger(__name__)


class UnsupportedRuntimeException(Exception):
pass


class UnsupportedBuilderLibraryVersionError(Exception):

def __init__(self, container_name, error_msg):
Expand All @@ -41,32 +37,6 @@ class BuildError(Exception):
pass


def _get_workflow_config(runtime):

config = namedtuple('Capability', ["language", "dependency_manager", "application_framework", "manifest_name"])

if runtime.startswith("python"):
return config(
language="python",
dependency_manager="pip",
application_framework=None,
manifest_name="requirements.txt")
elif runtime.startswith("nodejs"):
return config(
language="nodejs",
dependency_manager="npm",
application_framework=None,
manifest_name="package.json")
elif runtime.startswith("ruby"):
return config(
language="ruby",
dependency_manager="bundler",
application_framework=None,
manifest_name="Gemfile")
else:
raise UnsupportedRuntimeException("'{}' runtime is not supported".format(runtime))


class ApplicationBuilder(object):
"""
Class to build an entire application. Currently, this class builds Lambda functions only, but there is nothing that
Expand Down Expand Up @@ -174,8 +144,7 @@ def update_template(self, template_dict, original_template_path, built_artifacts
return template_dict

def _build_function(self, function_name, codeuri, runtime):

config = _get_workflow_config(runtime)
config = get_workflow_config(runtime)

# Create the arguments to pass to the builder

Expand Down
68 changes: 68 additions & 0 deletions samcli/lib/build/workflow_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
Contains Builder Workflow Configs for different Runtimes
"""

from collections import namedtuple


CONFIG = namedtuple('Capability', ["language", "dependency_manager", "application_framework", "manifest_name"])

GO_MOD_CONFIG = CONFIG(
language="go",
dependency_manager="modules",
application_framework=None,
manifest_name="go.mod")

PYTHON_PIP_CONFIG = CONFIG(
language="python",
dependency_manager="pip",
application_framework=None,
manifest_name="requirements.txt")

NODEJS_NPM_CONFIG = CONFIG(
language="nodejs",
dependency_manager="npm",
application_framework=None,
manifest_name="package.json")

RUBY_BUNDLER_CONFIG = CONFIG(
language="ruby",
dependency_manager="bundler",
application_framework=None,
manifest_name="Gemfile")


class UnsupportedRuntimeException(Exception):
pass


def get_workflow_config(runtime):
"""
Get a workflow config that corresponds to the runtime provided

Parameters
----------
runtime str
The runtime of the config

Returns
-------
namedtuple(Capability)
namedtuple that represents the Builder Workflow Config
"""

workflow_config_by_runtime = {
"go1.x": GO_MOD_CONFIG,
"python2.7": PYTHON_PIP_CONFIG,
"python3.6": PYTHON_PIP_CONFIG,
"python3.7": PYTHON_PIP_CONFIG,
"nodejs4.3": NODEJS_NPM_CONFIG,
"nodejs6.10": NODEJS_NPM_CONFIG,
"nodejs8.10": NODEJS_NPM_CONFIG,
"ruby2.5": RUBY_BUNDLER_CONFIG
}

try:
return workflow_config_by_runtime[runtime]
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice 💃

except KeyError:
raise UnsupportedRuntimeException("'{}' runtime is not supported".format(runtime))
10 changes: 9 additions & 1 deletion tests/integration/buildcmd/build_integ_base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import shutil
import tempfile
from unittest import TestCase

import docker

Expand All @@ -9,7 +10,8 @@
except ImportError:
from pathlib2 import Path

from unittest import TestCase

from samcli.yamlhelper import yaml_parse


class BuildIntegBase(TestCase):
Expand Down Expand Up @@ -85,3 +87,9 @@ def _make_parameter_override_arg(self, overrides):
return " ".join([
"ParameterKey={},ParameterValue={}".format(key, value) for key, value in overrides.items()
])

def _verify_resource_property(self, template_path, logical_id, property, expected_value):

with open(template_path, 'r') as fp:
template_dict = yaml_parse(fp.read())
self.assertEquals(expected_value, template_dict["Resources"][logical_id]["Properties"][property])
19 changes: 0 additions & 19 deletions tests/integration/buildcmd/test_build_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from pathlib2 import Path
from parameterized import parameterized

from samcli.yamlhelper import yaml_parse
from .build_integ_base import BuildIntegBase


Expand Down Expand Up @@ -105,12 +104,6 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files)
actual_files = all_artifacts.intersection(expected_files)
self.assertEquals(actual_files, expected_files)

def _verify_resource_property(self, template_path, logical_id, property, expected_value):

with open(template_path, 'r') as fp:
template_dict = yaml_parse(fp.read())
self.assertEquals(expected_value, template_dict["Resources"][logical_id]["Properties"][property])

def _get_python_version(self):
return "python{}.{}".format(sys.version_info.major, sys.version_info.minor)

Expand Down Expand Up @@ -193,12 +186,6 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files,
actual_files = all_modules.intersection(expected_modules)
self.assertEquals(actual_files, expected_modules)

def _verify_resource_property(self, template_path, logical_id, property, expected_value):

with open(template_path, 'r') as fp:
template_dict = yaml_parse(fp.read())
self.assertEquals(expected_value, template_dict["Resources"][logical_id]["Properties"][property])


class TestBuildCommand_RubyFunctions(BuildIntegBase):

Expand Down Expand Up @@ -265,9 +252,3 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files,
gem_path = ruby_bundled_path.joinpath(ruby_version[0], 'gems')

self.assertTrue(any([True if self.EXPECTED_RUBY_GEM in gem else False for gem in os.listdir(str(gem_path))]))

def _verify_resource_property(self, template_path, logical_id, property, expected_value):

with open(template_path, 'r') as fp:
template_dict = yaml_parse(fp.read())
self.assertEquals(expected_value, template_dict["Resources"][logical_id]["Properties"][property])
3 changes: 2 additions & 1 deletion tests/unit/commands/buildcmd/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from samcli.commands.build.command import do_cli
from samcli.commands.exceptions import UserException
from samcli.lib.build.app_builder import UnsupportedRuntimeException, BuildError, UnsupportedBuilderLibraryVersionError
from samcli.lib.build.app_builder import BuildError, UnsupportedBuilderLibraryVersionError
from samcli.lib.build.workflow_config import UnsupportedRuntimeException


class TestDoCli(TestCase):
Expand Down
49 changes: 5 additions & 44 deletions tests/unit/lib/build_module/test_app_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,12 @@

from unittest import TestCase
from mock import Mock, call, patch
from parameterized import parameterized

from samcli.lib.build.app_builder import ApplicationBuilder, _get_workflow_config,\
UnsupportedBuilderLibraryVersionError, UnsupportedRuntimeException, BuildError, \
from samcli.lib.build.app_builder import ApplicationBuilder,\
UnsupportedBuilderLibraryVersionError, BuildError, \
LambdaBuilderError


class Test_get_workflow_config(TestCase):

@parameterized.expand([
("python2.7", ),
("python3.6", )
])
def test_must_work_for_python(self, runtime):

result = _get_workflow_config(runtime)
self.assertEquals(result.language, "python")
self.assertEquals(result.dependency_manager, "pip")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "requirements.txt")

@parameterized.expand([
("nodejs6.10", ),
("nodejs8.10", ),
("nodejsX.Y", ),
("nodejs", )
])
def test_must_work_for_nodejs(self, runtime):

result = _get_workflow_config(runtime)
self.assertEquals(result.language, "nodejs")
self.assertEquals(result.dependency_manager, "npm")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "package.json")

def test_must_raise_for_unsupported_runtimes(self):

runtime = "foobar"

with self.assertRaises(UnsupportedRuntimeException) as ctx:
_get_workflow_config(runtime)

self.assertEquals(str(ctx.exception),
"'foobar' runtime is not supported")


class TestApplicationBuilder_build(TestCase):

def setUp(self):
Expand Down Expand Up @@ -158,7 +118,7 @@ def setUp(self):
"/build/dir",
"/base/dir")

@patch("samcli.lib.build.app_builder._get_workflow_config")
@patch("samcli.lib.build.app_builder.get_workflow_config")
@patch("samcli.lib.build.app_builder.osutils")
def test_must_build_in_process(self, osutils_mock, get_workflow_config_mock):
function_name = "function_name"
Expand Down Expand Up @@ -186,7 +146,7 @@ def test_must_build_in_process(self, osutils_mock, get_workflow_config_mock):
manifest_path,
runtime)

@patch("samcli.lib.build.app_builder._get_workflow_config")
@patch("samcli.lib.build.app_builder.get_workflow_config")
@patch("samcli.lib.build.app_builder.osutils")
def test_must_build_in_container(self, osutils_mock, get_workflow_config_mock):
function_name = "function_name"
Expand Down Expand Up @@ -252,6 +212,7 @@ def test_must_raise_on_error(self, lambda_builder_mock):
config_mock = Mock()
builder_instance_mock = lambda_builder_mock.return_value = Mock()
builder_instance_mock.build.side_effect = LambdaBuilderError()
self.builder._get_build_options = Mock(return_value=None)

with self.assertRaises(BuildError):
self.builder._build_function_in_process(config_mock,
Expand Down
62 changes: 62 additions & 0 deletions tests/unit/lib/build_module/test_workflow_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from unittest import TestCase
from parameterized import parameterized

from samcli.lib.build.workflow_config import get_workflow_config, UnsupportedRuntimeException


class Test_get_workflow_config(TestCase):

@parameterized.expand([
("python2.7", ),
("python3.6", )
])
def test_must_work_for_python(self, runtime):

result = get_workflow_config(runtime)
self.assertEquals(result.language, "python")
self.assertEquals(result.dependency_manager, "pip")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "requirements.txt")

@parameterized.expand([
("nodejs4.3", ),
("nodejs6.10", ),
("nodejs8.10", ),
])
def test_must_work_for_nodejs(self, runtime):

result = get_workflow_config(runtime)
self.assertEquals(result.language, "nodejs")
self.assertEquals(result.dependency_manager, "npm")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "package.json")

@parameterized.expand([
("ruby2.5", )
])
def test_must_work_for_ruby(self, runtime):
result = get_workflow_config(runtime)
self.assertEquals(result.language, "ruby")
self.assertEquals(result.dependency_manager, "bundler")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "Gemfile")

@parameterized.expand([
("go1.x", )
])
def test_must_work_for_go(self, runtime):
result = get_workflow_config(runtime)
self.assertEquals(result.language, "go")
self.assertEquals(result.dependency_manager, "modules")
self.assertEquals(result.application_framework, None)
self.assertEquals(result.manifest_name, "go.mod")

def test_must_raise_for_unsupported_runtimes(self):

runtime = "foobar"

with self.assertRaises(UnsupportedRuntimeException) as ctx:
get_workflow_config(runtime)

self.assertEquals(str(ctx.exception),
"'foobar' runtime is not supported")