diff --git a/requirements/base.txt b/requirements/base.txt index bb4c20f9db..928877a0dd 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -12,5 +12,5 @@ dateparser~=0.7 python-dateutil~=2.6 pathlib2~=2.3.2; python_version<"3.4" requests==2.20.1 -aws_lambda_builders==0.1.0 +aws_lambda_builders==0.2.0 serverlessrepo==0.1.5 diff --git a/samcli/lib/build/workflow_config.py b/samcli/lib/build/workflow_config.py index 055b0c2240..fd901290a3 100644 --- a/samcli/lib/build/workflow_config.py +++ b/samcli/lib/build/workflow_config.py @@ -41,6 +41,13 @@ manifest_name="build.gradle", executable_search_paths=None) +JAVA_MAVEN_CONFIG = CONFIG( + language="java", + dependency_manager="maven", + application_framework=None, + manifest_name="pom.xml", + executable_search_paths=None) + class UnsupportedRuntimeException(Exception): pass @@ -83,7 +90,8 @@ def get_workflow_config(runtime, code_dir, project_dir): # manifest "java8": ManifestWorkflowSelector([ # Gradle builder needs custom executable paths to find `gradlew` binary - JAVA_GRADLE_CONFIG._replace(executable_search_paths=[code_dir, project_dir]) + JAVA_GRADLE_CONFIG._replace(executable_search_paths=[code_dir, project_dir]), + JAVA_MAVEN_CONFIG ]), } diff --git a/samcli/local/common/runtime_template.py b/samcli/local/common/runtime_template.py index 04672af324..bcfaa20a55 100644 --- a/samcli/local/common/runtime_template.py +++ b/samcli/local/common/runtime_template.py @@ -65,7 +65,7 @@ "runtimes": ["java8"], "dependency_manager": "maven", "init_location": os.path.join(_templates, "cookiecutter-aws-sam-hello-java-maven"), - "build": False + "build": True }, { "runtimes": ["java8"], diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/README.md b/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/README.md index 91899e4c3d..0d52d9f69c 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/README.md +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/README.md @@ -3,20 +3,19 @@ This is a sample template for {{ cookiecutter.project_name }} - Below is a brief explanation of what we have generated for you: ```bash -. -├── HelloWorldFunction -│   ├── pom.xml <-- Java dependencies -│   └── src -│   ├── main -│   │   └── java -│   │   └── helloworld <-- Source code for a lambda function -│   │   ├── App.java <-- Lambda function code -│   │   └── GatewayResponse.java <-- POJO for API Gateway Responses object -│   └── test <-- Unit tests -│   └── java -│   └── helloworld -│   └── AppTest.java -├── README.md <-- This instructions file +├── README.md <-- This instructions file +├── HelloWorldFunction <-- Source for HelloWorldFunction Lambda Function +│ ├── pom.xml <-- Java dependencies +│ └── src +│ ├── main +│ │ └── java +│ │ └── helloworld +│ │ ├── App.java <-- Lambda function code +│ │ └── GatewayResponse.java <-- POJO for API Gateway Responses object +│ └── test <-- Unit tests +│ └── java +│ └── helloworld +│ └── AppTest.java └── template.yaml ``` @@ -31,11 +30,16 @@ This is a sample template for {{ cookiecutter.project_name }} - Below is a brief ### Installing dependencies -We use `maven` to install our dependencies and package our application into a JAR file: +```bash +sam build +``` + +You can also build on a Lambda like environment by using ```bash -mvn package +sam build --use-container ``` + ### Local development **Invoking function locally through local API Gateway** @@ -109,6 +113,7 @@ aws cloudformation describe-stacks \ We use `JUnit` for testing our code and you can simply run the following command to run our tests: ```bash +cd HelloWorldFunction mvn test ``` diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/template.yaml b/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/template.yaml index 080a1e6e84..cbd079179a 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/template.yaml +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-java-maven/{{cookiecutter.project_name}}/template.yaml @@ -14,7 +14,7 @@ Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: - CodeUri: target/HelloWorld-1.0.jar + CodeUri: HelloWorldFunction Handler: helloworld.App::handleRequest Runtime: java8 Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index b8b5183968..3816e2624e 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -240,22 +240,26 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, self.assertTrue(any([True if self.EXPECTED_RUBY_GEM in gem else False for gem in os.listdir(str(gem_path))])) -class TestBuildCommand_JavaGradle(BuildIntegBase): +class TestBuildCommand_Java(BuildIntegBase): - EXPECTED_FILES_PROJECT_MANIFEST = {'aws', 'lib', "META-INF"} + EXPECTED_FILES_PROJECT_MANIFEST_GRADLE = {'aws', 'lib', "META-INF"} + EXPECTED_FILES_PROJECT_MANIFEST_MAVEN = {'aws', 'lib'} EXPECTED_DEPENDENCIES = {'annotations-2.1.0.jar', "aws-lambda-java-core-1.1.0.jar"} FUNCTION_LOGICAL_ID = "Function" USING_GRADLE_PATH = os.path.join("Java", "gradle") USING_GRADLEW_PATH = os.path.join("Java", "gradlew") + USING_MAVEN_PATH = str(Path('Java', 'maven')) @parameterized.expand([ - ("java8", USING_GRADLE_PATH, False), - ("java8", USING_GRADLEW_PATH, False), - ("java8", USING_GRADLE_PATH, "use_container"), - ("java8", USING_GRADLEW_PATH, "use_container"), + ("java8", USING_GRADLE_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE, False), + ("java8", USING_GRADLEW_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE, False), + ("java8", USING_MAVEN_PATH, EXPECTED_FILES_PROJECT_MANIFEST_MAVEN, False), + ("java8", USING_GRADLE_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE, "use_container"), + ("java8", USING_GRADLEW_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE, "use_container"), + ("java8", USING_MAVEN_PATH, EXPECTED_FILES_PROJECT_MANIFEST_MAVEN, "use_container") ]) - def test_with_gradle(self, runtime, code_path, use_container): + def test_with_building_java(self, runtime, code_path, expected_files, use_container): overrides = {"Runtime": runtime, "CodeUri": code_path, "Handler": "aws.example.Hello::myHandler"} cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) @@ -265,7 +269,7 @@ def test_with_gradle(self, runtime, code_path, use_container): process.wait() self._verify_built_artifact(self.default_build_dir, self.FUNCTION_LOGICAL_ID, - self.EXPECTED_FILES_PROJECT_MANIFEST, self.EXPECTED_DEPENDENCIES) + expected_files, self.EXPECTED_DEPENDENCIES) self._verify_resource_property(str(self.built_template), "OtherRelativePathResource", diff --git a/tests/integration/testdata/buildcmd/Java/maven/pom.xml b/tests/integration/testdata/buildcmd/Java/maven/pom.xml new file mode 100644 index 0000000000..d8d6558a12 --- /dev/null +++ b/tests/integration/testdata/buildcmd/Java/maven/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + helloworld + HelloWorld + 1.0 + jar + A sample Hello World created for SAM CLI. + + 1.8 + 1.8 + + + + + com.amazonaws + aws-lambda-java-core + 1.1.0 + + + software.amazon.awssdk + annotations + 2.1.0 + + + \ No newline at end of file diff --git a/tests/integration/testdata/buildcmd/Java/maven/src/main/java/aws/example/Hello.java b/tests/integration/testdata/buildcmd/Java/maven/src/main/java/aws/example/Hello.java new file mode 100644 index 0000000000..9f6e4084e9 --- /dev/null +++ b/tests/integration/testdata/buildcmd/Java/maven/src/main/java/aws/example/Hello.java @@ -0,0 +1,13 @@ +package aws.example; + + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.LambdaLogger; + +public class Hello { + public String myHandler(Context context) { + LambdaLogger logger = context.getLogger(); + logger.log("Function Invoked\n"); + return "Hello World"; + } +} \ No newline at end of file diff --git a/tests/unit/lib/build_module/test_workflow_config.py b/tests/unit/lib/build_module/test_workflow_config.py index 0722ea8a45..86cf41da14 100644 --- a/tests/unit/lib/build_module/test_workflow_config.py +++ b/tests/unit/lib/build_module/test_workflow_config.py @@ -50,20 +50,24 @@ def test_must_work_for_ruby(self, runtime): self.assertIsNone(result.executable_search_paths) @parameterized.expand([ - ("java8", "build.gradle") + ("java8", "build.gradle", "gradle"), + ("java8", "pom.xml", "maven") ]) @patch("samcli.lib.build.workflow_config.os") - def test_must_work_for_java(self, runtime, build_file, os_mock): - + def test_must_work_for_java(self, runtime, build_file, dep_manager, os_mock): os_mock.path.join.side_effect = lambda dirname, v: v os_mock.path.exists.side_effect = lambda v: v == build_file result = get_workflow_config(runtime, self.code_dir, self.project_dir) self.assertEquals(result.language, "java") - self.assertEquals(result.dependency_manager, "gradle") + self.assertEquals(result.dependency_manager, dep_manager) self.assertEquals(result.application_framework, None) - self.assertEquals(result.manifest_name, "build.gradle") - self.assertEquals(result.executable_search_paths, [self.code_dir, self.project_dir]) + self.assertEquals(result.manifest_name, build_file) + + if dep_manager == "gradle": + self.assertEquals(result.executable_search_paths, [self.code_dir, self.project_dir]) + else: + self.assertIsNone(result.executable_search_paths) @parameterized.expand([ ("java8", "unknown.manifest")