diff --git a/aws_lambda_builders/__init__.py b/aws_lambda_builders/__init__.py index 20063ad1b..f6d3af2b1 100644 --- a/aws_lambda_builders/__init__.py +++ b/aws_lambda_builders/__init__.py @@ -1,5 +1,5 @@ """ AWS Lambda Builder Library """ -__version__ = '0.2.1' -RPC_PROTOCOL_VERSION = "0.2" +__version__ = '0.3.0' +RPC_PROTOCOL_VERSION = "0.3" diff --git a/aws_lambda_builders/__main__.py b/aws_lambda_builders/__main__.py index bc01b46e7..b5fe009bc 100644 --- a/aws_lambda_builders/__main__.py +++ b/aws_lambda_builders/__main__.py @@ -133,7 +133,8 @@ def main(): # pylint: disable=too-many-statements executable_search_paths=params.get('executable_search_paths', None), runtime=params["runtime"], optimizations=params["optimizations"], - options=params["options"]) + options=params["options"], + mode=params.get('mode', None)) # Return a success response response = _success_response(request_id, artifacts_dir) diff --git a/aws_lambda_builders/builder.py b/aws_lambda_builders/builder.py index 1012a5d02..9518be6fd 100644 --- a/aws_lambda_builders/builder.py +++ b/aws_lambda_builders/builder.py @@ -56,7 +56,7 @@ def __init__(self, language, dependency_manager, application_framework, supporte LOG.debug("Found workflow '%s' to support capabilities '%s'", self.selected_workflow_cls.NAME, self.capability) def build(self, source_dir, artifacts_dir, scratch_dir, manifest_path, - runtime=None, optimizations=None, options=None, executable_search_paths=None): + runtime=None, optimizations=None, options=None, executable_search_paths=None, mode=None): """ Actually build the code by running workflows @@ -93,6 +93,10 @@ def build(self, source_dir, artifacts_dir, scratch_dir, manifest_path, :type executable_search_paths: list :param executable_search_paths: Additional list of paths to search for executables required by the workflow. + + :type mode: str + :param mode: + Optional, Mode the build should produce """ if not os.path.exists(scratch_dir): @@ -105,7 +109,8 @@ def build(self, source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=runtime, optimizations=optimizations, options=options, - executable_search_paths=executable_search_paths) + executable_search_paths=executable_search_paths, + mode=mode) return workflow.run() diff --git a/aws_lambda_builders/workflow.py b/aws_lambda_builders/workflow.py index 8a6032602..0c3541973 100644 --- a/aws_lambda_builders/workflow.py +++ b/aws_lambda_builders/workflow.py @@ -25,6 +25,12 @@ Capability = namedtuple('Capability', ["language", "dependency_manager", "application_framework"]) +class BuildMode(object): + + DEBUG = "debug" + RELEASE = "release" + + # TODO: Move sanitize out to its own class. def sanitize(func): """ @@ -119,7 +125,8 @@ def __init__(self, runtime=None, executable_search_paths=None, optimizations=None, - options=None): + options=None, + mode=BuildMode.RELEASE): """ Initialize the builder with given arguments. These arguments together form the "public API" that each build action must support at the minimum. @@ -157,6 +164,10 @@ def __init__(self, :type executable_search_paths: list :param executable_search_paths: Optional, Additional list of paths to search for executables required by the workflow. + + :type mode: str + :param mode: + Optional, Mode the build should produce """ self.source_dir = source_dir @@ -167,6 +178,7 @@ def __init__(self, self.optimizations = optimizations self.options = options self.executable_search_paths = executable_search_paths + self.mode = mode # Actions are registered by the subclasses as they seem fit self.actions = [] diff --git a/aws_lambda_builders/workflows/dotnet_clipackage/actions.py b/aws_lambda_builders/workflows/dotnet_clipackage/actions.py index 9b49b6fb4..0d67eaed1 100644 --- a/aws_lambda_builders/workflows/dotnet_clipackage/actions.py +++ b/aws_lambda_builders/workflows/dotnet_clipackage/actions.py @@ -6,6 +6,7 @@ import logging from aws_lambda_builders.actions import BaseAction, Purpose, ActionFailedError +from aws_lambda_builders.workflow import BuildMode from .utils import OSUtils from .dotnetcli import DotnetCLIExecutionError @@ -49,12 +50,13 @@ class RunPackageAction(BaseAction): DESCRIPTION = "Execute the `dotnet lambda package` command." PURPOSE = Purpose.COMPILE_SOURCE - def __init__(self, source_dir, subprocess_dotnet, artifacts_dir, options, os_utils=None): + def __init__(self, source_dir, subprocess_dotnet, artifacts_dir, options, mode, os_utils=None): super(RunPackageAction, self).__init__() self.source_dir = source_dir self.subprocess_dotnet = subprocess_dotnet self.artifacts_dir = artifacts_dir self.options = options + self.mode = mode self.os_utils = os_utils if os_utils else OSUtils() def execute(self): @@ -66,6 +68,10 @@ def execute(self): arguments = ['lambda', 'package', '--output-package', zipfullpath] + if self.mode and self.mode.lower() == BuildMode.DEBUG: + LOG.debug("Debug build requested: Setting configuration to Debug") + arguments += ["--configuration", "Debug"] + if self.options is not None: for key in self.options: if str.startswith(key, "-"): diff --git a/aws_lambda_builders/workflows/dotnet_clipackage/workflow.py b/aws_lambda_builders/workflows/dotnet_clipackage/workflow.py index 895dc46b6..0c92462af 100644 --- a/aws_lambda_builders/workflows/dotnet_clipackage/workflow.py +++ b/aws_lambda_builders/workflows/dotnet_clipackage/workflow.py @@ -26,6 +26,7 @@ def __init__(self, scratch_dir, manifest_path, runtime=None, + mode=None, **kwargs): super(DotnetCliPackageWorkflow, self).__init__( @@ -34,13 +35,18 @@ def __init__(self, scratch_dir, manifest_path, runtime=runtime, + mode=mode, **kwargs) options = kwargs["options"] if "options" in kwargs else {} subprocess_dotnetcli = SubprocessDotnetCLI(os_utils=OSUtils()) dotnetcli_install = GlobalToolInstallAction(subprocess_dotnet=subprocess_dotnetcli) - dotnetcli_deployment = RunPackageAction(source_dir, subprocess_dotnet=subprocess_dotnetcli, artifacts_dir=artifacts_dir, options=options) + dotnetcli_deployment = RunPackageAction(source_dir, + subprocess_dotnet=subprocess_dotnetcli, + artifacts_dir=artifacts_dir, + options=options, + mode=mode) self.actions = [ dotnetcli_install, dotnetcli_deployment, diff --git a/aws_lambda_builders/workflows/java_gradle/gradle_validator.py b/aws_lambda_builders/workflows/java_gradle/gradle_validator.py index 3350baa84..38165ef86 100644 --- a/aws_lambda_builders/workflows/java_gradle/gradle_validator.py +++ b/aws_lambda_builders/workflows/java_gradle/gradle_validator.py @@ -43,7 +43,7 @@ def validated_binary_path(self): def _get_major_version(self, gradle_path): vs = self._get_jvm_string(gradle_path) if vs: - m = re.search(r'JVM:\s+(\d.*)', vs) + m = re.search(r'JVM:\s+([\d\.]+)', vs) version = m.group(1).split('.') # For Java 8 or earlier, version strings begin with 1.{Major Version} if version[0] == '1': diff --git a/aws_lambda_builders/workflows/java_maven/maven_validator.py b/aws_lambda_builders/workflows/java_maven/maven_validator.py index 783d9dc8f..86eab63b1 100644 --- a/aws_lambda_builders/workflows/java_maven/maven_validator.py +++ b/aws_lambda_builders/workflows/java_maven/maven_validator.py @@ -43,7 +43,7 @@ def validated_binary_path(self): def _get_major_version(self, maven_path): vs = self._get_jvm_string(maven_path) if vs: - m = re.search(r'Java version:\s+(\d.*)', vs) + m = re.search(r'Java version:\s+([\d\.]+)', vs) version = m.group(1).split('.') # For Java 8 or earlier, version strings begin with 1.{Major Version} if version[0] == '1': diff --git a/tests/unit/test_builder.py b/tests/unit/test_builder.py index f5f7051b2..fa4b05603 100644 --- a/tests/unit/test_builder.py +++ b/tests/unit/test_builder.py @@ -79,10 +79,11 @@ def __init__(self, runtime=None, optimizations=None, options=None, - executable_search_paths=None): + executable_search_paths=None, + mode=None): super(MyWorkflow, self).__init__(source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=runtime, optimizations=optimizations, options=options, - executable_search_paths=executable_search_paths) + executable_search_paths=executable_search_paths, mode=mode) # Don't load any other workflows. The above class declaration will automatically load the workflow into registry builder = LambdaBuilder(self.lang, self.lang_framework, self.app_framework, supported_workflows=[]) @@ -121,11 +122,11 @@ def test_with_mocks(self, scratch_dir_exists, get_workflow_mock, importlib_mock, builder.build("source_dir", "artifacts_dir", "scratch_dir", "manifest_path", runtime="runtime", optimizations="optimizations", options="options", - executable_search_paths="executable_search_paths") + executable_search_paths="executable_search_paths", mode=None) workflow_cls.assert_called_with("source_dir", "artifacts_dir", "scratch_dir", "manifest_path", runtime="runtime", optimizations="optimizations", options="options", - executable_search_paths="executable_search_paths") + executable_search_paths="executable_search_paths", mode=None) workflow_instance.run.assert_called_once() os_mock.path.exists.assert_called_once_with("scratch_dir") if scratch_dir_exists: diff --git a/tests/unit/workflows/dotnet_clipackage/test_actions.py b/tests/unit/workflows/dotnet_clipackage/test_actions.py index a5e2c32e4..17d4edc59 100644 --- a/tests/unit/workflows/dotnet_clipackage/test_actions.py +++ b/tests/unit/workflows/dotnet_clipackage/test_actions.py @@ -14,16 +14,15 @@ class TestGlobalToolInstallAction(TestCase): def setUp(self, MockSubprocessDotnetCLI): self.subprocess_dotnet = MockSubprocessDotnetCLI.return_value - def test_global_tool_install(self): + def tearDown(self): self.subprocess_dotnet.reset_mock() + def test_global_tool_install(self): action = GlobalToolInstallAction(self.subprocess_dotnet) action.execute() self.subprocess_dotnet.run.assert_called_once_with(['tool', 'install', '-g', 'Amazon.Lambda.Tools']) def test_global_tool_update(self): - self.subprocess_dotnet.reset_mock() - self.subprocess_dotnet.run.side_effect = [DotnetCLIExecutionError(message="Already Installed"), None] action = GlobalToolInstallAction(self.subprocess_dotnet) action.execute() @@ -31,8 +30,6 @@ def test_global_tool_update(self): self.subprocess_dotnet.run.assert_any_call(['tool', 'update', '-g', 'Amazon.Lambda.Tools']) def test_global_tool_update_failed(self): - self.subprocess_dotnet.reset_mock() - self.subprocess_dotnet.run.side_effect = [DotnetCLIExecutionError(message="Already Installed"), DotnetCLIExecutionError(message="Updated Failed")] action = GlobalToolInstallAction(self.subprocess_dotnet) @@ -50,27 +47,28 @@ def setUp(self, MockSubprocessDotnetCLI, MockOSUtils): self.artifacts_dir = os.path.join('/artifacts_dir') self.scratch_dir = os.path.join('/scratch_dir') - def test_build_package(self): + def tearDown(self): self.subprocess_dotnet.reset_mock() + def test_build_package(self): + mode = "Release" + options = {} - action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, self.os_utils) + action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, mode, + self.os_utils) action.execute() - if platform.system().lower() == 'windows': - zipFilePath = '/artifacts_dir\\source_dir.zip' - else: - zipFilePath = '/artifacts_dir/source_dir.zip' + zipFilePath = os.path.join('/', 'artifacts_dir', 'source_dir.zip') self.subprocess_dotnet.run.assert_called_once_with(['lambda', 'package', '--output-package', zipFilePath], cwd='/source_dir') def test_build_package_arguments(self): - self.subprocess_dotnet.reset_mock() - + mode = "Release" options = {"--framework": "netcoreapp2.1"} - action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, self.os_utils) + action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, mode, + self.os_utils) action.execute() @@ -84,10 +82,25 @@ def test_build_package_arguments(self): cwd='/source_dir') def test_build_error(self): - self.subprocess_dotnet.reset_mock() + mode = "Release" self.subprocess_dotnet.run.side_effect = DotnetCLIExecutionError(message="Failed Package") options = {} - action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, self.os_utils) + action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, mode, + self.os_utils) self.assertRaises(ActionFailedError, action.execute) + + def test_debug_configuration_set(self): + mode = "Debug" + options = None + action = RunPackageAction(self.source_dir, self.subprocess_dotnet, self.artifacts_dir, options, mode, + self.os_utils) + + zipFilePath = os.path.join('/', 'artifacts_dir', 'source_dir.zip') + + action.execute() + + self.subprocess_dotnet.run.assert_called_once_with( + ['lambda', 'package', '--output-package', zipFilePath, '--configuration', 'Debug'], + cwd='/source_dir') diff --git a/tests/unit/workflows/java_gradle/test_gradle_validator.py b/tests/unit/workflows/java_gradle/test_gradle_validator.py index cdadf52fa..03755de79 100644 --- a/tests/unit/workflows/java_gradle/test_gradle_validator.py +++ b/tests/unit/workflows/java_gradle/test_gradle_validator.py @@ -30,7 +30,9 @@ def setUp(self, MockOSUtils): @parameterized.expand([ '1.7.0', '1.8.9', - '11.0.0' + '11.0.0', + '12 (Fluff)', + '12' ]) def test_accepts_any_jvm_mv(self, version): version_string = ('JVM: %s' % version).encode() diff --git a/tests/unit/workflows/java_maven/test_maven_validator.py b/tests/unit/workflows/java_maven/test_maven_validator.py index 0fae44764..7cbd3254d 100644 --- a/tests/unit/workflows/java_maven/test_maven_validator.py +++ b/tests/unit/workflows/java_maven/test_maven_validator.py @@ -39,6 +39,16 @@ def test_accepts_any_jvm_mv(self, version): self.assertTrue(validator.validate(maven_path=self.maven_path)) self.assertEqual(validator.validated_binary_path, self.maven_path) + @parameterized.expand([ + '12' + ]) + def test_accepts_major_version_only_jvm_mv(self, version): + version_string = ('Java version: %s, vendor: Oracle Corporation' % version).encode() + self.mock_os_utils.popen.side_effect = [FakePopen(stdout=version_string)] + validator = MavenValidator(os_utils=self.mock_os_utils) + self.assertTrue(validator.validate(maven_path=self.maven_path)) + self.assertEqual(validator.validated_binary_path, self.maven_path) + def test_emits_warning_when_jvm_mv_greater_than_8(self): version_string = 'Java version: 10.0.1, vendor: Oracle Corporation'.encode() self.mock_os_utils.popen.side_effect = [FakePopen(stdout=version_string)]