Skip to content

v2 Plugin System: lambda-init, lambda-build, lambda-deploy#567

Draft
sebsto wants to merge 42 commits into
mainfrom
sebsto/new-plugins
Draft

v2 Plugin System: lambda-init, lambda-build, lambda-deploy#567
sebsto wants to merge 42 commits into
mainfrom
sebsto/new-plugins

Conversation

@sebsto

@sebsto sebsto commented Sep 23, 2025

Copy link
Copy Markdown
Collaborator

This PR delivers the v4 plugin system, replacing the legacy single-purpose archive plugin with three focused SwiftPM command plugins that cover the end-to-end developer experience:

  • lambda-init — Scaffold a new Lambda function from a template
  • lambda-build — Compile and package for Amazon Linux 2023 (via Docker or Apple container)
  • lambda-deploy — Deploy to AWS Lambda (create, update, or delete)

The legacy archive command is preserved as a deprecated passthrough to lambda-build.

Dependencies

Important

This PR depends on soto-project/soto-core#694 (fixes soto-project/soto-core#693) being merged and released.

Before merging this PR, the Package.swift dependency on soto-core must be reverted from the temporary branch on my fork (sebsto/soto-core, branch remove-platforms-use-availability-macro) back to the official repository:

.package(url: "https://github.com/soto-project/soto-core.git", from: "<version-with-fix>")

CI: API Breakage Check False Positives

Note

