diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c2b4a4..93c6997 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,6 +71,7 @@ jobs: - "ruby32" - "ruby33" - "ruby34" + - "ruby40" include: - skip_arm_test: false - runtime: "dotnet8" diff --git a/Makefile b/Makefile index 7c364c5..359ba35 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ IS_python314 := python3.14 IS_ruby32 := ruby3.2 IS_ruby33 := ruby3.3 IS_ruby34 := ruby3.4 +IS_ruby40 := ruby4.0 init: pip install -Ur requirements.txt diff --git a/build-image-src/Dockerfile-ruby40 b/build-image-src/Dockerfile-ruby40 new file mode 100644 index 0000000..f8a7551 --- /dev/null +++ b/build-image-src/Dockerfile-ruby40 @@ -0,0 +1,61 @@ +ARG IMAGE_ARCH +FROM public.ecr.aws/lambda/ruby:4.0-$IMAGE_ARCH + +RUN dnf remove -y microdnf-dnf && \ + microdnf install -y dnf + +RUN dnf groupinstall -y development && \ + dnf install -y \ + tar \ + gzip \ + unzip \ + python3 \ + jq \ + grep \ + make \ + rsync \ + binutils \ + gcc-c++ \ + procps \ + gmp-devel \ + zlib-devel \ + libmpc-devel \ + python3-devel \ + libyaml-devel \ + && dnf clean all + +RUN dnf upgrade -y --releasever=latest + +# Install AWS CLI +ARG AWS_CLI_ARCH +RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$AWS_CLI_ARCH.zip" -o "awscliv2.zip" && unzip awscliv2.zip && ./aws/install && rm awscliv2.zip && rm -rf ./aws + +# Install SAM CLI from native installer +ARG SAM_CLI_VERSION +# need to redefine since ARG is not available after FROM tag: https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact +ARG IMAGE_ARCH +RUN curl -L "https://github.com/aws/aws-sam-cli/releases/download/v$SAM_CLI_VERSION/aws-sam-cli-linux-$IMAGE_ARCH.zip" -o "samcli.zip" && \ + unzip samcli.zip -d sam-installation && ./sam-installation/install && \ + rm samcli.zip && rm -rf sam-installation && sam --version + +# Prepare virtualenv for lambda builders +RUN python3 -m venv --without-pip /usr/local/opt/lambda-builders +RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +RUN /usr/local/opt/lambda-builders/bin/python3 get-pip.py +# Install lambda builders in a dedicated Python virtualenv +RUN AWS_LB_VERSION=$(curl -sSL https://raw.githubusercontent.com/aws/aws-sam-cli/v$SAM_CLI_VERSION/pyproject.toml | grep aws_lambda_builders | cut -d'=' -f3 | tr -d '",') && \ + /usr/local/opt/lambda-builders/bin/pip3 --no-cache-dir install "aws-lambda-builders==$AWS_LB_VERSION" + +ENV PATH=$PATH:/usr/local/opt/lambda-builders/bin + +ENV LANG=en_US.UTF-8 + +# Wheel is required by SAM CLI to build libraries like cryptography. It needs to be installed in the system +# Python for it to be picked up during `sam build` +RUN pip3 install wheel==0.45.1 + +COPY ATTRIBUTION.txt / + +# Compatible with initial base image +ENTRYPOINT [] +CMD ["/bin/bash"] diff --git a/build-image-src/build_all_images.sh b/build-image-src/build_all_images.sh index 1a6e86f..c6bbf44 100755 --- a/build-image-src/build_all_images.sh +++ b/build-image-src/build_all_images.sh @@ -4,19 +4,17 @@ set -e # Of course, you can also run a single one of these commands manually. # If you use this script, ensure that you run with --skip-pull-image, else the remote image may be used. -if [ -z ${SAM_CLI_VERSION+x} ]; -then - echo "Must set SAM_CLI_VERSION to run this script." - exit 1; +if [ -z ${SAM_CLI_VERSION+x} ]; then + echo "Must set SAM_CLI_VERSION to run this script." + exit 1 else - echo "SAM CLI VERSION: $SAM_CLI_VERSION"; + echo "SAM CLI VERSION: $SAM_CLI_VERSION" fi # Disable DOCKER_CONTENT_TRUST for pulling from public ECR export DOCKER_CONTENT_TRUST=0 export DOCKER_CLI_EXPERIMENTAL=enabled - # Multi arch images # First build all x86 docker build -f Dockerfile-dotnet6 -t amazon/aws-sam-cli-build-image-dotnet6:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & @@ -46,6 +44,7 @@ docker build -f Dockerfile-python314 -t amazon/aws-sam-cli-build-image-python3.1 docker build -f Dockerfile-ruby32 -t amazon/aws-sam-cli-build-image-ruby3.2:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-ruby33 -t amazon/aws-sam-cli-build-image-ruby3.3:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & docker build -f Dockerfile-ruby34 -t amazon/aws-sam-cli-build-image-ruby3.4:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & +docker build -f Dockerfile-ruby40 -t amazon/aws-sam-cli-build-image-ruby4.0:x86_64 --platform linux/amd64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=x86_64 --build-arg IMAGE_ARCH=x86_64 . & wait # Build arm64 images @@ -77,4 +76,5 @@ docker build -f Dockerfile-python314 -t amazon/aws-sam-cli-build-image-python3.1 docker build -f Dockerfile-ruby32 -t amazon/aws-sam-cli-build-image-ruby3.2:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-ruby33 -t amazon/aws-sam-cli-build-image-ruby3.3:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & docker build -f Dockerfile-ruby34 -t amazon/aws-sam-cli-build-image-ruby3.4:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & +docker build -f Dockerfile-ruby40 -t amazon/aws-sam-cli-build-image-ruby4.0:arm64 --platform linux/arm64 --build-arg SAM_CLI_VERSION=$SAM_CLI_VERSION --build-arg AWS_CLI_ARCH=aarch64 --build-arg IMAGE_ARCH=arm64 . & wait diff --git a/pytest.ini b/pytest.ini index d4b8055..562e606 100644 --- a/pytest.ini +++ b/pytest.ini @@ -83,3 +83,6 @@ markers = ruby34 ruby34x86_64 ruby34arm64 + ruby40 + ruby40x86_64 + ruby40arm64 diff --git a/tests/apps/ruby4.0/sam-test-app/sam-test-app/Gemfile b/tests/apps/ruby4.0/sam-test-app/sam-test-app/Gemfile new file mode 100644 index 0000000..b566789 --- /dev/null +++ b/tests/apps/ruby4.0/sam-test-app/sam-test-app/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +gem "httparty" + +group :test do + gem "test-unit" + gem "mocha" +end diff --git a/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/Gemfile b/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/Gemfile new file mode 100644 index 0000000..c4ce820 --- /dev/null +++ b/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +gem "httparty" + +ruby '~> 4.0.0' diff --git a/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/app.rb b/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/app.rb new file mode 100644 index 0000000..e2a102f --- /dev/null +++ b/tests/apps/ruby4.0/sam-test-app/sam-test-app/hello_world/app.rb @@ -0,0 +1,38 @@ +# require 'httparty' +require 'json' + +def lambda_handler(event:, context:) + # Sample pure Lambda function + + # Parameters + # ---------- + # event: Hash, required + # API Gateway Lambda Proxy Input Format + # Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format + + # context: object, required + # Lambda Context runtime methods and attributes + # Context doc: https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html + + # Returns + # ------ + # API Gateway Lambda Proxy Output Format: dict + # 'statusCode' and 'body' are required + # # api-gateway-simple-proxy-for-lambda-output-format + # Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html + + # begin + # response = HTTParty.get('http://checkip.amazonaws.com/') + # rescue HTTParty::Error => error + # puts error.inspect + # raise error + # end + + { + statusCode: 200, + body: { + message: "Hello World!", + # location: response.body + }.to_json + } +end diff --git a/tests/apps/ruby4.0/sam-test-app/sam-test-app/template.yaml b/tests/apps/ruby4.0/sam-test-app/sam-test-app/template.yaml new file mode 100644 index 0000000..2f34e62 --- /dev/null +++ b/tests/apps/ruby4.0/sam-test-app/sam-test-app/template.yaml @@ -0,0 +1,39 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + sam-test-app11 + + Sample SAM Template for sam-test-app11 + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 3 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: hello_world/ + Handler: app.lambda_handler + Runtime: ruby4.0 + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/tests/test_build_images.py b/tests/test_build_images.py index c7b8a50..bbe3a21 100644 --- a/tests/test_build_images.py +++ b/tests/test_build_images.py @@ -1019,6 +1019,36 @@ def test_packages(self): self.assertTrue(self.is_architecture("aarch64")) +@pytest.mark.ruby40x86_64 +class TestBIRuby40(AL2023BasedBuildImageBase): + __test__ = True + + @classmethod + def setUpClass(cls): + super().setUpClass("ruby4.0", "Dockerfile-ruby40", "bundler", tag="x86_64") + + def test_packages(self): + self.assertTrue(self.check_package_output("ruby --version", "ruby 4.0.")) + self.assertTrue(self.is_package_present("bundler")) + self.assertTrue(self.is_package_present("gem")) + self.assertTrue(self.is_architecture("x86_64")) + + +@pytest.mark.ruby40arm64 +class TestBIRuby40ForArm(AL2023BasedBuildImageBase): + __test__ = True + + @classmethod + def setUpClass(cls): + super().setUpClass("ruby4.0", "Dockerfile-ruby40", "bundler", tag="arm64") + + def test_packages(self): + self.assertTrue(self.check_package_output("ruby --version", "ruby 4.0.")) + self.assertTrue(self.is_package_present("bundler")) + self.assertTrue(self.is_package_present("gem")) + self.assertTrue(self.is_architecture("aarch64")) + + @pytest.mark.provided_al2x86_64 class TestBIProvidedAL2(BuildImageBase): __test__ = True