Skip to content
Closed
Show file tree
Hide file tree
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
79 changes: 4 additions & 75 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ on:
type: boolean
description: "Boolean to enable the test of the archive plugin. Defaults to true."
default: true
archive_plugin_swift64_enabled:
type: boolean
description: "Boolean to enable the Swift 6.4 packaging plugin test (archive + lambda-build). Defaults to true."
default: true
archive_plugin_swift64_container_image:
type: string
description: "Container image providing the Swift 6.4+ toolchain for the packaging plugin test."
default: "swiftlang/swift:nightly-6.4.x-bookworm"
check_foundation_enabled:
type: boolean
description: "Boolean to enable the check for Foundation dependency. Defaults to true."
Expand All @@ -49,9 +41,8 @@ on:
required: true
matrix_linux_swift_container_image:
type: string
# Note: we don't use Amazon Linux 2 here because zip is not installed by default.
description: "Container image for the matrix test jobs. Defaults to Swift 6.3"
default: "swift:6.3"
description: "Container image for the matrix test jobs. Defaults to Swift 6.4"
default: "swiftlang/swift:nightly-6.4.x-bookworm"

## We are cancelling previously triggered workflow runs
concurrency:
Expand Down Expand Up @@ -106,7 +97,8 @@ jobs:
fail-fast: false
matrix:
examples: ${{ fromJson(inputs.archive_plugin_examples) }}
# These must run on Ubuntu and not in a container, because the plugin uses docker
# These must run on bare Ubuntu and not in a container: the plugin shells out to the host
# docker daemon, and we can't run docker inside a docker job container.
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -129,69 +121,6 @@ jobs:
run: |
.github/workflows/scripts/check-archive-plugin.sh

test-archive-plugin-swift64:
name: Test packaging plugins (Swift 6.4)
if: ${{ inputs.archive_plugin_swift64_enabled }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
examples: ${{ fromJson(inputs.archive_plugin_examples) }}
# Runs in the Swift 6.4 container so that `swift(>=6.4)` is true and the new
# helper-delegating `archive` verb and the new `lambda-build` verb are compiled.
#
# The packaging plugins shell out to the HOST docker daemon (socket mounted below).
# The plugin builds the example inside an Amazon Linux container and bind-mounts the
# checkout into it. Because the daemon runs on the host, the bind-mount source must be
# a HOST path: GitHub mounts the host work dir (/home/runner/work) at /__w inside this
# job container, so a path like /__w/... does not exist for the host daemon. We mount
# /home/runner/work at the SAME path here, and the test step runs the plugin from that
# host-equivalent path, so the inner `docker run -v <src>:/workspace` source resolves
# correctly on the host.
container:
image: ${{ inputs.archive_plugin_swift64_container_image }}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/runner/work:/home/runner/work
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Cache SPM dependencies
uses: actions/cache@v5
with:
# Cache the whole .build, not just checkouts/repositories. The plugins
# delegate to AWSLambdaPluginHelper, which links the SotoCore/NIO stack;
# compiling that on the host takes ~220s per run. Caching .build lets
# SwiftPM reuse the unchanged dependency objects and rebuild only the
# sources that changed.
path: Examples/${{ matrix.examples }}/.build
key: spm-swift64-${{ runner.os }}-${{ matrix.examples }}-${{ hashFiles(format('Examples/{0}/Package.swift', matrix.examples)) }}
restore-keys: |
spm-swift64-${{ runner.os }}-${{ matrix.examples }}-

- name: Install dependencies
run: |
apt-get -qq update
apt-get -qq -y install docker.io zip unzip file libssl-dev

- name: Test the packaging plugins
env:
EXAMPLE: ${{ matrix.examples }}
run: |
# GitHub mounts the host work dir (/home/runner/work) at /__w inside this
# container, so $GITHUB_WORKSPACE is /__w/<repo>/<repo>. The plugin shells out
# to the host docker daemon, which cannot resolve /__w paths. We mounted
# /home/runner/work at the same path, so re-enter the checkout via the
# host-equivalent path before running the plugin.
# NOTE: this step runs under `sh` (dash) inside the container, so we use
# POSIX `sed` rather than a bash-only `${var/a/b}` substitution.
HOST_WORKSPACE=$(printf '%s\n' "$GITHUB_WORKSPACE" | sed 's#^/__w/#/home/runner/work/#')
cd "${HOST_WORKSPACE}"
.github/workflows/scripts/check-archive-plugin-swift64.sh

check-foundation:
name: No dependencies on Foundation
if: ${{ inputs.check_foundation_enabled }}
Expand Down
17 changes: 7 additions & 10 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
license_header_check_project_name: "SwiftAWSLambdaRuntime"
shell_check_enabled: true
python_lint_check_enabled: true
api_breakage_check_container_image: "swift:6.3-noble"
docs_check_container_image: "swift:6.3-noble"
format_check_container_image: "swift:6.3-noble"
api_breakage_check_container_image: "swiftlang/swift:nightly-6.4.x-bookworm"
docs_check_container_image: "swiftlang/swift:nightly-6.4.x-bookworm"
format_check_container_image: "swiftlang/swift:nightly-6.4.x-bookworm"
yamllint_check_enabled: true
docs_check_enabled: true

Expand All @@ -26,11 +26,10 @@ jobs:
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
with:
enable_windows_checks: false
# nightly-main (6.5-dev) is temporarily excluded: the compiler crashes with a SIL
# verification error while compiling AWSLambdaRuntimeTests. This is a toolchain bug
# (the same code compiles on 6.1-6.4), not an issue in this package. Remove the
# nightly-main entry once fixed upstream: https://github.com/swiftlang/swift/issues/90211
linux_exclude_swift_versions: "[{\"swift_version\": \"5.9\"}, {\"swift_version\": \"5.10\"}, {\"swift_version\": \"6.0\"}, {\"swift_version\": \"nightly-main\"}]"
linux_exclude_swift_versions: "[{\"swift_version\": \"5.9\"}, {\"swift_version\": \"5.10\"}, {\"swift_version\": \"6.0\"}, {\"swift_version\": \"6.1\"}]"
# The ZipArchiveBackend tests shell out to the `zip` CLI, which the official Swift Linux
# container images do not ship by default. Install it before running the unit tests.
linux_pre_build_command: "apt-get update -y && apt-get install -y zip"
swift_flags: "--explicit-target-dependency-import-check error"
swift_nightly_flags: "--explicit-target-dependency-import-check error"
enable_linux_static_sdk_build: true
Expand All @@ -55,8 +54,6 @@ jobs:
examples: "[ 'APIGatewayV1', 'APIGatewayV2', 'APIGatewayV2+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'HelloWorldNoTraits', 'HummingbirdLambda', 'ManagedInstances', 'MultiSourceAPI', 'MultiTenant', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming+APIGateway', 'Streaming+FunctionUrl', 'Streaming+Codable', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]"
archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]"
archive_plugin_enabled: true
archive_plugin_swift64_enabled: true
archive_plugin_swift64_container_image: "swiftlang/swift:nightly-6.4.x-bookworm"

