From cfacdf592475f30d264e44e57f2ab527376d8b9b Mon Sep 17 00:00:00 2001 From: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:10:47 -0700 Subject: [PATCH 1/7] chore: remove deprecated runtime dotnetcore3.1 (#5091) * chore: remove deprecated runtime dotnetcore3.1 * apply pr comments --- .gitignore | 6 --- designs/build_debug_artifacts.md | 2 +- designs/sam_build_cmd.md | 2 +- samcli/commands/build/command.py | 2 +- samcli/commands/init/init_templates.py | 8 ++-- samcli/lib/build/constants.py | 1 + samcli/lib/build/workflow_config.py | 1 - samcli/lib/init/local_manifest.json | 2 +- .../cookiecutter.json | 2 +- .../src/HelloWorld/HelloWorld.csproj | 4 -- .../HelloWorld/aws-lambda-tools-defaults.json | 3 -- .../template.yaml | 4 +- .../HelloWorld.Test/HelloWorld.Tests.csproj | 4 +- samcli/lib/utils/architecture.py | 1 - samcli/local/common/runtime_template.py | 8 ++-- samcli/local/docker/lambda_debug_settings.py | 4 -- samcli/local/docker/lambda_image.py | 3 +- tests/integration/buildcmd/test_build_cmd.py | 35 ++------------- .../buildcmd/Dotnetcore3.1/HelloWorld.csproj | 16 ------- .../buildcmd/Dotnetcore3.1/Program.cs | 44 ------------------- .../aws-lambda-tools-defaults.json | 19 -------- .../inprocess/dotnet/STS/STS.csproj | 2 +- .../credential_tests/inprocess/template.yaml | 2 +- tests/unit/commands/init/test_cli.py | 12 +++-- tests/unit/commands/init/test_manifest.json | 4 +- .../unit/lib/build_module/test_app_builder.py | 4 +- .../lib/build_module/test_build_strategy.py | 2 +- .../lib/build_module/test_workflow_config.py | 2 +- tests/unit/lib/utils/test_architecture.py | 2 +- .../local/docker/test_lambda_container.py | 3 +- .../docker/test_lambda_debug_settings.py | 1 - tests/unit/local/docker/test_lambda_image.py | 1 - 32 files changed, 37 insertions(+), 169 deletions(-) delete mode 100644 tests/integration/testdata/buildcmd/Dotnetcore3.1/HelloWorld.csproj delete mode 100644 tests/integration/testdata/buildcmd/Dotnetcore3.1/Program.cs delete mode 100644 tests/integration/testdata/buildcmd/Dotnetcore3.1/aws-lambda-tools-defaults.json diff --git a/.gitignore b/.gitignore index 05b0da72bd..6b3c26c6e5 100644 --- a/.gitignore +++ b/.gitignore @@ -412,12 +412,6 @@ coverage.xml # Temporary scratch directory used by the tests tests/integration/buildcmd/scratch -tests/integration/testdata/buildcmd/Dotnetcore2.0/bin -tests/integration/testdata/buildcmd/Dotnetcore2.0/obj -tests/integration/testdata/buildcmd/Dotnetcore2.1/bin -tests/integration/testdata/buildcmd/Dotnetcore2.1/obj -tests/integration/testdata/buildcmd/Dotnetcore3.1/bin -tests/integration/testdata/buildcmd/Dotnetcore3.1/obj tests/integration/testdata/buildcmd/Dotnet6/bin tests/integration/testdata/buildcmd/Dotnet6/obj tests/integration/testdata/buildcmd/Dotnet7/bin diff --git a/designs/build_debug_artifacts.md b/designs/build_debug_artifacts.md index 01ba532f9e..b839ba6be2 100644 --- a/designs/build_debug_artifacts.md +++ b/designs/build_debug_artifacts.md @@ -16,7 +16,7 @@ We will introduce a way in `sam build` to produce these debuggable artifacts for Success criteria for the change ------------------------------- -1. Artifacts generated will be debuggable for runtimes DotNetCore 2.0 and above. +1. Artifacts generated will be debuggable for runtimes DotNet 6.0 and above. Out-of-Scope ------------ diff --git a/designs/sam_build_cmd.md b/designs/sam_build_cmd.md index bb6c7cbacb..cb288ddf44 100644 --- a/designs/sam_build_cmd.md +++ b/designs/sam_build_cmd.md @@ -494,7 +494,7 @@ build actions. This section will look like: "build": { "actions": { "java8": "gradle build", - "dotnetcore2.1": "./build.sh" + "dotnet6": "./build.sh" } } } diff --git a/samcli/commands/build/command.py b/samcli/commands/build/command.py index b8ba89052a..92a2c6578c 100644 --- a/samcli/commands/build/command.py +++ b/samcli/commands/build/command.py @@ -54,7 +54,7 @@ 2. Nodejs 18.x, 16.x, 14.x, 12.x using NPM\n 3. Ruby 2.7, 3.2 using Bundler\n 4. Java 8, Java 11, Java 17 using Gradle and Maven\n - 5. Dotnetcore 3.1, Dotnet6 using Dotnet CLI (without --use-container)\n + 5. Dotnet6 using Dotnet CLI (without --use-container)\n 6. Go 1.x using Go Modules (without --use-container)\n """ diff --git a/samcli/commands/init/init_templates.py b/samcli/commands/init/init_templates.py index 9452faaa4d..c11998c543 100644 --- a/samcli/commands/init/init_templates.py +++ b/samcli/commands/init/init_templates.py @@ -211,17 +211,17 @@ def get_preprocessed_manifest( """ This method get the manifest cloned from the git repo and preprocessed it. Below is the link to manifest: - https://github.com/aws/aws-sam-cli-app-templates/blob/master/manifest.json + https://github.com/aws/aws-sam-cli-app-templates/blob/master/manifest-v2.json The structure of the manifest is shown below: { - "dotnetcore3.1": [ + "dotnet6": [ { - "directory": "dotnetcore3.1/cookiecutter-aws-sam-hello-dotnet", + "directory": "dotnet6/hello", "displayName": "Hello World Example", "dependencyManager": "cli-package", "appTemplate": "hello-world", "packageType": "Zip", - "useCaseName": "Serverless API" + "useCaseName": "Hello World Example" }, ] } diff --git a/samcli/lib/build/constants.py b/samcli/lib/build/constants.py index 77869c27cf..c7c4a3b94d 100644 --- a/samcli/lib/build/constants.py +++ b/samcli/lib/build/constants.py @@ -10,6 +10,7 @@ "nodejs10.x", "dotnetcore2.0", "dotnetcore2.1", + "dotnetcore3.1", "python2.7", "python3.6", "ruby2.5", diff --git a/samcli/lib/build/workflow_config.py b/samcli/lib/build/workflow_config.py index 39ea1acad7..b9ac751aed 100644 --- a/samcli/lib/build/workflow_config.py +++ b/samcli/lib/build/workflow_config.py @@ -161,7 +161,6 @@ def get_workflow_config( "nodejs18.x": BasicWorkflowSelector(NODEJS_NPM_CONFIG), "ruby2.7": BasicWorkflowSelector(RUBY_BUNDLER_CONFIG), "ruby3.2": BasicWorkflowSelector(RUBY_BUNDLER_CONFIG), - "dotnetcore3.1": BasicWorkflowSelector(DOTNET_CLIPACKAGE_CONFIG), "dotnet6": BasicWorkflowSelector(DOTNET_CLIPACKAGE_CONFIG), "go1.x": BasicWorkflowSelector(GO_MOD_CONFIG), # When Maven builder exists, add to this list so we can automatically choose a builder based on the supported diff --git a/samcli/lib/init/local_manifest.json b/samcli/lib/init/local_manifest.json index 38b95dc3be..462d8d4a8f 100644 --- a/samcli/lib/init/local_manifest.json +++ b/samcli/lib/init/local_manifest.json @@ -1,5 +1,5 @@ { - "dotnetcore3.1": [ + "dotnet6": [ { "directory": "template/cookiecutter-aws-sam-hello-dotnet", "displayName": "Hello World Example", diff --git a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/cookiecutter.json b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/cookiecutter.json index 9bf09d0306..19b21add11 100644 --- a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/cookiecutter.json +++ b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/cookiecutter.json @@ -1,6 +1,6 @@ { "project_name": "Name of the project", - "runtime": "dotnetcore3.1", + "runtime": "dotnet6", "architectures": { "value": [ "x86_64" diff --git a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj index 0749a6fd85..8926242ef3 100644 --- a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj +++ b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj @@ -1,11 +1,7 @@ - {%- if cookiecutter.runtime == 'dotnetcore3.1' %} - netcoreapp3.1 - {%- else %} net6.0 - {%- endif %} true diff --git a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json index 34ae747e11..fd910bc628 100644 --- a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json +++ b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json @@ -11,9 +11,6 @@ "profile":"", "region" : "", "configuration": "Release", - {%- if cookiecutter.runtime == 'dotnetcore3.1' %} - "framework" : "netcoreapp3.1", - {%- endif %} "function-runtime":"{{ cookiecutter.runtime }}", "function-memory-size" : 256, "function-timeout" : 30, diff --git a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/template.yaml b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/template.yaml index 4bcfaa9d43..3450d2620e 100644 --- a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/template.yaml +++ b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/template.yaml @@ -14,8 +14,8 @@ Resources: Properties: CodeUri: ./src/HelloWorld/ Handler: HelloWorld::HelloWorld.Function::FunctionHandler - {%- if cookiecutter.runtime == 'dotnetcore3.1' %} - Runtime: dotnetcore3.1 + {%- if cookiecutter.runtime == 'dotnet6' %} + Runtime: dotnet6 {%- endif %} Architectures: {%- for arch in cookiecutter.architectures.value %} diff --git a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj index 1c2b1f32e2..998671f9e5 100644 --- a/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj +++ b/samcli/lib/init/templates/cookiecutter-aws-sam-hello-dotnet/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj @@ -1,9 +1,7 @@ - {%- if cookiecutter.runtime == 'dotnetcore3.1' %} - netcoreapp3.1 - {%- else %} + {%- if cookiecutter.runtime == 'dotnet6' %} net6.0 {%- endif %} diff --git a/samcli/lib/utils/architecture.py b/samcli/lib/utils/architecture.py index 470754b2c1..a8025d8b3f 100644 --- a/samcli/lib/utils/architecture.py +++ b/samcli/lib/utils/architecture.py @@ -29,7 +29,6 @@ "java11": [ARM64, X86_64], "java17": [ARM64, X86_64], "go1.x": [X86_64], - "dotnetcore3.1": [ARM64, X86_64], "dotnet6": [ARM64, X86_64], "provided": [X86_64], "provided.al2": [ARM64, X86_64], diff --git a/samcli/local/common/runtime_template.py b/samcli/local/common/runtime_template.py index 85eb282a90..697631adea 100644 --- a/samcli/local/common/runtime_template.py +++ b/samcli/local/common/runtime_template.py @@ -40,7 +40,7 @@ ], "dotnet": [ { - "runtimes": ["dotnet6", "dotnetcore3.1"], + "runtimes": ["dotnet6"], "dependency_manager": "cli-package", "init_location": os.path.join(_templates, "cookiecutter-aws-sam-hello-dotnet"), "build": True, @@ -96,9 +96,8 @@ def get_local_lambda_images_location(mapping, runtime): # When adding new Lambda runtimes, please update SAM_RUNTIME_TO_SCHEMAS_CODE_LANG_MAPPING # Runtimes are ordered in alphabetical fashion with reverse version order (latest versions first) INIT_RUNTIMES = [ - # dotnetcore runtimes in descending order + # dotnet runtimes in descending order "dotnet6", - "dotnetcore3.1", "go1.x", # java runtimes in descending order "java17", @@ -126,7 +125,6 @@ def get_local_lambda_images_location(mapping, runtime): LAMBDA_IMAGES_RUNTIMES_MAP = { "dotnet6": "amazon/dotnet6-base", - "dotnetcore3.1": "amazon/dotnetcore3.1-base", "go1.x": "amazon/go1.x-base", "go (provided.al2)": "amazon/go-provided.al2-base", "java17": "amazon/java17-base", @@ -158,7 +156,7 @@ def get_local_lambda_images_location(mapping, runtime): "python3.8": "Python36", "python3.9": "Python36", "python3.10": "Python36", - "dotnet6": "dotnetcore3.1", + "dotnet6": "dotnet6", "go1.x": "Go1", } diff --git a/samcli/local/docker/lambda_debug_settings.py b/samcli/local/docker/lambda_debug_settings.py index 856717be99..8bffc6a3e2 100644 --- a/samcli/local/docker/lambda_debug_settings.py +++ b/samcli/local/docker/lambda_debug_settings.py @@ -93,10 +93,6 @@ def get_debug_settings(debug_port, debug_args_list, _container_env_vars, runtime **_container_env_vars, }, ), - Runtime.dotnetcore31.value: lambda: DebugSettings( - entry + ["/var/runtime/bootstrap"] + debug_args_list, - container_env_vars={"_AWS_LAMBDA_DOTNET_DEBUGGING": "1", **_container_env_vars}, - ), Runtime.dotnet6.value: lambda: DebugSettings( entry + ["/var/runtime/bootstrap"] + debug_args_list, container_env_vars={"_AWS_LAMBDA_DOTNET_DEBUGGING": "1", **_container_env_vars}, diff --git a/samcli/local/docker/lambda_image.py b/samcli/local/docker/lambda_image.py index 285e1b81e7..23f0a770d9 100644 --- a/samcli/local/docker/lambda_image.py +++ b/samcli/local/docker/lambda_image.py @@ -46,7 +46,6 @@ class Runtime(Enum): java11 = "java11" java17 = "java17" go1x = "go1.x" - dotnetcore31 = "dotnetcore3.1" dotnet6 = "dotnet6" provided = "provided" providedal2 = "provided.al2" @@ -86,7 +85,7 @@ def get_image_name_tag(cls, runtime: str, architecture: str) -> str: # `provided.al2` becomes `provided:al2`` runtime_image_tag = runtime.replace(".", ":") elif runtime.startswith("dotnet"): - # dotnetcore3.1 becomes dotnet:core3.1 and dotnet6 becomes dotnet:6 + # dotnet6 becomes dotnet:6 runtime_image_tag = runtime.replace("dotnet", "dotnet:") else: # This fits most runtimes format: `nameN.M` becomes `name:N.M` (python3.9 -> python:3.9) diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index 1a22c9cbb7..2b35d7c6e9 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -1223,15 +1223,13 @@ class TestBuildCommand_Dotnet_cli_package(BuildIntegBase): @parameterized.expand( [ - ("dotnetcore3.1", "Dotnetcore3.1", None), ("dotnet6", "Dotnet6", None), - ("dotnetcore3.1", "Dotnetcore3.1", "debug"), ("dotnet6", "Dotnet6", "debug"), ("provided.al2", "Dotnet7", None), ] ) @pytest.mark.flaky(reruns=3) - def test_dotnetcore_in_process(self, runtime, code_uri, mode, architecture="x86_64"): + def test_dotnet_in_process(self, runtime, code_uri, mode, architecture="x86_64"): # dotnet7 requires docker to build the function if code_uri == "Dotnet7" and (SKIP_DOCKER_TESTS or SKIP_DOCKER_BUILD): self.skipTest(SKIP_DOCKER_MESSAGE) @@ -1294,9 +1292,7 @@ def test_dotnetcore_in_process(self, runtime, code_uri, mode, architecture="x86_ @parameterized.expand( [ - ("dotnetcore3.1", "Dotnetcore3.1", None), ("dotnet6", "Dotnet6", None), - ("dotnetcore3.1", "Dotnetcore3.1", "debug"), ("dotnet6", "Dotnet6", "debug"), # force to run tests on arm64 machines may cause dotnet7 test failing # because Native AOT Lambda functions require the host and lambda architectures to match @@ -1305,7 +1301,7 @@ def test_dotnetcore_in_process(self, runtime, code_uri, mode, architecture="x86_ ) @skipIf(SKIP_DOCKER_TESTS or SKIP_DOCKER_BUILD, SKIP_DOCKER_MESSAGE) @pytest.mark.flaky(reruns=3) - def test_dotnetcore_in_container_mount_with_write_explicit(self, runtime, code_uri, mode, architecture="x86_64"): + def test_dotnet_in_container_mount_with_write_explicit(self, runtime, code_uri, mode, architecture="x86_64"): overrides = { "Runtime": runtime, "CodeUri": code_uri, @@ -1368,9 +1364,7 @@ def test_dotnetcore_in_container_mount_with_write_explicit(self, runtime, code_u @parameterized.expand( [ - ("dotnetcore3.1", "Dotnetcore3.1", None), ("dotnet6", "Dotnet6", None), - ("dotnetcore3.1", "Dotnetcore3.1", "debug"), ("dotnet6", "Dotnet6", "debug"), # force to run tests on arm64 machines may cause dotnet7 test failing # because Native AOT Lambda functions require the host and lambda architectures to match @@ -1379,7 +1373,7 @@ def test_dotnetcore_in_container_mount_with_write_explicit(self, runtime, code_u ) @skipIf(SKIP_DOCKER_TESTS or SKIP_DOCKER_BUILD, SKIP_DOCKER_MESSAGE) @pytest.mark.flaky(reruns=3) - def test_dotnetcore_in_container_mount_with_write_interactive( + def test_dotnet_in_container_mount_with_write_interactive( self, runtime, code_uri, @@ -1444,7 +1438,7 @@ def test_dotnetcore_in_container_mount_with_write_interactive( ) self.verify_docker_container_cleanedup(runtime) - @parameterized.expand([("dotnetcore3.1", "Dotnetcore3.1"), ("dotnet6", "Dotnet6")]) + @parameterized.expand([("dotnet6", "Dotnet6")]) @skipIf(SKIP_DOCKER_TESTS or SKIP_DOCKER_BUILD, SKIP_DOCKER_MESSAGE) @pytest.mark.flaky(reruns=3) def test_must_fail_on_container_mount_without_write_interactive(self, runtime, code_uri): @@ -2045,13 +2039,6 @@ class TestBuildWithDedupBuilds(DedupBuildIntegBase): @parameterized.expand( [ # in process - ( - False, - "Dotnetcore3.1", - "HelloWorld::HelloWorld.FirstFunction::FunctionHandler", - "HelloWorld::HelloWorld.SecondFunction::FunctionHandler", - "dotnetcore3.1", - ), ( False, "Dotnet6", @@ -2177,13 +2164,6 @@ class TestBuildWithCacheBuilds(CachedBuildIntegBase): @parameterized.expand( [ # in process - ( - False, - "Dotnetcore3.1", - "HelloWorld::HelloWorld.FirstFunction::FunctionHandler", - "HelloWorld::HelloWorld.SecondFunction::FunctionHandler", - "dotnetcore3.1", - ), ( False, "Dotnet6", @@ -2366,13 +2346,6 @@ class TestParallelBuilds(DedupBuildIntegBase): @parameterized.expand( [ # in process - ( - False, - "Dotnetcore3.1", - "HelloWorld::HelloWorld.FirstFunction::FunctionHandler", - "HelloWorld::HelloWorld.SecondFunction::FunctionHandler", - "dotnetcore3.1", - ), ( False, "Dotnet6", diff --git a/tests/integration/testdata/buildcmd/Dotnetcore3.1/HelloWorld.csproj b/tests/integration/testdata/buildcmd/Dotnetcore3.1/HelloWorld.csproj deleted file mode 100644 index b795d281f0..0000000000 --- a/tests/integration/testdata/buildcmd/Dotnetcore3.1/HelloWorld.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp3.1 - true - - - - - - - - - - - diff --git a/tests/integration/testdata/buildcmd/Dotnetcore3.1/Program.cs b/tests/integration/testdata/buildcmd/Dotnetcore3.1/Program.cs deleted file mode 100644 index b7dc35f8f6..0000000000 --- a/tests/integration/testdata/buildcmd/Dotnetcore3.1/Program.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Net.Http; -using System.Net.Http.Headers; -using Newtonsoft.Json; - -using Amazon.Lambda.Core; -using Amazon.Lambda.APIGatewayEvents; - -// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] - -namespace HelloWorld -{ - - public class Function - { - - public string FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) - { - return "{'message': 'Hello World'}"; - } - } - - public class FirstFunction - { - - public string FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) - { - return "Hello World"; - } - } - - public class SecondFunction - { - - public string FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) - { - return "Hello Mars"; - } - } -} diff --git a/tests/integration/testdata/buildcmd/Dotnetcore3.1/aws-lambda-tools-defaults.json b/tests/integration/testdata/buildcmd/Dotnetcore3.1/aws-lambda-tools-defaults.json deleted file mode 100644 index 89bbd11cf2..0000000000 --- a/tests/integration/testdata/buildcmd/Dotnetcore3.1/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Information" : [ - "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", - "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", - - "dotnet lambda help", - - "All the command line options for the Lambda command can be specified in this file." - ], - - "profile":"", - "region" : "", - "configuration": "Release", - "framework": "netcoreapp3.1", - "function-runtime":"dotnetcore3.1", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "HelloWorld::HelloWorld.Function::FunctionHandler" -} diff --git a/tests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/STS.csproj b/tests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/STS.csproj index 95f1ecee69..148daf168b 100644 --- a/tests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/STS.csproj +++ b/tests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/STS.csproj @@ -1,7 +1,7 @@ - netcoreapp2.1 + net6.0 true diff --git a/tests/integration/testdata/invoke/credential_tests/inprocess/template.yaml b/tests/integration/testdata/invoke/credential_tests/inprocess/template.yaml index d5b0c32de6..41147cf58c 100644 --- a/tests/integration/testdata/invoke/credential_tests/inprocess/template.yaml +++ b/tests/integration/testdata/invoke/credential_tests/inprocess/template.yaml @@ -13,7 +13,7 @@ Resources: Properties: CodeUri: dotnet/STS Handler: STS::STS.Function::FunctionHandler - Runtime: dotnetcore3.1 + Runtime: dotnet6 GoStsExample: Type: AWS::Serverless::Function Properties: diff --git a/tests/unit/commands/init/test_cli.py b/tests/unit/commands/init/test_cli.py index 65ff97a31b..15c892a114 100644 --- a/tests/unit/commands/init/test_cli.py +++ b/tests/unit/commands/init/test_cli.py @@ -2119,7 +2119,6 @@ def test_init_cli_must_not_generate_default_hello_world_app( def test_must_return_runtime_from_base_image_name(self): base_images = [ "amazon/dotnet6-base", - "amazon/dotnetcore3.1-base", "amazon/go1.x-base", "amazon/java11-base", "amazon/nodejs14.x-base", @@ -2131,7 +2130,6 @@ def test_must_return_runtime_from_base_image_name(self): expected_runtime = [ "dotnet6", - "dotnetcore3.1", "go1.x", "java11", "nodejs14.x", @@ -2153,10 +2151,10 @@ def test_must_process_manifest(self, _get_manifest_mock): preprocess_manifest = template.get_preprocessed_manifest() expected_result = { "Hello World Example": { - "dotnetcore3.1": { + "dotnet6": { "Zip": [ { - "directory": "dotnetcore3.1/cookiecutter-aws-sam-hello-dotnet", + "directory": "dotnet6/cookiecutter-aws-sam-hello-dotnet", "displayName": "Hello World Example", "dependencyManager": "cli-package", "appTemplate": "hello-world", @@ -2788,9 +2786,9 @@ def test_init_cli_generate_app_template_from_local_cli_templates( @patch("samcli.local.common.runtime_template.INIT_RUNTIMES") def test_must_remove_unsupported_runtime(self, init_runtime_mock): - runtime_option_list = ["python3.7", "ruby3.2", "ruby2.7", "java11", "unsupported_runtime", "dotnetcore3.1"] - init_runtime_mock.return_value = ["dotnetcore3.1", "go1.x", "java11", "python3.7", "ruby3.2", "ruby2.7"] - expect_result = ["dotnetcore3.1", "java11", "python3.7", "ruby3.2", "ruby2.7"] + runtime_option_list = ["python3.7", "ruby3.2", "ruby2.7", "java11", "unsupported_runtime"] + init_runtime_mock.return_value = ["go1.x", "java11", "python3.7", "ruby3.2", "ruby2.7"] + expect_result = ["java11", "python3.7", "ruby3.2", "ruby2.7"] actual_result = get_sorted_runtimes(runtime_option_list) self.assertEqual(actual_result, expect_result) diff --git a/tests/unit/commands/init/test_manifest.json b/tests/unit/commands/init/test_manifest.json index 0ae5edf30f..7ae51a146b 100644 --- a/tests/unit/commands/init/test_manifest.json +++ b/tests/unit/commands/init/test_manifest.json @@ -1,7 +1,7 @@ { - "dotnetcore3.1": [ + "dotnet6": [ { - "directory": "dotnetcore3.1/cookiecutter-aws-sam-hello-dotnet", + "directory": "dotnet6/cookiecutter-aws-sam-hello-dotnet", "displayName": "Hello World Example", "dependencyManager": "cli-package", "appTemplate": "hello-world", diff --git a/tests/unit/lib/build_module/test_app_builder.py b/tests/unit/lib/build_module/test_app_builder.py index 98b8006ad0..408ba8bb35 100644 --- a/tests/unit/lib/build_module/test_app_builder.py +++ b/tests/unit/lib/build_module/test_app_builder.py @@ -460,7 +460,9 @@ def test_must_raise_for_functions_with_multi_architecture(self, persist_mock, re msg = "Function name property Architectures should be a list of length 1" self.assertEqual(str(ex.exception), msg) - @parameterized.expand([("python2.7",), ("python3.6",), ("ruby2.5",), ("nodejs10.x",), ("dotnetcore2.1",)]) + @parameterized.expand( + [("python2.7",), ("python3.6",), ("ruby2.5",), ("nodejs10.x",), ("dotnetcore2.1",), ("dotnetcore3.1",)] + ) def test_deprecated_runtimes(self, runtime): with self.assertRaises(UnsupportedRuntimeException): self.builder._build_function( diff --git a/tests/unit/lib/build_module/test_build_strategy.py b/tests/unit/lib/build_module/test_build_strategy.py index 3e3bc35754..5b2f3f7d77 100644 --- a/tests/unit/lib/build_module/test_build_strategy.py +++ b/tests/unit/lib/build_module/test_build_strategy.py @@ -749,7 +749,7 @@ def test_will_call_incremental_build_strategy(self, mocked_read, mocked_write, r @parameterized.expand( [ - "dotnetcore3.1", + "dotnet6", "go1.x", "java11", ] diff --git a/tests/unit/lib/build_module/test_workflow_config.py b/tests/unit/lib/build_module/test_workflow_config.py index c8a1fad900..9a1beaccfd 100644 --- a/tests/unit/lib/build_module/test_workflow_config.py +++ b/tests/unit/lib/build_module/test_workflow_config.py @@ -64,7 +64,7 @@ def test_must_work_for_provided_with_build_method_dotnet7(self, runtime): self.assertIn(Event("BuildWorkflowUsed", "dotnet-cli-package"), EventTracker.get_tracked_events()) self.assertTrue(result.must_mount_with_write_in_container) - @parameterized.expand([("dotnetcore3.1",), ("dotnet6",), ("provided.al2", "dotnet7")]) + @parameterized.expand([("dotnet6",), ("provided.al2", "dotnet7")]) def test_must_mount_with_write_for_dotnet_in_container(self, runtime, specified_workflow=None): result = get_workflow_config(runtime, self.code_dir, self.project_dir, specified_workflow) self.assertTrue(result.must_mount_with_write_in_container) diff --git a/tests/unit/lib/utils/test_architecture.py b/tests/unit/lib/utils/test_architecture.py index 1c95a96aa5..860c513a07 100644 --- a/tests/unit/lib/utils/test_architecture.py +++ b/tests/unit/lib/utils/test_architecture.py @@ -44,7 +44,7 @@ def test_validate_architecture_errors(self, value): [ ("nodejs14.x", X86_64, ZIP), ("java8.al2", ARM64, ZIP), - ("dotnetcore3.1", ARM64, ZIP), + ("dotnet6", ARM64, ZIP), (None, X86_64, IMAGE), (None, ARM64, IMAGE), (None, X86_64, IMAGE), diff --git a/tests/unit/local/docker/test_lambda_container.py b/tests/unit/local/docker/test_lambda_container.py index 1ccff3c2f0..90893e4e49 100644 --- a/tests/unit/local/docker/test_lambda_container.py +++ b/tests/unit/local/docker/test_lambda_container.py @@ -12,7 +12,7 @@ from samcli.local.docker.lambda_debug_settings import DebuggingNotSupported from samcli.local.docker.lambda_image import RAPID_IMAGE_TAG_PREFIX -RUNTIMES_WITH_ENTRYPOINT = [Runtime.dotnetcore31.value, Runtime.dotnet6.value, Runtime.go1x.value] +RUNTIMES_WITH_ENTRYPOINT = [Runtime.dotnet6.value, Runtime.go1x.value] RUNTIMES_WITH_BOOTSTRAP_ENTRYPOINT = [ Runtime.nodejs12x.value, @@ -31,7 +31,6 @@ Runtime.java11.value, Runtime.java8.value, Runtime.java8al2.value, - Runtime.dotnetcore31.value, Runtime.dotnet6.value, Runtime.go1x.value, ] diff --git a/tests/unit/local/docker/test_lambda_debug_settings.py b/tests/unit/local/docker/test_lambda_debug_settings.py index 407cd05bba..1dd024ebc2 100644 --- a/tests/unit/local/docker/test_lambda_debug_settings.py +++ b/tests/unit/local/docker/test_lambda_debug_settings.py @@ -10,7 +10,6 @@ Runtime.java8al2, Runtime.java11, Runtime.java17, - Runtime.dotnetcore31, Runtime.dotnet6, Runtime.go1x, Runtime.nodejs12x, diff --git a/tests/unit/local/docker/test_lambda_image.py b/tests/unit/local/docker/test_lambda_image.py index 3ad8a10c54..1e8f936d98 100644 --- a/tests/unit/local/docker/test_lambda_image.py +++ b/tests/unit/local/docker/test_lambda_image.py @@ -34,7 +34,6 @@ class TestRuntime(TestCase): ("java17", "java:17-x86_64"), ("go1.x", "go:1"), ("dotnet6", "dotnet:6-x86_64"), - ("dotnetcore3.1", "dotnet:core3.1-x86_64"), ("provided", "provided:alami"), ("provided.al2", "provided:al2-x86_64"), ] From 97104eac05c47aec1c7db62cb98cd050c7656d3d Mon Sep 17 00:00:00 2001 From: Jacob Fuss <32497805+jfuss@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:16:14 -0500 Subject: [PATCH 2/7] fix(invoke): Write in UTF-8 string instead of bytes. (#5232) * fix(invoke): Write in UTF-8 string instead of bytes. It appears that we were using sys.stdout.buffer to support python2 and python3 at the same time. Switching to just write to sys.stdout allows us to write a utf-8 encoding string. When using sys.stdout.buffer, we can only write bytes and I couldn't get the correct UTF8 encoded string to print correctly. * Fix ruff errors * Update log_streamer.py to remove encoding * More updates to make everything work better in general * Fix with ruff again * Explictingly write to stream for building images * More patching writes * More patching * Fix long line * Use mock over io.string * More fixing of tests * Assert mock instead of data directly * More small edits in test * Verify through calls instead of value * run make black * Fix when we flush to match pervious behavior and output * add integration tests * run make black --------- Co-authored-by: Jacob Fuss Co-authored-by: Mehmet Nuri Deveci <5735811+mndeveci@users.noreply.github.com> --- samcli/lib/utils/osutils.py | 4 ++-- samcli/lib/utils/stream_writer.py | 7 ++++-- samcli/local/docker/container.py | 5 +++- samcli/local/docker/lambda_image.py | 10 ++++---- samcli/local/docker/manager.py | 8 ++++--- .../local/invoke/test_integrations_cli.py | 21 ++++++++++++++++ tests/unit/lib/utils/test_osutils.py | 8 ------- tests/unit/lib/utils/test_stream_writer.py | 2 +- tests/unit/local/docker/test_lambda_image.py | 9 ++++--- tests/unit/local/docker/test_manager.py | 24 +++++++++++++------ 10 files changed, 64 insertions(+), 34 deletions(-) diff --git a/samcli/lib/utils/osutils.py b/samcli/lib/utils/osutils.py index d53dc9ffb5..dfdd1ed256 100644 --- a/samcli/lib/utils/osutils.py +++ b/samcli/lib/utils/osutils.py @@ -87,7 +87,7 @@ def stdout(): io.BytesIO Byte stream of Stdout """ - return sys.stdout.buffer + return sys.stdout def stderr(): @@ -99,7 +99,7 @@ def stderr(): io.BytesIO Byte stream of stderr """ - return sys.stderr.buffer + return sys.stderr def remove(path): diff --git a/samcli/lib/utils/stream_writer.py b/samcli/lib/utils/stream_writer.py index 1fc62fa690..606efb606c 100644 --- a/samcli/lib/utils/stream_writer.py +++ b/samcli/lib/utils/stream_writer.py @@ -22,7 +22,7 @@ def __init__(self, stream, auto_flush=False): def stream(self): return self._stream - def write(self, output, encode=False): + def write(self, output, encode=False, write_to_buffer=True): """ Writes specified text to the underlying stream @@ -31,7 +31,10 @@ def write(self, output, encode=False): output bytes-like object Bytes to write """ - self._stream.write(output.encode() if encode else output) + if write_to_buffer: + self._stream.buffer.write(output.encode() if encode else output) + else: + self._stream.write(output) if self._auto_flush: self._stream.flush() diff --git a/samcli/local/docker/container.py b/samcli/local/docker/container.py index e70f7c2a1f..a5aebc1bd3 100644 --- a/samcli/local/docker/container.py +++ b/samcli/local/docker/container.py @@ -1,6 +1,7 @@ """ Representation of a generic Docker container """ +import json import logging import os import pathlib @@ -324,7 +325,8 @@ def wait_for_http_response(self, name, event, stdout): data=event.encode("utf-8"), timeout=(self.RAPID_CONNECTION_TIMEOUT, None), ) - stdout.write(resp.content) + stdout.write(json.dumps(json.loads(resp.content), ensure_ascii=False), write_to_buffer=False) + stdout.flush() def wait_for_result(self, full_path, event, stdout, stderr, start_timer=None): # NOTE(sriram-mv): Let logging happen in its own thread, so that a http request can be sent. @@ -434,6 +436,7 @@ def _write_container_output(output_itr, stdout=None, stderr=None): if stderr_data and stderr: stderr.write(stderr_data) + except Exception as ex: LOG.debug("Failed to get the logs from the container", exc_info=ex) diff --git a/samcli/local/docker/lambda_image.py b/samcli/local/docker/lambda_image.py index 23f0a770d9..ab9a20a8a8 100644 --- a/samcli/local/docker/lambda_image.py +++ b/samcli/local/docker/lambda_image.py @@ -226,7 +226,7 @@ def build(self, runtime, packagetype, image, layers, architecture, stream=None, or not runtime ): stream_writer = stream or StreamWriter(sys.stderr) - stream_writer.write("Building image...") + stream_writer.write("Building image...", write_to_buffer=False) stream_writer.flush() self._build_image( image if image else base_image, rapid_image, downloaded_layers, architecture, stream=stream_writer @@ -337,15 +337,15 @@ def set_item_permission(tar_info): platform=get_docker_platform(architecture), ) for log in resp_stream: - stream_writer.write(".") + stream_writer.write(".", write_to_buffer=False) stream_writer.flush() if "error" in log: - stream_writer.write("\n") + stream_writer.write("\n", write_to_buffer=False) LOG.exception("Failed to build Docker Image") raise ImageBuildException("Error building docker image: {}".format(log["error"])) - stream_writer.write("\n") + stream_writer.write("\n", write_to_buffer=False) except (docker.errors.BuildError, docker.errors.APIError) as ex: - stream_writer.write("\n") + stream_writer.write("\n", write_to_buffer=False) LOG.exception("Failed to build Docker Image") raise ImageBuildException("Building Image failed.") from ex finally: diff --git a/samcli/local/docker/manager.py b/samcli/local/docker/manager.py index a035003bb0..0cd8dc8dc8 100644 --- a/samcli/local/docker/manager.py +++ b/samcli/local/docker/manager.py @@ -168,16 +168,18 @@ def pull_image(self, image_name, tag=None, stream=None): raise DockerImagePullFailedException(str(ex)) from ex # io streams, especially StringIO, work only with unicode strings - stream_writer.write("\nFetching {}:{} Docker container image...".format(image_name, tag)) + stream_writer.write( + "\nFetching {}:{} Docker container image...".format(image_name, tag), write_to_buffer=False + ) # Each line contains information on progress of the pull. Each line is a JSON string for _ in result_itr: # For every line, print a dot to show progress - stream_writer.write(".") + stream_writer.write(".", write_to_buffer=False) stream_writer.flush() # We are done. Go to the next line - stream_writer.write("\n") + stream_writer.write("\n", write_to_buffer=False) def has_image(self, image_name): """ diff --git a/tests/integration/local/invoke/test_integrations_cli.py b/tests/integration/local/invoke/test_integrations_cli.py index 3604fc4010..bf3f1d1e2e 100644 --- a/tests/integration/local/invoke/test_integrations_cli.py +++ b/tests/integration/local/invoke/test_integrations_cli.py @@ -291,6 +291,27 @@ def test_invoke_returns_expected_result_when_no_event_given(self): self.assertEqual(process.returncode, 0) self.assertEqual("{}", process_stdout.decode("utf-8")) + # @pytest.mark.flaky(reruns=3) + def test_invoke_returns_utf8(self): + command_list = InvokeIntegBase.get_command_list( + "EchoEventFunction", template_path=self.template_path, event_path=self.event_utf8_path + ) + + process = Popen(command_list, stdout=PIPE) + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() + + with open(self.event_utf8_path) as f: + expected_output = json.dumps(json.load(f), ensure_ascii=False) + + self.assertEqual(process.returncode, 0) + self.assertEqual(expected_output, process_stdout.decode("utf-8")) + @pytest.mark.flaky(reruns=3) def test_invoke_with_env_using_parameters(self): command_list = InvokeIntegBase.get_command_list( diff --git a/tests/unit/lib/utils/test_osutils.py b/tests/unit/lib/utils/test_osutils.py index bf4794f2c4..6f7a6cf4df 100644 --- a/tests/unit/lib/utils/test_osutils.py +++ b/tests/unit/lib/utils/test_osutils.py @@ -34,9 +34,7 @@ def test_raises_on_cleanup_failure(self, rmdir_mock): @patch("os.rmdir") def test_handles_ignore_error_case(self, rmdir_mock): rmdir_mock.side_effect = OSError("fail") - dir_name = None with osutils.mkdir_temp(ignore_errors=True) as tempdir: - dir_name = tempdir self.assertTrue(os.path.exists(tempdir)) @@ -44,9 +42,6 @@ class Test_stderr(TestCase): def test_must_return_sys_stderr(self): expected_stderr = sys.stderr - if sys.version_info.major > 2: - expected_stderr = sys.stderr.buffer - self.assertEqual(expected_stderr, osutils.stderr()) @@ -54,9 +49,6 @@ class Test_stdout(TestCase): def test_must_return_sys_stdout(self): expected_stdout = sys.stdout - if sys.version_info.major > 2: - expected_stdout = sys.stdout.buffer - self.assertEqual(expected_stdout, osutils.stdout()) diff --git a/tests/unit/lib/utils/test_stream_writer.py b/tests/unit/lib/utils/test_stream_writer.py index cb48955850..3ef9425a3e 100644 --- a/tests/unit/lib/utils/test_stream_writer.py +++ b/tests/unit/lib/utils/test_stream_writer.py @@ -17,7 +17,7 @@ def test_must_write_to_stream(self): writer = StreamWriter(stream_mock) writer.write(buffer) - stream_mock.write.assert_called_once_with(buffer) + stream_mock.buffer.write.assert_called_once_with(buffer) def test_must_flush_underlying_stream(self): stream_mock = Mock() diff --git a/tests/unit/local/docker/test_lambda_image.py b/tests/unit/local/docker/test_lambda_image.py index 1e8f936d98..03b57be804 100644 --- a/tests/unit/local/docker/test_lambda_image.py +++ b/tests/unit/local/docker/test_lambda_image.py @@ -1,4 +1,3 @@ -import io import tempfile from unittest import TestCase @@ -271,7 +270,7 @@ def test_force_building_image_that_doesnt_already_exists( docker_client_mock.images.get.side_effect = ImageNotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = io.StringIO() + stream = Mock() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) actual_image_id = lambda_image.build( @@ -311,7 +310,7 @@ def test_force_building_image_on_daemon_404( docker_client_mock.images.get.side_effect = NotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = io.StringIO() + stream = Mock() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) actual_image_id = lambda_image.build( @@ -351,7 +350,7 @@ def test_docker_distribution_api_error_on_daemon_api_error( docker_client_mock.images.get.side_effect = APIError("error from docker daemon") docker_client_mock.images.list.return_value = [] - stream = io.StringIO() + stream = Mock() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) with self.assertRaises(DockerDistributionAPIError): @@ -377,7 +376,7 @@ def test_not_force_building_image_that_doesnt_already_exists( docker_client_mock.images.get.side_effect = ImageNotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = io.StringIO() + stream = Mock() lambda_image = LambdaImage(layer_downloader_mock, False, False, docker_client=docker_client_mock) actual_image_id = lambda_image.build( diff --git a/tests/unit/local/docker/test_manager.py b/tests/unit/local/docker/test_manager.py index ada69903ea..b5dbe16a9b 100644 --- a/tests/unit/local/docker/test_manager.py +++ b/tests/unit/local/docker/test_manager.py @@ -1,8 +1,6 @@ """ Tests container manager """ - -import io import importlib from unittest import TestCase from unittest.mock import Mock, patch, MagicMock, ANY, call @@ -218,17 +216,29 @@ def setUp(self): self.manager = ContainerManager(docker_client=self.mock_docker_client) def test_must_pull_and_print_progress_dots(self): - stream = io.StringIO() + stream = Mock() pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] self.mock_docker_client.api.pull.return_value = pull_result - expected_stream_output = "\nFetching {}:latest Docker container image...{}\n".format( - self.image_name, "." * len(pull_result) # Progress bar will print one dot per response from pull API - ) + expected_stream_calls = [ + call(f"\nFetching {self.image_name}:latest Docker container image...", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call(".", write_to_buffer=False), + call("\n", write_to_buffer=False), + ] self.manager.pull_image(self.image_name, stream=stream) self.mock_docker_client.api.pull.assert_called_with(self.image_name, stream=True, decode=True, tag="latest") - self.assertEqual(stream.getvalue(), expected_stream_output) + + stream.write.assert_has_calls(expected_stream_calls) def test_must_raise_if_image_not_found(self): msg = "some error" From 7b7c54c59ad15ad90fd558d640daefa5142115d7 Mon Sep 17 00:00:00 2001 From: Jacob Fuss <32497805+jfuss@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:43:21 -0500 Subject: [PATCH 3/7] Revert "fix(invoke): Write in UTF-8 string instead of bytes. (#5232)" (#5401) This reverts commit 97104eac05c47aec1c7db62cb98cd050c7656d3d. --- samcli/lib/utils/osutils.py | 4 ++-- samcli/lib/utils/stream_writer.py | 7 ++---- samcli/local/docker/container.py | 5 +--- samcli/local/docker/lambda_image.py | 10 ++++---- samcli/local/docker/manager.py | 8 +++---- .../local/invoke/test_integrations_cli.py | 21 ---------------- tests/unit/lib/utils/test_osutils.py | 8 +++++++ tests/unit/lib/utils/test_stream_writer.py | 2 +- tests/unit/local/docker/test_lambda_image.py | 9 +++---- tests/unit/local/docker/test_manager.py | 24 ++++++------------- 10 files changed, 34 insertions(+), 64 deletions(-) diff --git a/samcli/lib/utils/osutils.py b/samcli/lib/utils/osutils.py index dfdd1ed256..d53dc9ffb5 100644 --- a/samcli/lib/utils/osutils.py +++ b/samcli/lib/utils/osutils.py @@ -87,7 +87,7 @@ def stdout(): io.BytesIO Byte stream of Stdout """ - return sys.stdout + return sys.stdout.buffer def stderr(): @@ -99,7 +99,7 @@ def stderr(): io.BytesIO Byte stream of stderr """ - return sys.stderr + return sys.stderr.buffer def remove(path): diff --git a/samcli/lib/utils/stream_writer.py b/samcli/lib/utils/stream_writer.py index 606efb606c..1fc62fa690 100644 --- a/samcli/lib/utils/stream_writer.py +++ b/samcli/lib/utils/stream_writer.py @@ -22,7 +22,7 @@ def __init__(self, stream, auto_flush=False): def stream(self): return self._stream - def write(self, output, encode=False, write_to_buffer=True): + def write(self, output, encode=False): """ Writes specified text to the underlying stream @@ -31,10 +31,7 @@ def write(self, output, encode=False, write_to_buffer=True): output bytes-like object Bytes to write """ - if write_to_buffer: - self._stream.buffer.write(output.encode() if encode else output) - else: - self._stream.write(output) + self._stream.write(output.encode() if encode else output) if self._auto_flush: self._stream.flush() diff --git a/samcli/local/docker/container.py b/samcli/local/docker/container.py index a5aebc1bd3..e70f7c2a1f 100644 --- a/samcli/local/docker/container.py +++ b/samcli/local/docker/container.py @@ -1,7 +1,6 @@ """ Representation of a generic Docker container """ -import json import logging import os import pathlib @@ -325,8 +324,7 @@ def wait_for_http_response(self, name, event, stdout): data=event.encode("utf-8"), timeout=(self.RAPID_CONNECTION_TIMEOUT, None), ) - stdout.write(json.dumps(json.loads(resp.content), ensure_ascii=False), write_to_buffer=False) - stdout.flush() + stdout.write(resp.content) def wait_for_result(self, full_path, event, stdout, stderr, start_timer=None): # NOTE(sriram-mv): Let logging happen in its own thread, so that a http request can be sent. @@ -436,7 +434,6 @@ def _write_container_output(output_itr, stdout=None, stderr=None): if stderr_data and stderr: stderr.write(stderr_data) - except Exception as ex: LOG.debug("Failed to get the logs from the container", exc_info=ex) diff --git a/samcli/local/docker/lambda_image.py b/samcli/local/docker/lambda_image.py index ab9a20a8a8..23f0a770d9 100644 --- a/samcli/local/docker/lambda_image.py +++ b/samcli/local/docker/lambda_image.py @@ -226,7 +226,7 @@ def build(self, runtime, packagetype, image, layers, architecture, stream=None, or not runtime ): stream_writer = stream or StreamWriter(sys.stderr) - stream_writer.write("Building image...", write_to_buffer=False) + stream_writer.write("Building image...") stream_writer.flush() self._build_image( image if image else base_image, rapid_image, downloaded_layers, architecture, stream=stream_writer @@ -337,15 +337,15 @@ def set_item_permission(tar_info): platform=get_docker_platform(architecture), ) for log in resp_stream: - stream_writer.write(".", write_to_buffer=False) + stream_writer.write(".") stream_writer.flush() if "error" in log: - stream_writer.write("\n", write_to_buffer=False) + stream_writer.write("\n") LOG.exception("Failed to build Docker Image") raise ImageBuildException("Error building docker image: {}".format(log["error"])) - stream_writer.write("\n", write_to_buffer=False) + stream_writer.write("\n") except (docker.errors.BuildError, docker.errors.APIError) as ex: - stream_writer.write("\n", write_to_buffer=False) + stream_writer.write("\n") LOG.exception("Failed to build Docker Image") raise ImageBuildException("Building Image failed.") from ex finally: diff --git a/samcli/local/docker/manager.py b/samcli/local/docker/manager.py index 0cd8dc8dc8..a035003bb0 100644 --- a/samcli/local/docker/manager.py +++ b/samcli/local/docker/manager.py @@ -168,18 +168,16 @@ def pull_image(self, image_name, tag=None, stream=None): raise DockerImagePullFailedException(str(ex)) from ex # io streams, especially StringIO, work only with unicode strings - stream_writer.write( - "\nFetching {}:{} Docker container image...".format(image_name, tag), write_to_buffer=False - ) + stream_writer.write("\nFetching {}:{} Docker container image...".format(image_name, tag)) # Each line contains information on progress of the pull. Each line is a JSON string for _ in result_itr: # For every line, print a dot to show progress - stream_writer.write(".", write_to_buffer=False) + stream_writer.write(".") stream_writer.flush() # We are done. Go to the next line - stream_writer.write("\n", write_to_buffer=False) + stream_writer.write("\n") def has_image(self, image_name): """ diff --git a/tests/integration/local/invoke/test_integrations_cli.py b/tests/integration/local/invoke/test_integrations_cli.py index bf3f1d1e2e..3604fc4010 100644 --- a/tests/integration/local/invoke/test_integrations_cli.py +++ b/tests/integration/local/invoke/test_integrations_cli.py @@ -291,27 +291,6 @@ def test_invoke_returns_expected_result_when_no_event_given(self): self.assertEqual(process.returncode, 0) self.assertEqual("{}", process_stdout.decode("utf-8")) - # @pytest.mark.flaky(reruns=3) - def test_invoke_returns_utf8(self): - command_list = InvokeIntegBase.get_command_list( - "EchoEventFunction", template_path=self.template_path, event_path=self.event_utf8_path - ) - - process = Popen(command_list, stdout=PIPE) - try: - stdout, _ = process.communicate(timeout=TIMEOUT) - except TimeoutExpired: - process.kill() - raise - - process_stdout = stdout.strip() - - with open(self.event_utf8_path) as f: - expected_output = json.dumps(json.load(f), ensure_ascii=False) - - self.assertEqual(process.returncode, 0) - self.assertEqual(expected_output, process_stdout.decode("utf-8")) - @pytest.mark.flaky(reruns=3) def test_invoke_with_env_using_parameters(self): command_list = InvokeIntegBase.get_command_list( diff --git a/tests/unit/lib/utils/test_osutils.py b/tests/unit/lib/utils/test_osutils.py index 6f7a6cf4df..bf4794f2c4 100644 --- a/tests/unit/lib/utils/test_osutils.py +++ b/tests/unit/lib/utils/test_osutils.py @@ -34,7 +34,9 @@ def test_raises_on_cleanup_failure(self, rmdir_mock): @patch("os.rmdir") def test_handles_ignore_error_case(self, rmdir_mock): rmdir_mock.side_effect = OSError("fail") + dir_name = None with osutils.mkdir_temp(ignore_errors=True) as tempdir: + dir_name = tempdir self.assertTrue(os.path.exists(tempdir)) @@ -42,6 +44,9 @@ class Test_stderr(TestCase): def test_must_return_sys_stderr(self): expected_stderr = sys.stderr + if sys.version_info.major > 2: + expected_stderr = sys.stderr.buffer + self.assertEqual(expected_stderr, osutils.stderr()) @@ -49,6 +54,9 @@ class Test_stdout(TestCase): def test_must_return_sys_stdout(self): expected_stdout = sys.stdout + if sys.version_info.major > 2: + expected_stdout = sys.stdout.buffer + self.assertEqual(expected_stdout, osutils.stdout()) diff --git a/tests/unit/lib/utils/test_stream_writer.py b/tests/unit/lib/utils/test_stream_writer.py index 3ef9425a3e..cb48955850 100644 --- a/tests/unit/lib/utils/test_stream_writer.py +++ b/tests/unit/lib/utils/test_stream_writer.py @@ -17,7 +17,7 @@ def test_must_write_to_stream(self): writer = StreamWriter(stream_mock) writer.write(buffer) - stream_mock.buffer.write.assert_called_once_with(buffer) + stream_mock.write.assert_called_once_with(buffer) def test_must_flush_underlying_stream(self): stream_mock = Mock() diff --git a/tests/unit/local/docker/test_lambda_image.py b/tests/unit/local/docker/test_lambda_image.py index 03b57be804..1e8f936d98 100644 --- a/tests/unit/local/docker/test_lambda_image.py +++ b/tests/unit/local/docker/test_lambda_image.py @@ -1,3 +1,4 @@ +import io import tempfile from unittest import TestCase @@ -270,7 +271,7 @@ def test_force_building_image_that_doesnt_already_exists( docker_client_mock.images.get.side_effect = ImageNotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = Mock() + stream = io.StringIO() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) actual_image_id = lambda_image.build( @@ -310,7 +311,7 @@ def test_force_building_image_on_daemon_404( docker_client_mock.images.get.side_effect = NotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = Mock() + stream = io.StringIO() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) actual_image_id = lambda_image.build( @@ -350,7 +351,7 @@ def test_docker_distribution_api_error_on_daemon_api_error( docker_client_mock.images.get.side_effect = APIError("error from docker daemon") docker_client_mock.images.list.return_value = [] - stream = Mock() + stream = io.StringIO() lambda_image = LambdaImage(layer_downloader_mock, False, True, docker_client=docker_client_mock) with self.assertRaises(DockerDistributionAPIError): @@ -376,7 +377,7 @@ def test_not_force_building_image_that_doesnt_already_exists( docker_client_mock.images.get.side_effect = ImageNotFound("image not found") docker_client_mock.images.list.return_value = [] - stream = Mock() + stream = io.StringIO() lambda_image = LambdaImage(layer_downloader_mock, False, False, docker_client=docker_client_mock) actual_image_id = lambda_image.build( diff --git a/tests/unit/local/docker/test_manager.py b/tests/unit/local/docker/test_manager.py index b5dbe16a9b..ada69903ea 100644 --- a/tests/unit/local/docker/test_manager.py +++ b/tests/unit/local/docker/test_manager.py @@ -1,6 +1,8 @@ """ Tests container manager """ + +import io import importlib from unittest import TestCase from unittest.mock import Mock, patch, MagicMock, ANY, call @@ -216,29 +218,17 @@ def setUp(self): self.manager = ContainerManager(docker_client=self.mock_docker_client) def test_must_pull_and_print_progress_dots(self): - stream = Mock() + stream = io.StringIO() pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] self.mock_docker_client.api.pull.return_value = pull_result - expected_stream_calls = [ - call(f"\nFetching {self.image_name}:latest Docker container image...", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call(".", write_to_buffer=False), - call("\n", write_to_buffer=False), - ] + expected_stream_output = "\nFetching {}:latest Docker container image...{}\n".format( + self.image_name, "." * len(pull_result) # Progress bar will print one dot per response from pull API + ) self.manager.pull_image(self.image_name, stream=stream) self.mock_docker_client.api.pull.assert_called_with(self.image_name, stream=True, decode=True, tag="latest") - - stream.write.assert_has_calls(expected_stream_calls) + self.assertEqual(stream.getvalue(), expected_stream_output) def test_must_raise_if_image_not_found(self): msg = "some error" From 49fe5925a325934d2464f9435319114613b765a0 Mon Sep 17 00:00:00 2001 From: Wing Fung Lau <4760060+hawflau@users.noreply.github.com> Date: Thu, 22 Jun 2023 12:43:47 -0700 Subject: [PATCH 4/7] Add sanity check script and use it in pyinstaller GHA (#5400) * Add sanity check script and use it in pyinstaller GHA * set pipefail in sanity-check.sh * Make CI_OVERRIDE a global env var in the GHA workflow * setup go in GHA * disable telemetry * Update script to check binary existence and to fix an issue in go build --- .github/workflows/validate_pyinstaller.yml | 17 +++++++- tests/sanity-check.sh | 45 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100755 tests/sanity-check.sh diff --git a/.github/workflows/validate_pyinstaller.yml b/.github/workflows/validate_pyinstaller.yml index 8370328b5d..04b5c828ca 100644 --- a/.github/workflows/validate_pyinstaller.yml +++ b/.github/workflows/validate_pyinstaller.yml @@ -5,6 +5,9 @@ on: branches: - develop +env: + CI_OVERRIDE: "1" + jobs: build-for-linux: name: build-pyinstaller-linux @@ -15,15 +18,20 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v3 + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: "1.20" - name: Build PyInstaller run: | chmod +x ./installer/pyinstaller/build-linux.sh - CI_OVERRIDE=1 ./installer/pyinstaller/build-linux.sh aws-sam-cli-linux-x86_64.zip + ./installer/pyinstaller/build-linux.sh aws-sam-cli-linux-x86_64.zip - name: Basic tests for PyInstaller run: | unzip .build/output/aws-sam-cli-linux-x86_64.zip -d sam-installation ./sam-installation/install sam-beta --version + ./tests/sanity-check.sh - uses: actions/upload-artifact@v3 with: name: pyinstaller-linux-zip @@ -41,15 +49,20 @@ jobs: - uses: actions/setup-python@v4 with: python-version: "3.7" + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: "1.20" - name: Build PyInstaller run: | chmod +x ./installer/pyinstaller/build-mac.sh - CI_OVERRIDE=1 ./installer/pyinstaller/build-mac.sh aws-sam-cli-macos-x86_64.zip + ./installer/pyinstaller/build-mac.sh aws-sam-cli-macos-x86_64.zip - name: Basic tests for PyInstaller run: | unzip .build/output/aws-sam-cli-macos-x86_64.zip -d sam-installation sudo ./sam-installation/install sam-beta --version + ./tests/sanity-check.sh - uses: actions/upload-artifact@v3 with: name: pyinstaller-macos-zip diff --git a/tests/sanity-check.sh b/tests/sanity-check.sh new file mode 100755 index 0000000000..8f971dbd00 --- /dev/null +++ b/tests/sanity-check.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -xeo pipefail + +export SAM_CLI_TELEMETRY="${SAM_CLI_TELEMETRY:-0}" + +if [ "$CI_OVERRIDE" = "1" ]; then + sam_binary="sam-beta" +elif [ "$IS_NIGHTLY" = "1" ]; then + sam_binary="sam-nightly" +elif [ "$SAM_CLI_DEV" = "1" ]; then + sam_binary="samdev" +else + sam_binary="sam" +fi + +if ! command -v "$sam_binary" &> /dev/null; then + echo "$sam_binary not found. Please check if it is in PATH" + exit 1 +fi + +echo "Using ${sam_binary} as SAM CLI binary name" + +if [ "$sam_binary" = "sam" ]; then + SAMCLI_INSTALLED_VERSION=$($sam_binary --version | cut -d " " -f 4) + + # Get latest SAM CLI version from GH main branch + SAMCLI_LATEST_VERSION=$(curl -L https://raw.githubusercontent.com/aws/aws-sam-cli/master/samcli/__init__.py | tail -n 1 | cut -d '"' -f 2) + + # Check version + if [[ "$SAMCLI_INSTALLED_VERSION" != "$SAMCLI_LATEST_VERSION" ]]; then + echo "expected: $SAMCLI_LATEST_VERSION; got: $SAMCLI_INSTALLED_VERSION" + exit 1 + fi + + echo "Version check succeeded" +fi + +echo "Starting testing sam binary" +rm -rf sam-app-testing +"$sam_binary" init --no-interactive -n sam-app-testing --dependency-manager mod --runtime go1.x --app-template hello-world --package-type Zip --architecture x86_64 +cd sam-app-testing +GOFLAGS="-buildvcs=false" "$sam_binary" build +"$sam_binary" validate + +echo "sam init, sam build, and sam validate commands Succeeded" From 4e2509badf7800dd58583d0098eb6d494acf37e4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 02:43:32 +0000 Subject: [PATCH 5/7] chore: update aws-sam-translator to 1.70.0 (#5402) Co-authored-by: GitHub Action --- requirements/base.txt | 2 +- requirements/reproducible-linux.txt | 6 +++--- requirements/reproducible-mac.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 2ba320212e..34edac3fd0 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,7 @@ jmespath~=1.0.1 ruamel_yaml~=0.17.21 PyYAML>=5.4.1,==5.* cookiecutter~=2.1.1 -aws-sam-translator==1.69.0 +aws-sam-translator==1.70.0 #docker minor version updates can include breaking changes. Auto update micro version only. docker~=6.1.0 dateparser~=1.1 diff --git a/requirements/reproducible-linux.txt b/requirements/reproducible-linux.txt index a6438fc289..6ad1ef3c90 100644 --- a/requirements/reproducible-linux.txt +++ b/requirements/reproducible-linux.txt @@ -19,9 +19,9 @@ aws-lambda-builders==1.34.0 \ --hash=sha256:0790f7e9b7ee7286b96fbcf49450c5be0341bb7cb852ca7d74beae190139eb48 \ --hash=sha256:20456a942a417407b42ecf8ab7fce6a47306fd063051e7cb09d02d1be24d5cf3 # via aws-sam-cli (setup.py) -aws-sam-translator==1.69.0 \ - --hash=sha256:bf26c061675f20367e87d48963ada1ec983a8d897e85db02d0f35913a6174bb0 \ - --hash=sha256:c6ed7a25c77d30d3d31156049415d15fde46c0d3b77a4c5cdc0ef8b53ba9bca2 +aws-sam-translator==1.70.0 \ + --hash=sha256:753288eda07b057e5350773b7617076962b59404d49cd05e2259ac96a7694436 \ + --hash=sha256:a2df321607d29791893707ef2ded9e79be00dbb71ac430696f6e6d7d0b0301a5 # via # aws-sam-cli (setup.py) # cfn-lint diff --git a/requirements/reproducible-mac.txt b/requirements/reproducible-mac.txt index 0122453b5e..c69964a4c7 100644 --- a/requirements/reproducible-mac.txt +++ b/requirements/reproducible-mac.txt @@ -19,9 +19,9 @@ aws-lambda-builders==1.34.0 \ --hash=sha256:0790f7e9b7ee7286b96fbcf49450c5be0341bb7cb852ca7d74beae190139eb48 \ --hash=sha256:20456a942a417407b42ecf8ab7fce6a47306fd063051e7cb09d02d1be24d5cf3 # via aws-sam-cli (setup.py) -aws-sam-translator==1.69.0 \ - --hash=sha256:bf26c061675f20367e87d48963ada1ec983a8d897e85db02d0f35913a6174bb0 \ - --hash=sha256:c6ed7a25c77d30d3d31156049415d15fde46c0d3b77a4c5cdc0ef8b53ba9bca2 +aws-sam-translator==1.70.0 \ + --hash=sha256:753288eda07b057e5350773b7617076962b59404d49cd05e2259ac96a7694436 \ + --hash=sha256:a2df321607d29791893707ef2ded9e79be00dbb71ac430696f6e6d7d0b0301a5 # via # aws-sam-cli (setup.py) # cfn-lint From af26ea2f00d94b8057a48b63ae3fb1e4c8763175 Mon Sep 17 00:00:00 2001 From: Daniel Mil <84205762+mildaniel@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:33:37 -0700 Subject: [PATCH 6/7] Version bump to 1.89.0 (#5420) --- samcli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samcli/__init__.py b/samcli/__init__.py index 705542b65e..48bdee91f7 100644 --- a/samcli/__init__.py +++ b/samcli/__init__.py @@ -2,4 +2,4 @@ SAM CLI version """ -__version__ = "1.88.0" +__version__ = "1.89.0" From 8aa10081f0c6d3cd6a90b8dae334902eb5321432 Mon Sep 17 00:00:00 2001 From: Stephen Liedig Date: Tue, 27 Jun 2023 01:00:33 +0800 Subject: [PATCH 7/7] chore(docs): updated readme with additional resources (#5349) * chore: updated gitignore to ignore tmp scratch directory used by dotnet tests * chore: update readme to include additional workshop resources and missing Powertools links. Fixed formatting --------- Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com> --- .gitignore | 3 +++ README.md | 49 +++++++++++++++++++++++-------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 6b3c26c6e5..784bc4af7c 100644 --- a/.gitignore +++ b/.gitignore @@ -417,8 +417,11 @@ tests/integration/testdata/buildcmd/Dotnet6/obj tests/integration/testdata/buildcmd/Dotnet7/bin tests/integration/testdata/buildcmd/Dotnet7/obj tests/integration/testdata/invoke/credential_tests/inprocess/dotnet/STS/obj +tests/integration/testdata/sync/code/after/dotnet_function/src/HelloWorld/obj/ +tests/integration/testdata/sync/code/before/dotnet_function/src/HelloWorld/obj/ # End of https://www.gitignore.io/api/osx,node,macos,linux,python,windows,pycharm,intellij,sublimetext,visualstudiocode # Installer build folder .build + diff --git a/README.md b/README.md index 452f5c6318..359f085e74 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,14 @@ [Installation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) | [Blogs](https://serverlessland.com/blog?tag=AWS%20SAM) | [Videos](https://serverlessland.com/video?tag=AWS%20SAM) | [AWS Docs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) | [Roadmap](https://github.com/aws/aws-sam-cli/wiki/SAM-CLI-Roadmap) | [Try It Out](https://s12d.com/jKo46elk) | [Slack Us](https://join.slack.com/t/awsdevelopers/shared_invite/zt-yryddays-C9fkWrmguDv0h2EEDzCqvw) The AWS Serverless Application Model (SAM) CLI is an open-source CLI tool that helps you develop serverless applications containing [Lambda functions](https://aws.amazon.com/lambda/), [Step Functions](https://aws.amazon.com/step-functions/), [API Gateway](https://aws.amazon.com/api-gateway/), [EventBridge](https://aws.amazon.com/eventbridge/), [SQS](https://aws.amazon.com/sqs/), [SNS](https://aws.amazon.com/sns/) and more. Some of the features it provides are: -- **Initialize serverless applications** in minutes with AWS-provided infrastructure templates with `sam init` -- **Compile, build, and package** Lambda functions with provided runtimes and with custom Makefile workflows, for zip and image types of Lambda functions with `sam build` -- **Locally test** a Lambda function and API Gateway easily in a Docker container with `sam local` commands on SAM and CDK applications -- **Sync and test your changes in the cloud** with `sam sync` in your developer environments -- **Deploy** your SAM and CloudFormation templates using `sam deploy` -- Quickly **create pipelines** with prebuilt templates with popular CI/CD systems using `sam pipeline init` -- **Tail CloudWatch logs and X-Ray traces** with `sam logs` and `sam traces` +* **Initialize serverless applications** in minutes with AWS-provided infrastructure templates with `sam init` +* **Compile, build, and package** Lambda functions with provided runtimes and with custom Makefile workflows, for zip and image types of Lambda functions with `sam build` +* **Locally test** a Lambda function and API Gateway easily in a Docker container with `sam local` commands on SAM and CDK applications +* **Sync and test your changes in the cloud** with `sam sync` in your developer environments +* **Deploy** your SAM and CloudFormation templates using `sam deploy` +* Quickly **create pipelines** with prebuilt templates with popular CI/CD systems using `sam pipeline init` +* **Tail CloudWatch logs and X-Ray traces** with `sam logs` and `sam traces` ## Recent blogposts and workshops @@ -28,53 +28,51 @@ The AWS Serverless Application Model (SAM) CLI is an open-source CLI tool that h * **Speed up development with SAM Accelerate** - quickly test your changes in the cloud. [Read docs here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/accelerate.html). +* **AWS Serverless Developer Experience Workshop: A day in a life of a developer** - [This advanced workshop](https://s12d.com/aws-sde-workshop) provides you with an immersive experience as a serverless developer, with hands-on experience building a serverless solution using AWS SAM and SAM CLI. + * **The Complete SAM Workshop**- [This workshop](https://s12d.com/jKo46elk) is a great way to experience the power of SAM and SAM CLI. * **Getting started with CI/CD? SAM pipelines can help you get started** - [This workshop](https://s12d.com/_JQ48d5T) walks you through the basics. * **Get started with Serverless Application development using SAM CLI** - [This workshop](https://s12d.com/Tq9ZE-Br) walks you through the basics. - ## Get Started -To get started with building SAM-based applications, use the SAM CLI. SAM CLI provides a Lambda-like execution +To get started with building SAM-based applications, use the SAM CLI. SAM CLI provides a Lambda-like execution environment that lets you locally build, test, debug, and deploy [AWS serverless](https://aws.amazon.com/serverless/) applications. * [Install SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) * [Build & Deploy a "Hello World" Web App](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html) * [Install AWS Toolkit](https://aws.amazon.com/getting-started/tools-sdks/#IDE_and_IDE_Toolkits) to use SAM with your favorite IDEs * [Tutorials and Workshops](https://serverlessland.com/learn) -* [Powertools for AWS Lambda](https://aws.amazon.com/blogs/opensource/simplifying-serverless-best-practices-with-lambda-powertools/) Utilities for building Lambda functions in [Python](https://awslabs.github.io/aws-lambda-powertools-python/latest/), [Java](https://github.com/awslabs/aws-lambda-powertools-java), and [TypeScript](https://github.com/awslabs/aws-lambda-powertools-typescript) - +* **Powertools for AWS Lambda** is a developer toolkit to implement Serverless best practices and increase developer velocity. Available for [Python](https://awslabs.github.io/aws-lambda-powertools-python), [Java](https://github.com/awslabs/aws-lambda-powertools-java), [TypeScript](https://github.com/awslabs/aws-lambda-powertools-typescript) and [.NET](https://github.com/awslabs/aws-lambda-powertools-dotnet). **Next Steps:** Learn to build a more complex serverless application. + * [Extract text from images and store it in a database](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-example-s3.html) using Amazon S3 and Amazon Rekognition services. * [Detect when records are added to a database](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-example-ddb.html) using Amazon DynamoDB database and asynchronous stream processing. * [Explore popular patterns](https://serverlessland.com/patterns) - ## What is this Github repository? 💻 This Github repository contains source code for SAM CLI. Here is the development team talking about this code: -> SAM CLI code is written in Python. Source code is well documented, very modular, with 95% unit test coverage. +> SAM CLI code is written in Python. Source code is well documented, very modular, with 95% unit test coverage. It uses this awesome Python library called Click to manage the command line interaction and uses Docker to run Lambda functions locally. We think you'll like the code base. Clone it and run `make pr` or `./Make -pr` on Windows! - ## Related Repositories and Resources -+ **SAM Transform** [Open source template specification](https://github.com/aws/serverless-application-model/) that provides shorthand syntax for CloudFormation -+ **SAM CLI application templates** Get started quickly with [predefined application templates](https://github.com/aws/aws-sam-cli-app-templates/blob/master/README.md) for all supported runtimes and languages, used by `sam init` -+ **Lambda Builders** [Lambda builder tools](https://github.com/aws/aws-lambda-builders) for supported runtimes and custom build workflows, used by `sam build` -+ **Build and local emulation images for CI/CD tools** [Build container images](https://gallery.ecr.aws/sam/) to use with CI/CD tasks - +* **SAM Transform** [Open source template specification](https://github.com/aws/serverless-application-model/) that provides shorthand syntax for CloudFormation +* **SAM CLI application templates** Get started quickly with [predefined application templates](https://github.com/aws/aws-sam-cli-app-templates/blob/master/README.md) for all supported runtimes and languages, used by `sam init` +* **Lambda Builders** [Lambda builder tools](https://github.com/aws/aws-lambda-builders) for supported runtimes and custom build workflows, used by `sam build` +* **Build and local emulation images for CI/CD tools** [Build container images](https://gallery.ecr.aws/sam/) to use with CI/CD tasks ## Contribute to SAM -We love our contributors ❤️ We have over 100 contributors who have built various parts of the product. +We love our contributors ❤️ We have over 100 contributors who have built various parts of the product. Read this [testimonial from @ndobryanskyy](https://www.lohika.com/aws-sam-my-exciting-first-open-source-experience/) to learn -more about what it was like contributing to SAM. +more about what it was like contributing to SAM. Depending on your interest and skill, you can help build the different parts of the SAM project; @@ -84,21 +82,20 @@ Make pull requests, report bugs, and share ideas to improve the full SAM templat Source code is located on Github at [aws/serverless-application-model](https://github.com/aws/serverless-application-model). Read the [SAM Specification Contributing Guide](https://github.com/aws/serverless-application-model/blob/master/CONTRIBUTING.md) to get started. - + **Strengthen SAM CLI** Add new commands, enhance existing ones, report bugs, or request new features for the SAM CLI. Source code is located on Github at [aws/aws-sam-cli](https://github.com/aws/aws-sam-cli). Read the [SAM CLI Contributing Guide](https://github.com/aws/aws-sam-cli/blob/develop/CONTRIBUTING.md) to -get started. +get started. **Update SAM Developer Guide** [SAM Developer Guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/index.html) provides a comprehensive getting started guide and reference documentation. Source code is located on Github at [awsdocs/aws-sam-developer-guide](https://github.com/awsdocs/aws-sam-developer-guide). Read the [SAM Documentation Contribution Guide](https://github.com/awsdocs/aws-sam-developer-guide/blob/master/CONTRIBUTING.md) to get -started. - +started. ### Join the SAM Community on Slack -[Join the SAM developers channel (#samdev)](https://join.slack.com/t/awsdevelopers/shared_invite/zt-yryddays-C9fkWrmguDv0h2EEDzCqvw) on Slack to collaborate with fellow community members and the AWS SAM team. +[Join the SAM developers channel (#samdev)](https://join.slack.com/t/awsdevelopers/shared_invite/zt-yryddays-C9fkWrmguDv0h2EEDzCqvw) on Slack to collaborate with fellow community members and the AWS SAM team. \ No newline at end of file