From dfbd9030444036bbf186d1929c7528227f800ccf Mon Sep 17 00:00:00 2001 From: Alex Wood Date: Mon, 17 Dec 2018 16:03:34 -0800 Subject: [PATCH 1/9] Add Ruby to Supported Runtime Enum --- samcli/lib/build/app_builder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samcli/lib/build/app_builder.py b/samcli/lib/build/app_builder.py index d1482c7f6a..2a15fa1ef4 100644 --- a/samcli/lib/build/app_builder.py +++ b/samcli/lib/build/app_builder.py @@ -57,6 +57,12 @@ def _get_workflow_config(runtime): 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)) From b2cdfdec2ae98b9eeed951c91999dcaef26b4edc Mon Sep 17 00:00:00 2001 From: Alex Wood Date: Mon, 17 Dec 2018 16:16:07 -0800 Subject: [PATCH 2/9] Ruby Project Template Changes WIP: Unit tests may have a notion of a central Gemfile that isn't compatible with per-function Gemfile pattern that `sam build` expects. --- .../cookiecutter-aws-sam-hello-ruby/README.md | 2 +- .../{{cookiecutter.project_name}}/Gemfile | 3 - .../{{cookiecutter.project_name}}/README.md | 29 ++----- .../hello_world/Gemfile | 8 ++ .../hello_world/app.rb | 2 +- .../template.yaml | 2 +- .../tests/unit/test_handler.rb | 83 +++++++++---------- 7 files changed, 57 insertions(+), 72 deletions(-) delete mode 100644 samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile create mode 100644 samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/README.md b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/README.md index f13c3e7088..1fee2ad2f0 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/README.md +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/README.md @@ -1,6 +1,6 @@ # Cookiecutter SAM for Ruby Lambda functions -This is a [Cookiecutter](https://github.com/audreyr/cookiecutter) template to create a Serverless Hello World App based on Serverless Application Model (SAM) and Python. +This is a [Cookiecutter](https://github.com/audreyr/cookiecutter) template to create a Serverless Hello World App based on Serverless Application Model (SAM) and Ruby. ## Recommendations diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile deleted file mode 100644 index 3abba1b8b3..0000000000 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source "https://rubygems.org" - -gem "httparty" diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md index 919fa08da2..2dc5c92f09 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md @@ -7,7 +7,7 @@ This is a sample template for {{ cookiecutter.project_name }} - Below is a brief ├── README.md <-- This instructions file ├── hello_world <-- Source code for a lambda function │ ├── app.rb <-- Lambda function code -├── Gemfile <-- Ruby dependencies +│ ├── Gemfile <-- Ruby dependencies ├── template.yaml <-- SAM template └── tests <-- Unit tests └── unit @@ -31,27 +31,16 @@ Setup Ruby Version Manager from [Ruby Version Manager](http://rvm.io/) Run following commands ```bash -rvm install ruby-2.5.0 -rvm use ruby-2.5.0 -rvm --default use 2.5.0 +rvm install ruby-2.5.3 +rvm use ruby-2.5.3 +rvm --default use 2.5.3 ``` - ### Installing dependencies -```sam-app``` comes with a Gemfile that defines the requirements and manages installing them. - -```bash -gem install bundler -bundle install -bundle install --deployment --path hello_world/vendor/bundle -``` - -* Step 1 installs ```bundler```which provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed. -* Step 2 creates a Gemfile.lock that locks down the versions and creates the full dependency closure. -* Step 3 installs the gems to ```hello_world/vendor/bundle```. +```sam-app``` comes with a Gemfile that defines the requirements and manages installing them. The `sam build` command will install the dependencies in your function Gemfile and vendor it for deployment. -**NOTE:** As you change your dependencies during development you'll need to make sure these steps are repeated in order to execute your Lambda and/or API Gateway locally. +**NOTE:** As you change your dependencies during development you'll need to run `sam build` again in order to execute your Lambda and/or API Gateway locally. ### Local development @@ -124,12 +113,10 @@ aws cloudformation describe-stacks \ ## Testing -We use [Mocha](http://gofreerange.com/mocha/docs) for testing our code and you can install it using gem: ``gem install mocha`` - -Next, we run our initial unit tests: +Run our initial unit tests: ```bash -ruby tests/unit/test_hello.rb +ruby tests/unit/test_handler.rb ``` **NOTE**: It is recommended to use a Ruby Version Manager to manage, and work with multiple ruby environments from interpreters to sets of gems diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile new file mode 100644 index 0000000000..b566789dfb --- /dev/null +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +gem "httparty" + +group :test do + gem "test-unit" + gem "mocha" +end diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb index 89f645d0ff..4224cb08d7 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb @@ -73,7 +73,7 @@ def lambda_handler(event:, context:) raise error end - return { + { :statusCode => response.code, :body => { :message => "Hello World!", diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/template.yaml b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/template.yaml index 5617c03472..c1bcb7ba61 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/template.yaml +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/template.yaml @@ -4,7 +4,7 @@ Description: > {{ cookiecutter.project_name }} Sample SAM Template for {{ cookiecutter.project_name }} - + # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb index 8ae3a2595e..d496ec1866 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb @@ -1,12 +1,12 @@ require 'json' require 'test/unit' require 'mocha/test_unit' + require_relative '../../hello_world/app' class HelloWorldTest < Test::Unit::TestCase - - def setup - @event = { + def event + { body: 'eyJ0ZXN0IjoiYm9keSJ9', resource: '/{proxy+}', path: '/path/to/resource', @@ -22,24 +22,24 @@ def setup baz: 'qux' }, headers: { - Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', - Accept-Encoding: 'gzip, deflate, sdch', - Accept-Language: 'en-US,en;q=0.8', - Cache-Control: 'max-age=0', - CloudFront-Forwarded-Proto: 'https', - CloudFront-Is-Desktop-Viewer: 'true', - CloudFront-Is-Mobile-Viewer: 'false', - CloudFront-Is-SmartTV-Viewer: 'false', - CloudFront-Is-Tablet-Viewer: 'false', - CloudFront-Viewer-Country: 'US', - Host: '1234567890.execute-api.us-east-1.amazonaws.com', - Upgrade-Insecure-Requests: '1', - User-Agent: 'Custom User Agent String', - Via: '1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)', - X-Amz-Cf-Id: 'cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==', - X-Forwarded-For: '127.0.0.1, 127.0.0.2', - X-Forwarded-Port: '443', - X-Forwarded-Proto: 'https' + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'Accept-Encoding' => 'gzip, deflate, sdch', + 'Accept-Language' => 'en-US,en;q=0.8', + 'Cache-Control' => 'max-age=0', + 'CloudFront-Forwarded-Proto' => 'https', + 'CloudFront-Is-Desktop-Viewer' => 'true', + 'CloudFront-Is-Mobile-Viewer' => 'false', + 'CloudFront-Is-SmartTV-Viewer' => 'false', + 'CloudFront-Is-Tablet-Viewer' => 'false', + 'CloudFront-Viewer-Country' => 'US', + 'Host' => '1234567890.execute-api.us-east-1.amazonaws.com', + 'Upgrade-Insecure-Requests' => '1', + 'User-Agent' => 'Custom User Agent String', + 'Via' => '1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)', + 'X-Amz-Cf-Id' => 'cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==', + 'X-Forwarded-For' => '127.0.0.1, 127.0.0.2', + 'X-Forwarded-Port' => '443', + 'X-Forwarded-Proto' => 'https' }, requestContext: { accountId: '123456789012', @@ -49,17 +49,17 @@ def setup requestTime: '09/Apr/2015:12:34:56 +0000', requestTimeEpoch: 1428582896000, identity: { - cognitoIdentityPoolId: "null", - accountId: "null", - cognitoIdentityId: "null", - caller: "null", - accessKey: "null", + cognitoIdentityPoolId: 'null', + accountId: 'null', + cognitoIdentityId: 'null', + caller: 'null', + accessKey: 'null', sourceIp: '127.0.0.1', - cognitoAuthenticationType: "null", - cognitoAuthenticationProvider: "null", - userArn: "null", + cognitoAuthenticationType: 'null', + cognitoAuthenticationProvider: 'null', + userArn: 'null', userAgent: 'Custom User Agent String', - user: "null" + user: 'null' }, path: '/prod/path/to/resource', resourcePath: '/{proxy+}', @@ -68,24 +68,17 @@ def setup protocol: 'HTTP/1.1' } } + end - @mock_response = { - :statusCode => 200, - :body => { - message: "Hello World!", - location: "1.1.1.1" - }.to_json - } - + def mock_response + Object.new.tap do |mock| + mock.expects(:code).returns(200) + mock.expects(:body).returns('1.1.1.1') + end end def test_lambda_handler - expects(:lambda_handler).with(event:@event, context:"").returns(@mock_response) - response = lambda_handler(event:@event, context:"") - json_body = JSON.parse(response[:body]) - - assert_equal(200, response[:statusCode]) - assert_equal("Hello World!", json_body["message"]) - assert_equal("1.1.1.1", json_body["location"]) + HTTParty.expects(:get).with('http://checkip.amazonaws.com/').returns(mock_response) + assert_equal(lambda_handler(event: event, context: ''), expected_result) end end From ac35ac2cdb27a3a092e45ed2b11656739d0fcb8b Mon Sep 17 00:00:00 2001 From: Alex Wood Date: Mon, 17 Dec 2018 16:21:01 -0800 Subject: [PATCH 3/9] Tweaks Global Gemfile for tests. Gemfile in the function for use in tests. Hat tip to lauratpa and her PR #860 which is the core of this part of the change set. --- .../{{cookiecutter.project_name}}/Gemfile | 8 ++++++++ .../{{cookiecutter.project_name}}/hello_world/Gemfile | 5 ----- .../tests/unit/test_handler.rb | 10 ++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile new file mode 100644 index 0000000000..b566789dfb --- /dev/null +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +gem "httparty" + +group :test do + gem "test-unit" + gem "mocha" +end diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile index b566789dfb..3abba1b8b3 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/Gemfile @@ -1,8 +1,3 @@ source "https://rubygems.org" gem "httparty" - -group :test do - gem "test-unit" - gem "mocha" -end diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb index d496ec1866..df66b969a1 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/tests/unit/test_handler.rb @@ -77,6 +77,16 @@ def mock_response end end + def expected_result + { + statusCode: 200, + body: { + message: 'Hello World!', + location: '1.1.1.1' + }.to_json + } + end + def test_lambda_handler HTTParty.expects(:get).with('http://checkip.amazonaws.com/').returns(mock_response) assert_equal(lambda_handler(event: event, context: ''), expected_result) From ee51bb4bcf89d4190d2f5188a7053001ca9f2754 Mon Sep 17 00:00:00 2001 From: Alex Wood Date: Mon, 17 Dec 2018 16:36:41 -0800 Subject: [PATCH 4/9] Ruby Init App in Working State --- .../{{cookiecutter.project_name}}/README.md | 7 ++++--- .../{{cookiecutter.project_name}}/hello_world/app.rb | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md index 2dc5c92f09..dbff37e7db 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md @@ -7,7 +7,8 @@ This is a sample template for {{ cookiecutter.project_name }} - Below is a brief ├── README.md <-- This instructions file ├── hello_world <-- Source code for a lambda function │ ├── app.rb <-- Lambda function code -│ ├── Gemfile <-- Ruby dependencies +│ ├── Gemfile <-- Ruby function dependencies +├── Gemfile <-- Ruby test/documentation dependencies ├── template.yaml <-- SAM template └── tests <-- Unit tests └── unit @@ -124,11 +125,11 @@ ruby tests/unit/test_handler.rb ## AWS CLI commands -AWS CLI commands to package, deploy and describe outputs defined within the cloudformation stack: +AWS CLI commands to package, deploy and describe outputs defined within the cloudformation stack after building: ```bash sam package \ - --template-file template.yaml \ + --template-file .aws-sam/build/template.yaml \ --output-template-file packaged.yaml \ --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb index 4224cb08d7..963182dd7c 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/hello_world/app.rb @@ -74,10 +74,10 @@ def lambda_handler(event:, context:) end { - :statusCode => response.code, - :body => { - :message => "Hello World!", - :location => response.body + statusCode: response.code, + body: { + message: "Hello World!", + location: response.body }.to_json } end From f8988c346c869eb3868a65076b11a546f18b709f Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan Date: Wed, 19 Dec 2018 16:17:58 -0800 Subject: [PATCH 5/9] fix: add integration tests for sam build - ruby --- .../local/apigw/test_local_apigw_service.py | 2 +- tests/integration/buildcmd/test_build_cmd.py | 73 +++++++++++++++++++ .../testdata/buildcmd/Ruby/Gemfile | 3 + .../integration/testdata/buildcmd/Ruby/app.rb | 0 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/integration/testdata/buildcmd/Ruby/Gemfile create mode 100644 tests/integration/testdata/buildcmd/Ruby/app.rb diff --git a/tests/functional/local/apigw/test_local_apigw_service.py b/tests/functional/local/apigw/test_local_apigw_service.py index ce4c8016cb..96f442fc83 100644 --- a/tests/functional/local/apigw/test_local_apigw_service.py +++ b/tests/functional/local/apigw/test_local_apigw_service.py @@ -630,7 +630,7 @@ def make_service(list_of_routes, function_provider, cwd): def make_service_response(port, method, scheme, resourcePath, resolvedResourcePath, pathParameters=None, body=None, headers=None, queryParams=None, isBase64Encoded=False): - response_str = '{"httpMethod": "GET", "body": null, "resource": "/something/{event}", "requestContext": {"resourceId": "123456", "apiId": "1234567890", "resourcePath": "/something/{event}", "httpMethod": "GET", "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", "accountId": "123456789012", "stage": "prod", "identity": {"apiKey": null, "userArn": null, "cognitoAuthenticationType": null, "caller": null, "userAgent": "Custom User Agent String", "user": null, "cognitoIdentityPoolId": null, "cognitoAuthenticationProvider": null, "sourceIp": "127.0.0.1", "accountId": null}, "extendedRequestId": null, "path": "/something/{event}"}, "queryStringParameters": null, "headers": {"Host": "0.0.0.0:33651", "User-Agent": "python-requests/2.20.0", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Connection": "keep-alive"}, "pathParameters": {"event": "event1"}, "stageVariables": null, "path": "/something/event1", "isBase64Encoded": false}' # NOQA + response_str = '{"httpMethod": "GET", "body": null, "resource": "/something/{event}", "requestContext": {"resourceId": "123456", "apiId": "1234567890", "resourcePath": "/something/{event}", "httpMethod": "GET", "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", "accountId": "123456789012", "stage": "prod", "identity": {"apiKey": null, "userArn": null, "cognitoAuthenticationType": null, "caller": null, "userAgent": "Custom User Agent String", "user": null, "cognitoIdentityPoolId": null, "cognitoAuthenticationProvider": null, "sourceIp": "127.0.0.1", "accountId": null}, "extendedRequestId": null, "path": "/something/{event}"}, "queryStringParameters": null, "headers": {"Host": "0.0.0.0:33651", "User-Agent": "python-requests/2.20.1", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Connection": "keep-alive"}, "pathParameters": {"event": "event1"}, "stageVariables": null, "path": "/something/event1", "isBase64Encoded": false}' # NOQA response = json.loads(response_str) if body: diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index fe7c3d30a4..04330471af 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -4,6 +4,7 @@ import json import logging +from pathlib import Path from parameterized import parameterized from samcli.yamlhelper import yaml_parse @@ -192,3 +193,75 @@ def _verify_resource_property(self, template_path, logical_id, property, expecte 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): + + EXPECTED_FILES_GLOBAL_MANIFEST = set() + EXPECTED_FILES_PROJECT_MANIFEST = {'app.rb'} + EXPECTED_RUBY_GEM = 'httparty' + + FUNCTION_LOGICAL_ID = "Function" + + @parameterized.expand([ + ("ruby2.5", False), + ("ruby2.5", "use_container") + ]) + def test_with_default_gemfile(self, runtime, use_container): + overrides = {"Runtime": runtime, "CodeUri": "Ruby"} + cmdlist = self.get_command_list(use_container=use_container, + parameter_overrides=overrides) + + LOG.info("Running Command: {}".format(cmdlist)) + process = subprocess.Popen(cmdlist, cwd=self.working_dir) + process.wait() + + self._verify_built_artifact(self.default_build_dir, self.FUNCTION_LOGICAL_ID, + self.EXPECTED_FILES_PROJECT_MANIFEST, self.EXPECTED_RUBY_GEM) + + self._verify_resource_property(str(self.built_template), + "OtherRelativePathResource", + "BodyS3Location", + os.path.relpath( + os.path.normpath(os.path.join(str(self.test_data_path), "SomeRelativePath")), + str(self.default_build_dir)) + ) + + def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, expected_modules): + + self.assertTrue(build_dir.exists(), "Build directory should be created") + + build_dir_files = os.listdir(str(build_dir)) + self.assertIn("template.yaml", build_dir_files) + self.assertIn(function_logical_id, build_dir_files) + + template_path = build_dir.joinpath("template.yaml") + resource_artifact_dir = build_dir.joinpath(function_logical_id) + + # Make sure the template has correct CodeUri for resource + self._verify_resource_property(str(template_path), + function_logical_id, + "CodeUri", + function_logical_id) + + all_artifacts = set(os.listdir(str(resource_artifact_dir))) + actual_files = all_artifacts.intersection(expected_files) + self.assertEquals(actual_files, expected_files) + + ruby_version = None + ruby_bundled_path = None + + # Walk through ruby version to get to the gem path + for dirpath, dirname, _ in os.walk(resource_artifact_dir.joinpath('vendor', 'bundle', 'ruby')): + ruby_version = dirname + ruby_bundled_path = Path(dirpath) + break + 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]) diff --git a/tests/integration/testdata/buildcmd/Ruby/Gemfile b/tests/integration/testdata/buildcmd/Ruby/Gemfile new file mode 100644 index 0000000000..e214f5af12 --- /dev/null +++ b/tests/integration/testdata/buildcmd/Ruby/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "httparty" \ No newline at end of file diff --git a/tests/integration/testdata/buildcmd/Ruby/app.rb b/tests/integration/testdata/buildcmd/Ruby/app.rb new file mode 100644 index 0000000000..e69de29bb2 From b79f2fddb60ed4e8816dabd1095629ca54700ea4 Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan Date: Thu, 20 Dec 2018 12:22:59 -0800 Subject: [PATCH 6/9] bump: version bump aws-lambda-builders to 0.0.5 --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 6681943284..ae96ed26a6 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.0 -aws_lambda_builders==0.0.4 +aws_lambda_builders==0.0.5 serverlessrepo==0.1.5 From 381a7c5fd5158c90c128263d853b78ddd423b7f0 Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan Date: Thu, 20 Dec 2018 14:11:17 -0800 Subject: [PATCH 7/9] fix: requests version pin and imports --- requirements/base.txt | 2 +- requirements/dev.txt | 1 - tests/integration/buildcmd/test_build_cmd.py | 5 ++++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index ae96ed26a6..d947ecc626 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -11,6 +11,6 @@ docker>=3.3.0 dateparser~=0.7 python-dateutil~=2.6 pathlib2~=2.3.2; python_version<"3.4" -requests~=2.20.0 +requests==2.20.1 aws_lambda_builders==0.0.5 serverlessrepo==0.1.5 diff --git a/requirements/dev.txt b/requirements/dev.txt index af480e2bf1..a920601b7c 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -10,7 +10,6 @@ pylint==1.7.2 pytest==3.0.7 py==1.4.33 mock==2.0.0 -requests==2.20.0 parameterized==0.6.1 pathlib2==2.3.2; python_version<"3.4" futures==3.2.0; python_version<"3.2.3" diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index 04330471af..06d063883a 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -4,7 +4,10 @@ import json import logging -from pathlib import Path +try: + from pathlib import Path +except ImportError: + from pathlib2 import Path from parameterized import parameterized from samcli.yamlhelper import yaml_parse From 98cf7b0156a24ced33d35a52a659a4f8237fcee8 Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan Date: Thu, 20 Dec 2018 14:29:26 -0800 Subject: [PATCH 8/9] fix: string paths on Pathlib for py2 --- tests/integration/buildcmd/test_build_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index 06d063883a..62c812a42a 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -255,7 +255,7 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, ruby_bundled_path = None # Walk through ruby version to get to the gem path - for dirpath, dirname, _ in os.walk(resource_artifact_dir.joinpath('vendor', 'bundle', 'ruby')): + for dirpath, dirname, _ in os.walk(str(resource_artifact_dir.joinpath('vendor', 'bundle', 'ruby'))): ruby_version = dirname ruby_bundled_path = Path(dirpath) break From 24a3aeda3ea846ce93681cb3cfb328fbdc439d72 Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan Date: Fri, 21 Dec 2018 09:11:07 -0800 Subject: [PATCH 9/9] fix: README - add references to build --- .../{{cookiecutter.project_name}}/README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md index dbff37e7db..f220a6b515 100644 --- a/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md +++ b/samcli/local/init/templates/cookiecutter-aws-sam-hello-ruby/{{cookiecutter.project_name}}/README.md @@ -37,10 +37,21 @@ rvm use ruby-2.5.3 rvm --default use 2.5.3 ``` -### Installing dependencies +### Building the Project ```sam-app``` comes with a Gemfile that defines the requirements and manages installing them. The `sam build` command will install the dependencies in your function Gemfile and vendor it for deployment. +``` +sam build +``` + +If your dependencies contain native modules that need to be compiled specifically for the operating system running on AWS Lambda, use this command to build inside a Lambda-like Docker container instead: + +``` +sam build --use-container +``` +By default, this command writes built artifacts to .aws-sam/build folder. + **NOTE:** As you change your dependencies during development you'll need to run `sam build` again in order to execute your Lambda and/or API Gateway locally. ### Local development @@ -129,7 +140,7 @@ AWS CLI commands to package, deploy and describe outputs defined within the clou ```bash sam package \ - --template-file .aws-sam/build/template.yaml \ + --template-file template.yaml \ --output-template-file packaged.yaml \ --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME