diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 9557464..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM mcr.microsoft.com/devcontainers/python:3 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a9ae156..e691ab2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,21 +1,27 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/python +// For format details, see https://aka.ms/devcontainer.json. { - "name": "Python 3", - "build": { "dockerfile": "Dockerfile" }, - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pip3 install --user -r requirements.txt", - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - "remoteUser": "root" + "name": "dev", + "image": "mcr.microsoft.com/devcontainers/python:3", + "features": { + "ghcr.io/devcontainers-extra/features/mise:1": {}, + "ghcr.io/devcontainers/features/aws-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "hverlin.mise-vscode", + "tamasfe.even-better-toml", + "redhat.vscode-yaml", + "charliermarsh.ruff", + "ms-python.python" + ] + } + }, + "mounts": [ + "source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind" + ], + "postCreateCommand": "echo 'eval \"$(mise activate bash)\"' >> ~/.bashrc", + "forwardPorts": [ + "8000:8000" + ] } diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 01b956c..1c966b9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -9,16 +9,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - name: Install uv and setup Python - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - python-version: 3.14 - - name: Install dependencies - run: make install + - name: Install mise + uses: jdx/mise-action@v4 - name: Format and lint - run: make lint + run: mise run lint - name: Run tests - run: make test + run: mise run test env: AWS_DEFAULT_REGION: us-east-1 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index daa4926..4559b1c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -44,15 +44,8 @@ jobs: stack: [agent, api, eventbridge, graphql, s3, sqs, stream] steps: - uses: actions/checkout@v6 - - name: Install uv and setup Python - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - python-version: 3.14 - - name: Install dependencies - run: make install - - name: Install AWS CDK CLI - run: npm install -g aws-cdk + - name: Install mise + uses: jdx/mise-action@v4 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v6 with: @@ -60,4 +53,4 @@ jobs: aws-region: ${{ vars.AWS_REGION }} - name: Deploy stack if: github.event_name != 'workflow_dispatch' || inputs.stack == 'all' || contains(inputs.stack, matrix.stack) - run: make deploy STACK=${{ matrix.stack }} + run: mise run deploy ${{ matrix.stack }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e8c7484..0ac2331 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,23 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - name: Install uv and setup Python - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - python-version: 3.14 + - name: Install mise + uses: jdx/mise-action@v4 - name: Configure Git Credentials run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v5 - with: - key: mkdocs-material-${{ env.cache_id }} - path: .cache - restore-keys: | - mkdocs-material- - - name: Install dependencies - run: make install-docs - name: Publish to GitHub Pages - run: make docs + run: mise run docs diff --git a/.gitignore b/.gitignore index c07350a..910939d 100644 --- a/.gitignore +++ b/.gitignore @@ -165,4 +165,10 @@ cython_debug/ .pypirc # AI Agent logs -.[jJ]ules/ \ No newline at end of file +.[jJ]ules/ + +# Dev container +devcontainer-lock.json + +# CDK +cdk.out/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c238608..0f3675e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,5 +3,5 @@ repos: hooks: - id: lint name: Linting - entry: make lint + entry: mise run lint language: system diff --git a/.vscode/settings.json b/.vscode/settings.json index 082b194..24a62d6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,45 @@ { - "makefile.configureOnOpen": false + "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "explicit", + "source.organizeImports.ruff": "explicit" + } + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml" + }, + "[yaml]": { + "editor.defaultFormatter": "redhat.vscode-yaml" + }, + "python.testing.pytestEnabled": true, + "python.testing.unittestEnabled": false, + "python.testing.pytestArgs": [ + "--tb=short" + ], + "files.exclude": { + "**/__pycache__": true, + "**/*.pyc": true, + "**/.pytest_cache": true, + "**/.ruff_cache": true, + "**/cdk.out": true, + "**/.venv": true + }, + "search.exclude": { + "**/__pycache__": true, + "**/.venv": true, + "**/cdk.out": true, + "**/node_modules": true, + "uv.lock": true + }, + "editor.rulers": [ + 120 + ], + "editor.insertSpaces": true, + "editor.tabSize": 4, + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true } \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index c1ea9f7..e71545c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,22 +4,22 @@ This file provides guidance for AI agents working in this repository. ## Project Overview -Python AWS Lambda project template using [uv](https://docs.astral.sh/uv/) for dependency management, Click for CLI, and pytest for testing. +Python AWS Lambda project template using [mise](https://mise.jdx.dev/) for tool management and [uv](https://docs.astral.sh/uv/) for dependency management. ## Setup ```bash -make install # install dependencies -make precommit # install pre-commit hooks +mise run install # install dependencies +mise run precommit # install pre-commit hooks ``` ## Common Commands ```bash -make lint # run ruff (check + format) and pyright -make test # run pytest with coverage -make docs # build and deploy docs to GitHub Pages -make local # serve docs locally +mise run lint # run ruff (check + format) and pyright +mise run test # run pytest with coverage +mise run docs # build and deploy docs to GitHub Pages +mise run local # serve docs locally ``` ## Code Style @@ -27,14 +27,14 @@ make local # serve docs locally - Line length: 120 characters (enforced by ruff) - Linting rules: `E` (pycodestyle errors) and `I` (isort) via ruff - Type checking: pyright in strict mode -- All code must pass `make lint` before committing (enforced by pre-commit hooks) +- All code must pass `mise run lint` before committing (enforced by pre-commit hooks) ## Testing Tests live in `tests/`. Run with: ```bash -make test +mise run test ``` Coverage is measured with `coverage` and reported to stdout and `coverage.xml`. The source under test is `templates/`. @@ -55,7 +55,7 @@ infra/ # AWS CDK infrastructure stacks To rename the project from the default `templates` name, run: ```bash -make project NAME=my-project DESCRIPTION="My description" AUTHOR="Name" EMAIL=handle GITHUB=username +mise run project name=my-project description="My description" author="Name" email=handle github=username ``` ## Dependencies @@ -76,15 +76,15 @@ make project NAME=my-project DESCRIPTION="My description" AUTHOR="Name" EMAIL=ha - Use `moto.mock_aws` for mocking AWS services in tests (e.g. DynamoDB, S3, Secrets Manager) - Do not cheat! Never modify source code just to make a failing test pass. Fix real bugs in source code and fix incorrect assertions in tests -## Make Targets +## Mise Tasks -Use `make` targets for all common workflows: lint, test, run locally, and deploy. Refer to `docs/README.md` for currently available targets. Add new targets to `Makefile` as needed. +Use `mise run ` for all common workflows: lint, test, run locally, and deploy. Refer to `docs/README.md` for currently available tasks. Add new tasks to `mise.toml` as needed. ## Notes - Python 3.14+ required - Dependencies are managed via `pyproject.toml` and locked in `uv.lock` -- Do not edit `uv.lock` directly; use `make update` to update dependencies +- Tooling is managed via `mise.toml` ## Coding Conventions diff --git a/Makefile b/Makefile deleted file mode 100644 index b948f1c..0000000 --- a/Makefile +++ /dev/null @@ -1,93 +0,0 @@ -.PHONY: help -help: # Show available targets - @grep -E '^[a-zA-Z_-]+:.*# .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*# "}; {printf " %-12s %s\n", $$1, $$2}' - -NAME ?= templates -DESCRIPTION ?= AWS Lambda Templates -AUTHOR ?= Amr Abed -EMAIL ?= -GITHUB ?= amrabed -SOURCE ?= $(shell echo ${NAME} | tr '-' '_' | tr '[:upper:]' '[:lower:]') - -.PHONY: new -new: # Create new Lambda function template (usage: make new template=) - @[ -n "$(template)" ] || { echo "Usage: make new template="; exit 1; } - uv run new -n $(template) - -.PHONY: project -project: uv # Rename project (run once) - @uv run rename \ - --name '$(subst ','\'',$(NAME))' \ - --description '$(subst ','\'',$(DESCRIPTION))' \ - --author '$(subst ','\'',$(AUTHOR))' \ - --email '$(subst ','\'',$(EMAIL))' \ - --github '$(subst ','\'',$(GITHUB))' - -.PHONY: uv -uv: # Install uv if not already installed - @command -v uv >/dev/null 2>&1 || pipx install uv - -venv: # Activate virtual environment - uv venv --clear - . .venv/bin/activate - -install: # Install dependencies and project - uv sync - -update: # Update dependencies - uv lock --upgrade - -precommit: # Install pre-commit hooks - uv run pre-commit autoupdate - uv run pre-commit install - -dev: uv venv precommit install - -lint: - uv run ruff format - uv run ruff check --fix - uv run ruff format -# uv run pyright - -coverage: - uv run coverage run -m pytest . - uv run coverage report -m - uv run coverage xml - -test: coverage - -install-docs: - uv sync --group docs - -.PHONY: docs -docs: # Build and deploy documentation to GitHub pages - uv run mkdocs gh-deploy --force - -local: # Serve documentation on a local server - uv run mkdocs serve - -# CDK stacks mapping -CDK_STACK = \$(STACK_MAP_\$(STACK)) -STACK_MAP_agent = BedrockAgentStack -STACK_MAP_api = ApiGatewayDynamodbStack -STACK_MAP_stream = DynamodbStreamStack -STACK_MAP_eventbridge = EventBridgeApiCallerStack -STACK_MAP_graphql = AppSyncDynamodbStack -STACK_MAP_s3 = S3SqsStack -STACK_MAP_sqs = SqsStack - -.PHONY: deploy -deploy: # Deploy an CDK stack - @[ -n "$(STACK)" ] || { echo "Usage: make deploy STACK="; exit 1; } - @[ -n "\$(CDK_STACK)" ] || { echo "Error: unknown stack '\$(STACK)'"; exit 1; } - STACK=\$(STACK) uv run cdk deploy --app "python infra/app.py" --require-approval never \$(CDK_STACK) \ - \$(if \$(AWS_PROFILE),--profile \$(AWS_PROFILE),) - -.PHONY: destroy -destroy: # Destroy a deployed CDK stack - @[ -n "$(STACK)" ] || { echo "Usage: make destroy STACK="; exit 1; } - @[ -n "\$(CDK_STACK)" ] || { echo "Error: unknown stack '\$(STACK)'"; exit 1; } - STACK=\$(STACK) uv run cdk destroy --force --app "python infra/app.py" \$(CDK_STACK) \ - \$(if \$(AWS_PROFILE),--profile \$(AWS_PROFILE),) - -all: install lint test diff --git a/cdk.json b/cdk.json new file mode 100644 index 0000000..8e703da --- /dev/null +++ b/cdk.json @@ -0,0 +1,4 @@ +{ + "app": "python infra/app.py", + "requireApproval": "never" +} \ No newline at end of file diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 9a7a8e1..5ac440c 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -15,7 +15,7 @@ All types of contributions are encouraged and valued. Here are some ways you can ## Contributing to the code -> ### Legal Notice +> ### Legal Notice > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project licence. Unless your change is trivial (typo, docs tweak etc.), please create an issue to discuss the change before creating a pull request. @@ -29,19 +29,18 @@ To make contributing as easy and fast as possible, you'll want to run tests and You'll need the following prerequisites: -- **Python 3.14+** -- **Poetry** +- **[mise](https://mise.jdx.dev/)** - **git** -- **make** ### How to contribute -- Fork the repository on GitHub +- Fork the repository on GitHub - Clone your fork locally. -- Install the project dependencies: +- Set up development environment: ```bash -make poetry install pre-commit +mise install +mise run dev ``` - Create a new branch (with a descriptive name) for your changes: @@ -52,7 +51,8 @@ git checkout -b my-new-feature # use descriptive branch name - Run tests and linting locally to make sure everything is working as expected. ```bash -make lint test +mise run lint +mise run test ``` - Commit your changes and push your branch to GitHub ```bash @@ -86,7 +86,7 @@ Project Documentation is written in Markdown and built using [Material for MkDoc To preview the docuementation on your local, run: ```bash -make local +mise run local ``` ## Reporting Bugs diff --git a/docs/README.md b/docs/README.md index b2bb540..c6601fe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,6 +38,7 @@ Templates come pre-wired with: - **Development environment**: [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) for dockerized development environment - **Pre-commit Validations**: [pre-commit](https://pre-commit.com) hooks - **Workflow Automation**: [GitHub Actions](https://github.com/features/actions) for CI/CD and documentation auto-deployment to [GitHub Pages](https://pages.github.com) +- **Tool Management & Tasks**: [mise](https://mise.jdx.dev/) for managing project tools and automating common development tasks ### GitHub files The repository also comes preloaded with these GitHub files: @@ -59,22 +60,21 @@ Click this button to create a new repository for your project, then clone the ne [![Use this template](https://img.shields.io/badge/Use%20this%20template-238636?style=for-the-badge)](https://github.com/amrabed/aws-lambda-templates/generate) ### Rename the project -Run `make project` once after cloning, before any other setup steps: +Run `mise run rename` once after cloning, before any other setup steps: ```bash -make project NAME="my-project" DESCRIPTION="My project description" AUTHOR="Jane Doe" EMAIL="jane" GITHUB="janedoe" +mise run rename --name="my-project" --description="My project description" --author="Jane Doe" --email="jane" --github="janedoe" ``` Pass the following parameters: Parameter | Description --- | --- -`NAME` | Project new name -`DESCRIPTION` | Project short description -`AUTHOR` | Author name -`EMAIL` | Author email -`GITHUB` | GitHub username (for GitHub funding) -`SOURCE` | (optional) Source folder name +`name` | Project new name +`description` | Project short description +`author` | Author name +`email` | Author email +`github` | GitHub username ## Prerequisites @@ -82,92 +82,67 @@ Parameter | Description - Docker ### Local environment -- Python 3.14+ -- uv -- Docker (for Dev Containers) -- AWS CDK CLI (for deployment) +- [mise](https://mise.jdx.dev/) ## Setup ### Set up dev environment To set up the local dev environment, run: ```bash -make dev -``` - -### Install dependencies -To install the project dependencies defined in `pyproject.toml`, run: -```bash -make install -``` - -### Install pre-commit hooks -To install the pre-commit hooks for the project to format and lint your code automatically before committing, run: -```bash -make precommit -``` - -### Activate virtual environment -To activate the virtual environment, run: -```bash -make venv +mise run dev ``` +That will: +- Install the project dependencies defined in `pyproject.toml` +- Install the pre-commit hooks for the project to format and lint your code automatically before committing ### Format and lint code To format and lint project code, run: ```bash -make lint +mise run lint # alias: l ``` ### Run tests with coverage To run all tests (including Hypothesis property-based tests) and show the coverage report, run: ```bash -make test +mise run test # alias: t ``` -`make test` runs both standard pytest tests and Hypothesis property-based tests in a single command. +`mise run test` runs both standard pytest tests and Hypothesis property-based tests in a single command. ### Build a new template To start building a new Lambda template, use: ```bash -make new template= -``` - -Or, equivalently: - -```bash -uv run new --name +mise run new # alias: n ``` This runs the `new` script, which builds a skeleton for the new template from `.template`. ### Deploy a stack -Infrastructure is defined as AWS CDK stacks under [`infra/stacks/`](/infra/stacks). -The CDK entry point is [`infra/app.py`](/infra/app.py). -The `STACK` environment variable selects which stack to synthesise. +Infrastructure is defined as AWS CDK stacks under `infra/stacks/`. +The CDK entry point is `infra/app.py`. ```bash -make deploy STACK= +mise run deploy # alias: d ``` -Pass `AWS_PROFILE` to use a named AWS CLI profile: +Pass `--profile` (or `-p`) to use a named AWS CLI profile: ```bash -make deploy STACK= AWS_PROFILE= +mise run deploy --profile ``` ### Destroy a stack ```bash -make destroy STACK= +mise run destroy # alias: D ``` ### Generating documentation To build and publish the project documentation to GitHub Pages, run: ```bash -make docs +mise run docs ``` That pushes the new documentation to the `gh-pages` branch. Make sure GitHub Pages is enabled in your repository settings and using the `gh-pages` branch for the documentation to be publicly available. @@ -175,7 +150,7 @@ That pushes the new documentation to the `gh-pages` branch. Make sure GitHub Pag ### Local preview To serve the documentation on a local server, run: ```bash -make local +mise run local ``` ## Coding Conventions @@ -208,7 +183,7 @@ make local ├── .gitignore # Git-ignored file list ├── .pre-commit-config.yaml # Pre-commit configuration file ├── .vscode # VS Code folder -├── Makefile # Make commands +├── mise.toml # mise configuration and tasks ├── pyproject.toml # Configuration file for different tools ├── mkdocs.yml # MkDocs configuration file ├── docs # Documentation folder diff --git a/infra/code.py b/infra/code.py new file mode 100644 index 0000000..cce86d9 --- /dev/null +++ b/infra/code.py @@ -0,0 +1,26 @@ +from aws_cdk.aws_lambda import Code + + +def get_lambda_code() -> Code: + """Returns a standardized Code object that excludes unnecessary local files.""" + return Code.from_asset( + path=".", + exclude=[ + ".git", + ".github", + ".venv", + ".vscode", + "pyproject.toml", + "mise.toml", + "mkdocs.yml", + "docs", + "tests", + "infra", + "cdk.json", + "cdk.out", + "__pycache__", + ".pytest_cache", + ".ruff_cache", + ".hypothesis", + ], + ) diff --git a/infra/stacks/agent.py b/infra/stacks/agent.py index ca79774..e50c1eb 100644 --- a/infra/stacks/agent.py +++ b/infra/stacks/agent.py @@ -1,8 +1,10 @@ from aws_cdk import Stack from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, Table -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from constructs import Construct +from infra.code import get_lambda_code + class BedrockAgentStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -19,8 +21,8 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: self, "BedrockAgentFunction", runtime=Runtime.PYTHON_3_14, - handler="templates.bedrock_agent.handler.main", - code=Code.from_asset("."), + handler="templates.agent.handler.main", + code=get_lambda_code(), environment={ "TABLE_NAME": table.table_name, "SERVICE_NAME": "bedrock-agent", diff --git a/infra/stacks/api.py b/infra/stacks/api.py index 4d6dc03..a8d72d3 100644 --- a/infra/stacks/api.py +++ b/infra/stacks/api.py @@ -1,9 +1,11 @@ from aws_cdk import Stack from aws_cdk.aws_apigateway import LambdaIntegration, RestApi from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, Table -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from constructs import Construct +from infra.code import get_lambda_code + class ApiGatewayDynamodbStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -21,7 +23,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "ApiGatewayDynamodbFunction", runtime=Runtime.PYTHON_3_14, handler="templates.api.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "TABLE_NAME": table.table_name, "SERVICE_NAME": "api-gateway-dynamodb", diff --git a/infra/stacks/eventbridge.py b/infra/stacks/eventbridge.py index 71d5df0..e085293 100644 --- a/infra/stacks/eventbridge.py +++ b/infra/stacks/eventbridge.py @@ -2,10 +2,12 @@ from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, Table from aws_cdk.aws_events import Rule, Schedule from aws_cdk.aws_events_targets import LambdaFunction -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from aws_cdk.aws_secretsmanager import Secret from constructs import Construct +from infra.code import get_lambda_code + class EventBridgeApiCallerStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -26,7 +28,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "EventBridgeApiCallerFunction", runtime=Runtime.PYTHON_3_14, handler="templates.eventbridge.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "API_URL": "https://api.example.com", "SECRET_NAME": secret.secret_name, diff --git a/infra/stacks/graphql.py b/infra/stacks/graphql.py index b9cab4e..b842ef4 100644 --- a/infra/stacks/graphql.py +++ b/infra/stacks/graphql.py @@ -8,9 +8,11 @@ SchemaFile, ) from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, Table -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from constructs import Construct +from infra.code import get_lambda_code + class AppSyncDynamodbStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -28,7 +30,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "AppSyncDynamodbFunction", runtime=Runtime.PYTHON_3_14, handler="templates.graphql.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "TABLE_NAME": table.table_name, "SERVICE_NAME": "appsync-dynamodb", diff --git a/infra/stacks/s3.py b/infra/stacks/s3.py index d160ed1..169d3b4 100644 --- a/infra/stacks/s3.py +++ b/infra/stacks/s3.py @@ -1,10 +1,12 @@ from aws_cdk import RemovalPolicy, Stack -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from aws_cdk.aws_lambda_event_sources import S3EventSource from aws_cdk.aws_s3 import Bucket, EventType from aws_cdk.aws_sqs import Queue from constructs import Construct +from infra.code import get_lambda_code + class S3SqsStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -27,7 +29,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "S3SqsFunction", runtime=Runtime.PYTHON_3_14, handler="templates.s3.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "SQS_QUEUE_URL": queue.queue_url, "POWERTOOLS_SERVICE_NAME": "s3-sqs-processor", diff --git a/infra/stacks/sqs.py b/infra/stacks/sqs.py index e49ad6d..7108ff5 100644 --- a/infra/stacks/sqs.py +++ b/infra/stacks/sqs.py @@ -1,10 +1,12 @@ from aws_cdk import Stack from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, Table -from aws_cdk.aws_lambda import Code, Function, Runtime +from aws_cdk.aws_lambda import Function, Runtime from aws_cdk.aws_lambda_event_sources import SqsEventSource from aws_cdk.aws_sqs import Queue from constructs import Construct +from infra.code import get_lambda_code + class SqsLambdaDynamodbStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -33,7 +35,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "SqsLambdaDynamodbFunction", runtime=Runtime.PYTHON_3_14, handler="templates.sqs.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "TABLE_NAME": table.table_name, "SERVICE_NAME": "sqs-processor", diff --git a/infra/stacks/stream.py b/infra/stacks/stream.py index d562c4c..92c17f0 100644 --- a/infra/stacks/stream.py +++ b/infra/stacks/stream.py @@ -1,10 +1,12 @@ from aws_cdk import Stack -from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, StartingPosition, StreamViewType, Table -from aws_cdk.aws_lambda import Code, Function, Runtime -from aws_cdk.aws_lambda_event_sources import DynamoDBEventSource, SqsDlq +from aws_cdk.aws_dynamodb import Attribute, AttributeType, BillingMode, StreamViewType, Table +from aws_cdk.aws_lambda import Function, Runtime, StartingPosition +from aws_cdk.aws_lambda_event_sources import DynamoEventSource, SqsDlq from aws_cdk.aws_sqs import Queue from constructs import Construct +from infra.code import get_lambda_code + class DynamodbStreamStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: @@ -30,7 +32,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: "DynamodbStreamFunction", runtime=Runtime.PYTHON_3_14, handler="templates.stream.handler.main", - code=Code.from_asset("."), + code=get_lambda_code(), environment={ "SOURCE_TABLE_NAME": source_table.table_name, "DESTINATION_TABLE_NAME": destination_table.table_name, @@ -48,7 +50,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: ) function.add_event_source( - DynamoDBEventSource( + DynamoEventSource( source_table, starting_position=StartingPosition.TRIM_HORIZON, report_batch_item_failures=True, diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..7d1615b --- /dev/null +++ b/mise.toml @@ -0,0 +1,134 @@ +[tools] +python = "3.14" +uv = "latest" + +##### Settings and environment variables ##### + +[settings] +python.uv_venv_auto = "create|source" + +[env] +JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION = true # silence warning about untested Node.js versions in CDK + +##### Shell aliases ##### + +[shell_alias] +# Project-specific shortcuts +n = "mise run new" +i = "mise run install" +l = "mise run lint" +t = "mise run test" +d = "mise run deploy" +D = "mise run destroy" +c = "mise run clean" +m = "mise run" + +# Common utility aliases +ll = "ls -la" +la = "ls -A" +gs = "git status" +ga = "git add" +gc = "git commit" +gp = "git push" + +##### Scripts ##### + +[tasks.new] +description = "Create new Lambda function template" +usage = """ +arg "