semver-label-check:
name: Semantic Version label check
Expand Down
98 changes: 0 additions & 98 deletions .github/workflows/scripts/check-archive-plugin-swift64.sh

This file was deleted.

75 changes: 50 additions & 25 deletions .github/workflows/scripts/check-archive-plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
##
##===----------------------------------------------------------------------===##

# This script validates the packaging plugins

set -euo pipefail

log() { printf -- "** %s\n" "$*" >&2; }
error() { printf -- "** ERROR: %s\n" "$*" >&2; }
fatal() { error "$@"; exit 1; }
Expand All @@ -22,36 +26,57 @@ test -n "${EXAMPLE:-}" || fatal "EXAMPLE unset"
# Use the local checkout of swift-aws-lambda-runtime instead of the published release
.github/workflows/scripts/use-local-deps.sh "Examples/${EXAMPLE}/Package.swift"

OUTPUT_DIR=.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager
OUTPUT_FILE=${OUTPUT_DIR}/MyLambda/bootstrap
ZIP_FILE=${OUTPUT_DIR}/MyLambda/MyLambda.zip
# The product name is "MyLambda" in both HelloWorld and ResourcesPackaging.
PRODUCT=MyLambda

pushd "Examples/${EXAMPLE}" >/dev/null || exit 1

