Source code for aws_lambda_artifact_builder.layer.workflow

# -*- coding: utf-8 -*-

"""
All-in-one Lambda layer workflow - Build, Package, Upload, and Publish in one place.

This module provides a unified workflow class that combines all four steps of Lambda layer creation:

1. **Build**: Install dependencies using containerized build tools
2. **Package**: Create optimized zip archives  
3. **Upload**: Deploy artifacts to S3 storage
4. **Publish**: Create versioned Lambda layers with intelligent change detection
"""

import typing as T
import dataclasses
from pathlib import Path

from func_args.api import REQ

from ..constants import LayerBuildToolEnum
from ..imports import S3Path

from .foundation import BaseLogger, Credentials
from .pip_builder import PipBasedLambdaLayerContainerBuilder
from .poetry_builder import PoetryBasedLambdaLayerContainerBuilder
from .uv_builder import UVBasedLambdaLayerContainerBuilder
from .package import LambdaLayerZipper
from .upload import upload_layer_zip_to_s3
from .publish import LayerDeployment, LambdaLayerVersionPublisher


if T.TYPE_CHECKING:  # pragma: no cover
    from mypy_boto3_s3 import S3Client
    from mypy_boto3_lambda import LambdaClient


[docs] @dataclasses.dataclass(frozen=True) class LambdaLayerBuildPackageUploadAndPublishWorkflow(BaseLogger): """ All-in-one workflow for Lambda layer creation and deployment. This class orchestrates the complete Lambda layer lifecycle in a single interface, combining build, package, upload, and publish operations. It provides both unified execution via :meth:`run()` and granular control through individual step methods. **Workflow Steps:** 1. :meth:`step_1_build()` - Uses container-based builders from :mod:`~aws_lambda_artifact_builder.layer.build` 2. :meth:`step_2_package()` - Creates optimized zip using :class:`~aws_lambda_artifact_builder.layer.package.LambdaLayerZipper` 3. :meth:`step_3_upload()` - Deploys to S3 via :func:`~aws_lambda_artifact_builder.layer.upload.upload_layer_zip_to_s3` 4. :meth:`step_4_publish()` - Creates layer versions with :class:`~aws_lambda_artifact_builder.layer.publish.LambdaLayerVersionPublisher` **Multi-Tool Support:** The workflow automatically selects the appropriate builder based on ``layer_build_tool``: - :class:`~aws_lambda_artifact_builder.layer.build.PipBasedLambdaLayerContainerBuilder` for pip - :class:`~aws_lambda_artifact_builder.layer.build.PoetryBasedLambdaLayerContainerBuilder` for Poetry - :class:`~aws_lambda_artifact_builder.layer.build.UVBasedLambdaLayerContainerBuilder` for UV **Usage Example:** .. code-block:: python workflow = BuildPackageUploadAndPublishWorkflow( layer_name="my-python-deps", py_ver_major=3, py_ver_minor=11, path_pyproject_toml=Path("pyproject.toml"), s3dir_lambda=S3Path("s3://bucket/lambda/"), s3_client=s3_client, lambda_client=lambda_client, layer_build_tool=LayerBuildToolEnum.uv, ) # Execute complete workflow workflow.run() # Or execute individual steps workflow.build() workflow.package() workflow.upload() workflow.publish() :param layer_name: Name for the Lambda layer :param py_ver_major: Python major version (e.g., 3) :param py_ver_minor: Python minor version (e.g., 11) :param credentials: Optional private repository credentials :param is_arm: Whether to build for ARM64 architecture (default: False) :param path_pyproject_toml: Path to project's pyproject.toml file :param s3dir_lambda: S3 directory for Lambda artifacts :param s3_client: Boto3 S3 client for uploads :param lambda_client: Boto3 Lambda client for layer publishing :param layer_build_tool: Build tool to use (pip/poetry/uv) :param ignore_package_list: Packages to exclude from layer zip :param publish_layer_version_kwargs: Additional Lambda API parameters """ layer_name: str = dataclasses.field(default=REQ) py_ver_major: int = dataclasses.field(default=REQ) py_ver_minor: int = dataclasses.field(default=REQ) credentials: Credentials | None = dataclasses.field(default=None) is_arm: bool = dataclasses.field(default=False) path_pyproject_toml: Path = dataclasses.field(default=REQ) s3dir_lambda: "S3Path" = dataclasses.field(default=REQ) s3_client: "S3Client" = dataclasses.field(default=REQ) lambda_client: "LambdaClient" = dataclasses.field(default=REQ) layer_build_tool: LayerBuildToolEnum = dataclasses.field(default=REQ) ignore_package_list: list[str] | None = dataclasses.field(default=None) publish_layer_version_kwargs: dict[str, T.Any] | None = dataclasses.field( default=None ) def run(self) -> "LayerDeployment": self.step_1_build() self.step_2_package() self.step_3_upload() return self.step_4_publish() def step_1_build(self): if self.layer_build_tool == LayerBuildToolEnum.pip: builder = PipBasedLambdaLayerContainerBuilder( path_pyproject_toml=self.path_pyproject_toml, py_ver_major=self.py_ver_major, py_ver_minor=self.py_ver_minor, credentials=self.credentials, is_arm=self.is_arm, verbose=self.verbose, printer=self.printer, ) elif self.layer_build_tool == LayerBuildToolEnum.poetry: builder = PoetryBasedLambdaLayerContainerBuilder( path_pyproject_toml=self.path_pyproject_toml, py_ver_major=self.py_ver_major, py_ver_minor=self.py_ver_minor, credentials=self.credentials, is_arm=self.is_arm, verbose=self.verbose, printer=self.printer, ) elif self.layer_build_tool == LayerBuildToolEnum.uv: builder = UVBasedLambdaLayerContainerBuilder( path_pyproject_toml=self.path_pyproject_toml, py_ver_major=self.py_ver_major, py_ver_minor=self.py_ver_minor, credentials=self.credentials, is_arm=self.is_arm, verbose=self.verbose, printer=self.printer, ) else: # pragma: no cover raise ValueError(f"Unsupported layer_build_tool: {self.layer_build_tool}") builder.run() def step_2_package(self): zipper = LambdaLayerZipper( path_pyproject_toml=self.path_pyproject_toml, layer_build_tool=self.layer_build_tool, ignore_package_list=self.ignore_package_list, verbose=self.verbose, ) return zipper.run() def step_3_upload(self): return upload_layer_zip_to_s3( s3_client=self.s3_client, path_pyproject_toml=self.path_pyproject_toml, s3dir_lambda=self.s3dir_lambda, layer_build_tool=self.layer_build_tool, verbose=self.verbose, printer=self.printer, ) def step_4_publish(self) -> "LayerDeployment": publisher = LambdaLayerVersionPublisher( layer_name=self.layer_name, path_pyproject_toml=self.path_pyproject_toml, s3dir_lambda=self.s3dir_lambda, layer_build_tool=self.layer_build_tool, s3_client=self.s3_client, lambda_client=self.lambda_client, publish_layer_version_kwargs=self.publish_layer_version_kwargs, verbose=self.verbose, printer=self.printer, ) return publisher.run()