The CI "API breakage check" reports 33 false-positive "removed" types. This is a known SwiftPM bug (swiftlang/swift-package-manager#8081, #9254).

Root cause: The plugins depend on AWSLambdaPluginHelper which depends on soto-core. soto-core and its transitive dependencies bring C targets (CSotoExpat, CNIOBoringSSL, CNIOBoringSSLShims) that get built for both .host (plugin) and .target (library) destinations. The API digester receives -I paths for both builds, triggering silent "redefinition of module" errors that prevent it from loading AWSLambdaRuntime. All symbols then appear as "removed".

The AWSLambdaRuntime source code is unchanged between this branch and main. There are no actual API breakages. A partial fix landed in Swift 6.3.2 (PR #8776) for Swift targets, but Clang targets remain unfiltered. The full fix is tracked in PR #7664.

Quick Start

# Create a new project
swift package init --type executable --name MyLambda

# Scaffold a Lambda function
swift package lambda-init --allow-writing-to-package-directory

# Build for Amazon Linux
swift package --allow-network-connections docker lambda-build

# Deploy to AWS
swift package --allow-network-connections all:443 lambda-deploy

# Delete when done
swift package --allow-network-connections all:443 lambda-deploy --delete

Key Changes

Architecture

  • All plugins are thin wrappers that spawn a shared AWSLambdaPluginHelper executable
  • The helper dispatches to Initializer, Builder, or Deployer based on argv[1]
  • AWS API calls use generated service clients (Lambda, IAM, S3, STS) built on SotoCore

Builder (lambda-build)

  • Default base image changed from amazonlinux2 to amazonlinux2023
  • AL2 blanket deprecation warning removed; targeted warning only when AL2 explicitly chosen
  • New --cross-compile option (replaces --container-cli): docker, container, swift-static-sdk, custom-sdk
  • Default binary stripping with -Xlinker -s and --no-strip opt-out
  • --output-directory accepted as deprecated alias for --output-path
  • Container CLI existence check with helpful install URLs

Deployer (lambda-deploy)

  • Creates/updates/deletes Lambda functions with full IAM role lifecycle
  • Auto-creates IAM role with AWSLambdaBasicExecutionRole
  • S3 staging for archives > 50 MB
  • Function URL support with IAM auth (account-scoped, not world-accessible)
  • Auto-detects FunctionURLRequest usage in source code to enable URL without explicit --with-url
  • Ready-to-use invocation commands in deploy output

Initializer (lambda-init)

  • Detects the actual entry point file (supports both Sources/main.swift and Sources/<Name>/<Name>.swift)
  • Backs up existing file before overwriting

Dependencies

  • Added soto-core for AWS credential management, SigV4 signing, and HTTP transport
  • Removed vendored crypto/signer/HTTP code under Vendored/
  • Generated AWS service clients committed to the repository (maintainer-run generation script)

Backward Compatibility

  • swift package archive preserved as deprecated alias (emits warning, delegates to lambda-build)
  • --container-cli accepted as deprecated alias for --cross-compile
  • --output-directory accepted as deprecated alias for --output-path
  • All original archive CLI options continue to work

Documentation

  • Updated DocC articles, tutorials, and quick-setup guide
  • Updated all example READMEs with new plugin commands
  • SAM/CDK examples preserved with their respective deployment tools

Known Limitations

Testing

  • Unit tests for BuilderConfiguration and DeployerConfiguration argument parsing
  • Property-based tests for correctness properties (alias equivalence, cross-compile round-trip, mutual exclusion, bucket naming, archive threshold, AL2 warning logic)
  • End-to-end integration test script (scripts/integration-test.sh)
  • Manually tested: full create → invoke → update → delete lifecycle on AWS

@sebsto sebsto added this to the 2.1 milestone Sep 23, 2025
@sebsto sebsto self-assigned this Sep 23, 2025
@sebsto sebsto added 🆕 semver/minor Adds new public API. kind/feature New feature. size/L Large task. (A couple of weeks of work.) kind/usability Usability of generated code, ergonomics. labels Sep 23, 2025
@sebsto sebsto marked this pull request as draft September 23, 2025 19:28
@sebsto

sebsto commented Sep 23, 2025

Copy link
Copy Markdown
Collaborator Author

Issue tracker #566

@sebsto sebsto linked an issue Sep 23, 2025 that may be closed by this pull request
@tkrajacic

Copy link
Copy Markdown

Could we add the ability to pass build options. Sometimes it is nice to optimize for size and we can use

-Xlinker -s -Xswiftc -Osize

@sebsto sebsto force-pushed the sebsto/new-plugins branch from fcf0444 to bf73943 Compare November 2, 2025 21:31
@sebsto

sebsto commented Nov 3, 2025

Copy link
Copy Markdown
Collaborator Author

Could we add the ability to pass build options. Sometimes it is nice to optimize for size and we can use

Thank you @tkrajacic

This is planned. This will be a default setting, with an opt-out possibility --no-strip

We also propose to automatically strip the binary of debug symbols (-Xlinker -s) to reduce the size of the ZIP file. Our tests showed that this can reduce the size by up to 50%. An option to disable stripping will be provided.

I think -Xswiftc -Osize is the default with --release, but I will double check.

UPDATE: It's difficult to get an authoritative list of compiler and linker flags passed with --release. It looks like only -O is given. I'm not sure if -O size should be a default or an opt-in. Depending on the use case, Lambda developers might favor raw performance vs cold start time. It would be interesting to measure the effect of these. We need a basic benchmark suite to measure impact of these flags before taking decisions

@tkrajacic

tkrajacic commented Nov 7, 2025

Copy link
Copy Markdown

It's difficult to get an authoritative list of compiler and linker flags passed with --release

I was thinking more along the lines that you can pass arbitrary flags through to the compiler.
maybe just everything at the end of the invocation and after a -- or so?
I would definitely let the user decide how they want to compile their code.

Alternatively, why not just allow the user to add any -Xswiftc xxx flags and add them to the compiler flags?

@sebsto

sebsto commented Nov 7, 2025

Copy link
Copy Markdown
Collaborator Author

Alternatively, why not just allow the user to add any -Xswiftc xxx flags and add them to the compiler flags?

I think we should provide both. 1/ a sensible default set of options (like -Xlinker -s) by default to allow the best performance for all users and 2/ a possibility to pass any command for advanced users (that will override the default)

Sébastien Stormacq added 3 commits June 3, 2026 19:07
# Conflicts:
#	Package@swift-6.0.swift
#	Sources/AWSLambdaPluginHelper/lambda-build/Builder.swift
@sebsto sebsto force-pushed the sebsto/new-plugins branch 2 times, most recently from eacfd04 to 1f90a3d Compare June 4, 2026 14:08
@sebsto sebsto force-pushed the sebsto/new-plugins branch from 1f90a3d to 534cd29 Compare June 4, 2026 14:25
@sebsto sebsto changed the title New Plugins V4 Plugin System: lambda-init, lambda-build, lambda-deploy Jun 4, 2026
@sebsto sebsto changed the title V4 Plugin System: lambda-init, lambda-build, lambda-deploy v2 Plugin System: lambda-init, lambda-build, lambda-deploy Jun 4, 2026
sebsto and others added 3 commits June 5, 2026 09:56
…ility

soto-core removed its platforms: declaration and now uses @available
annotations on its types. Add matching availability annotations to
generated clients, test functions, and update the generation script
to include them automatically on future runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses SotoCore's .configFile(profile:) credential provider when
--profile is specified, keeping the default credential chain otherwise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature New feature. kind/usability Usability of generated code, ergonomics. 🆕 semver/minor Adds new public API. size/L Large task. (A couple of weeks of work.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove platforms: declaration from Package.swift, use @available instead [plugin] refactor the archive plugin

2 participants