pushd "Examples/${EXAMPLE}" || exit 1
# ---------------------------------------------------------------------------
# Assert that a given output directory contains a valid Linux bootstrap and ZIP.
# $1: human-readable label of the verb under test
# $2: path to the plugin output directory (containing <PRODUCT>/)
# ---------------------------------------------------------------------------
verify_output() {
local label="$1"
local output_dir="$2"
local bootstrap="${output_dir}/${PRODUCT}/bootstrap"
local zip_file="${output_dir}/${PRODUCT}/${PRODUCT}.zip"

# package the example (docker and swift toolchain are installed on the GH runner)
LAMBDA_USE_LOCAL_DEPS=../.. swift package archive --allow-network-connections docker --base-docker-image swift:amazonlinux2023 || exit 1
log "Verifying output of '${label}'"

# did the plugin generated a Linux binary?
[ -f "${OUTPUT_FILE}" ]
file "${OUTPUT_FILE}" | grep --silent ELF
# did the plugin generate a Linux binary?
[ -f "${bootstrap}" ] || fatal "${label}: bootstrap not found at ${bootstrap}"
file "${bootstrap}" | grep --silent ELF || fatal "${label}: bootstrap is not an ELF binary"

# did the plugin created a ZIP file?
[ -f "${ZIP_FILE}" ]
# did the plugin create a ZIP file?
[ -f "${zip_file}" ] || fatal "${label}: ZIP not found at ${zip_file}"

# does the ZIP file contain the bootstrap?
unzip -l "${ZIP_FILE}" | grep --silent bootstrap
# does the ZIP file contain the bootstrap?
unzip -l "${zip_file}" | grep --silent bootstrap || fatal "${label}: bootstrap missing from ZIP"

# if EXAMPLE is ResourcesPackaging, check if the ZIP file contains hello.txt
if [ "$EXAMPLE" == "ResourcesPackaging" ]; then
echo "Checking if resource was added to the ZIP file"
unzip -l "${ZIP_FILE}" | grep --silent hello.txt
SUCCESS=$?
if [ "$SUCCESS" -eq 1 ]; then
log "❌ Resource not found." && exit 1
else
log "✅ Resource found."
# if EXAMPLE is ResourcesPackaging, check the ZIP file contains hello.txt
if [ "$EXAMPLE" == "ResourcesPackaging" ]; then
log "${label}: checking that the resource was added to the ZIP file"
if unzip -l "${zip_file}" | grep --silent hello.txt; then
log "✅ ${label}: resource found."
else
fatal "❌ ${label}: resource hello.txt not found in ZIP."
fi
fi
fi

echo "✅ The archive plugin is OK with example ${EXAMPLE}"
popd || exit 1
log "✅ ${label}: output is OK for example ${EXAMPLE}"
}

# ---------------------------------------------------------------------------
# 1. 'lambda-build' verb
# ---------------------------------------------------------------------------
log "Testing 'lambda-build' verb"
BUILD_OUTPUT_DIR=.build/plugins/AWSLambdaBuilder/outputs/AWSLambdaBuilder
LAMBDA_USE_LOCAL_DEPS=../.. swift package lambda-build \
--allow-network-connections docker \
--products "${PRODUCT}" \
--base-docker-image swift:amazonlinux2023 || fatal "'lambda-build' verb failed"
verify_output "lambda-build" "${BUILD_OUTPUT_DIR}"

echo "✅ 'lambda-build' is OK with example ${EXAMPLE}"
popd >/dev/null || exit 1
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.DS_Store
*.build
*.build*
*.index-build
/.xcodeproj
*.pem
Expand Down
25 changes: 25 additions & 0 deletions Examples/JSONLogging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@ The Lambda function demonstrates various logging levels and metadata usage. When
}
```

## Logging from helper functions with `Logger.current`

The runtime binds the per-invocation logger as the task-local [`Logger.current`](https://github.com/apple/swift-log) for the duration of each handler call. This means functions your handler calls can log with the request's metadata (request ID, trace ID) **without** receiving a `LambdaContext` or `Logger` parameter:

```swift
func validate(_ event: Request) {
Logger.current.debug("Validating request", metadata: ["name": .string(event.name)])
if event.name.isEmpty {
Logger.current.warning("Received a request with an empty name")
}
}

let runtime = LambdaRuntime { (event: Request, context: LambdaContext) in
context.logger.info("Processing request for \(event.name)")
validate(event) // its logs carry this invocation's request ID and trace ID automatically
// ...
}
```

This keeps your business code clean — no need to thread a logger through every function signature. Inside the handler itself, `context.logger` and `Logger.current` are equivalent.

> **Notes**
> - Automatic binding requires **Swift 6.2 or later**. On older toolchains, `Logger.current` falls back to the process-wide default logger (without the request metadata).
> - Task-local values propagate through structured concurrency (`async let`, `withTaskGroup`, child `Task {}`) but are **not** inherited by `Task.detached` — capture the logger explicitly across a detached boundary.

## Configuration

### Environment Variables
Expand Down
Loading
Loading