Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 248 additions & 0 deletions .github/workflows/examples.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
name: Verify Examples

on:
pull_request:
branches:
- main
paths:
- "examples/**"
push:
branches:
- main
paths:
- "src/**"
workflow_dispatch:

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
validate:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v4
with:
python-version: "3.13"

- uses: aws-actions/setup-sam@v2
with:
use-installer: true
token: ${{ secrets.GITHUB_TOKEN }}

- name: Validate all SAM templates
run: |
failed=0
for template in $(find examples -maxdepth 2 -name "template.yaml" | sort); do
dir=$(dirname "$template")
echo "Validating $dir..."
if ! sam validate --template "$template" --lint 2>&1; then
echo "FAIL: $dir"
failed=1
fi
done
if [ "$failed" -eq 1 ]; then
echo "Some templates failed validation"
exit 1
fi

build-layer:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Install stable toolchain
run: rustup target add x86_64-unknown-linux-musl

- name: Install cargo lambda
run: pip3 install cargo-lambda

- name: Configure Rust cache
uses: Swatinem/rust-cache@v2

- name: Build x86_64 layer
run: |
cargo lambda build --release --extension --target x86_64-unknown-linux-musl
mkdir -p layer-x86_64
cp layer/bootstrap layer-x86_64/
cp target/lambda/extensions/lambda-adapter layer-x86_64/

- uses: actions/upload-artifact@v4
with:
name: layer-x86_64
path: layer-x86_64/

# Docker-based examples verified with sam local start-api.
# Excluded: nginx, php, flask, aspnet-mvc (web app hardcodes port 8080
# which conflicts with SAM's Lambda Runtime Interface Emulator).
test-image:
needs: [build-layer]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
example:
- expressjs
- fastapi
- fastapi-background-tasks
- fasthtml
- gin
- nextjs
- remix
- springboot
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v4
with:
python-version: "3.13"

- uses: aws-actions/setup-sam@v2
with:
use-installer: true
token: ${{ secrets.GITHUB_TOKEN }}

- uses: actions/download-artifact@v4
with:
name: layer-x86_64
path: /tmp/layer-x86_64

- name: Build local adapter image
run: |
printf 'FROM scratch\nCOPY lambda-adapter /lambda-adapter\n' | \
docker build -t public.ecr.aws/awsguru/aws-lambda-adapter:1.0.0-rc1 -f- /tmp/layer-x86_64

- name: Build
working-directory: examples/${{ matrix.example }}
run: sam build

- name: Start local API and verify
working-directory: examples/${{ matrix.example }}
run: |
# Set PORT=8000 to avoid conflict with SAM's RIE on port 8080
echo '{"Parameters":{"PORT":"8000"}}' > /tmp/env.json
sam local start-api --port 3000 --warm-containers EAGER --container-env-vars /tmp/env.json &
SAM_PID=$!
echo "SAM_PID=$SAM_PID" >> $GITHUB_ENV

echo "Waiting for local API to start..."
for i in $(seq 1 90); do
if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/ 2>/dev/null | grep -q "^[2345]"; then
echo "API is ready after ${i}s"
break
fi
if [ "$i" -eq 90 ]; then
echo "API failed to start within 90s"
kill $SAM_PID 2>/dev/null || true
exit 1
fi
sleep 1
done

status=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/)
echo "HTTP status: $status"
if [[ "$status" -ge 200 && "$status" -lt 500 ]]; then
echo "OK: Got valid response"
else
echo "FAIL: Unexpected status $status"
kill $SAM_PID 2>/dev/null || true
exit 1
fi

- name: Stop local API
if: always()
run: kill $SAM_PID 2>/dev/null || true

# Zip-based examples verified with local layer.
# Excluded: aspnet-*-zip (hardcode port 8080),
# bun/nginx/php-zip (need third-party layers), arm64 examples (javalin, rust-*).
test-zip:
needs: [build-layer]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
example:
- deno-zip
- expressjs-zip
- fastapi-zip
- fasthtml-zip
- flask-zip
- gin-zip
- nextjs-zip
- remix-zip
- springboot-zip
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v4
with:
python-version: "3.13"

- uses: aws-actions/setup-sam@v2
with:
use-installer: true
token: ${{ secrets.GITHUB_TOKEN }}

- uses: actions/download-artifact@v4
with:
name: layer-x86_64
path: /tmp/layer-x86_64

- name: Prepare local layer
run: |
LAYER_DIR="/tmp/local-layers/LambdaAdapterLayerX86"
mkdir -p "$LAYER_DIR/extensions"
cp /tmp/layer-x86_64/bootstrap "$LAYER_DIR/"
cp /tmp/layer-x86_64/lambda-adapter "$LAYER_DIR/extensions/"
chmod +x "$LAYER_DIR/extensions/lambda-adapter" "$LAYER_DIR/bootstrap"

- name: Patch template to use local layer
working-directory: examples/${{ matrix.example }}
run: |
sed -i 's|!Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:[0-9]*|/tmp/local-layers/LambdaAdapterLayerX86|' template.yaml

- name: Build
working-directory: examples/${{ matrix.example }}
run: sam build

- name: Start local API and verify
working-directory: examples/${{ matrix.example }}
run: |
# Set PORT=8000 to avoid conflict with SAM's RIE on port 8080
echo '{"Parameters":{"PORT":"8000"}}' > /tmp/env.json
sam local start-api --port 3000 --warm-containers EAGER --container-env-vars /tmp/env.json &
SAM_PID=$!
echo "SAM_PID=$SAM_PID" >> $GITHUB_ENV

echo "Waiting for local API to start..."
for i in $(seq 1 90); do
if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/ 2>/dev/null | grep -q "^[2345]"; then
echo "API is ready after ${i}s"
break
fi
if [ "$i" -eq 90 ]; then
echo "API failed to start within 90s"
kill $SAM_PID 2>/dev/null || true
exit 1
fi
sleep 1
done

status=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/)
echo "HTTP status: $status"
if [[ "$status" -ge 200 && "$status" -lt 500 ]]; then
echo "OK: Got valid response"
else
echo "FAIL: Unexpected status $status"
kill $SAM_PID 2>/dev/null || true
exit 1
fi

- name: Stop local API
if: always()
run: kill $SAM_PID 2>/dev/null || true
Loading