From 5d181ef685df2b71ff4d61083313eab16fa4e3df Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 12:22:38 +0000 Subject: [PATCH 01/27] Migrate from Makefile and pyproject.toml to mise - Introduce mise.toml for tool management and task automation - Migrate dependencies to requirements.txt files - Move tool configurations (Ruff, Pyright, Coverage) to standalone files - Update project scripts (new.py, rename.py) to support the new setup - Update GitHub Workflows to use jdx/mise-action - Update documentation and pre-commit hooks - Remove Makefile and pyproject.toml --- .coveragerc | 7 +++ .github/workflows/check.yml | 13 ++--- .github/workflows/deploy.yml | 11 ++-- .github/workflows/docs.yml | 11 ++-- .pre-commit-config.yaml | 2 +- AGENTS.md | 31 +++++----- Makefile | 93 ------------------------------ docs/README.md | 47 ++++++--------- mise.toml | 108 +++++++++++++++++++++++++++++++++++ pyproject.toml | 66 --------------------- pyrightconfig.json | 4 ++ requirements-dev.txt | 11 ++++ requirements-docs.txt | 4 ++ requirements-infra.txt | 2 + requirements.txt | 5 ++ ruff.toml | 4 ++ scripts/new.py | 47 +++++++-------- scripts/rename.py | 11 ++-- 18 files changed, 220 insertions(+), 257 deletions(-) create mode 100644 .coveragerc delete mode 100644 Makefile create mode 100644 mise.toml delete mode 100644 pyproject.toml create mode 100644 pyrightconfig.json create mode 100644 requirements-dev.txt create mode 100644 requirements-docs.txt create mode 100644 requirements-infra.txt create mode 100644 requirements.txt create mode 100644 ruff.toml diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..c6fdea4 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[run] +branch = true +source = templates + +[report] +omit = tests/* +fail_under = 90 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 01b956c..0ed131e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -9,16 +9,13 @@ 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@v2 - name: Install dependencies - run: make install + run: mise run install - 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..a73b635 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -44,13 +44,10 @@ 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 mise + uses: jdx/mise-action@v2 - name: Install dependencies - run: make install + run: mise run install - name: Install AWS CDK CLI run: npm install -g aws-cdk - name: Configure AWS credentials @@ -60,4 +57,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 stack=${{ matrix.stack }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e8c7484..ad309bb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,11 +11,8 @@ 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@v2 - name: Configure Git Credentials run: | git config user.name github-actions[bot] @@ -28,6 +25,6 @@ jobs: restore-keys: | mkdocs-material- - name: Install dependencies - run: make install-docs + run: mise run install-docs - name: Publish to GitHub Pages - run: make docs + run: mise run docs 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/AGENTS.md b/AGENTS.md index c1ea9f7..9a4ac8f 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,12 +55,13 @@ 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 -- Always use uv for dependency management (`uv add `) +- Always use uv for dependency management (`uv pip install `) +- Dependencies are listed in `requirements.txt` and its variants - Use Pydantic for data models - Use Pydantic-settings for environment variable configuration in a `settings.py` file - Use [AWS Lambda Powertools](https://docs.aws.amazon.com/powertools/python) wherever applicable: logger, tracer, metrics, parameters, event types, event handlers, etc. @@ -76,15 +77,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` +- Dependencies are managed via `requirements.txt` files ## 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/docs/README.md b/docs/README.md index b2bb540..7adfe89 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,10 +60,10 @@ 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 project` 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 project name="my-project" description="My project description" author="Jane Doe" email="jane" github="janedoe" ``` Pass the following parameters: @@ -82,8 +83,7 @@ Parameter | Description - Docker ### Local environment -- Python 3.14+ -- uv +- [mise](https://mise.jdx.dev/) - Docker (for Dev Containers) - AWS CDK CLI (for deployment) @@ -92,53 +92,41 @@ Parameter | Description ### Set up dev environment To set up the local dev environment, run: ```bash -make dev +mise run dev ``` ### Install dependencies -To install the project dependencies defined in `pyproject.toml`, run: +To install the project dependencies, run: ```bash -make install +mise run 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 precommit ``` ### Format and lint code To format and lint project code, run: ```bash -make lint +mise run lint ``` ### 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 ``` -`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 template= ``` This runs the `new` script, which builds a skeleton for the new template from `.template`. @@ -147,27 +135,26 @@ This runs the `new` script, which builds a skeleton for the new template from `. ### 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. ```bash -make deploy STACK= +mise run deploy stack= ``` Pass `AWS_PROFILE` to use a named AWS CLI profile: ```bash -make deploy STACK= AWS_PROFILE= +AWS_PROFILE= mise run deploy stack= ``` ### Destroy a stack ```bash -make destroy STACK= +mise run destroy stack= ``` ### 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 +162,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 diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..4671b97 --- /dev/null +++ b/mise.toml @@ -0,0 +1,108 @@ +[tools] +python = "3.14" +uv = "latest" + +[env] +_.python.venv = { path = ".venv", create = true } + +[tasks.new] +description = "Create new Lambda function template" +run = "uv run python scripts/new.py -n {{ arg(n='template') }}" + +[tasks.project] +description = "Rename project (run once)" +run = """ +uv run python scripts/rename.py \ + --name '{{ arg(n='name', default='templates') }}' \ + --description '{{ arg(n='description', default='AWS Lambda Templates') }}' \ + --author '{{ arg(n='author', default='Amr Abed') }}' \ + --email '{{ arg(n='email', default='') }}' \ + --github '{{ arg(n='github', default='amrabed') }}' +""" + +[tasks.install] +description = "Install dependencies and project" +run = "uv pip install -r requirements-dev.txt" + +[tasks.update] +description = "Update dependencies" +run = "uv pip install --upgrade -r requirements-dev.txt -r requirements-docs.txt" + +[tasks.precommit] +description = "Install pre-commit hooks" +run = "uv run pre-commit autoupdate && uv run pre-commit install" + +[tasks.dev] +description = "Set up dev environment" +depends = ["precommit", "install"] + +[tasks.lint] +description = "Format and lint code" +run = """ +uv run ruff format +uv run ruff check --fix +uv run ruff format +# uv run pyright +""" + +[tasks.coverage] +description = "Run tests with coverage" +run = """ +uv run coverage run -m pytest . +uv run coverage report -m +uv run coverage xml +""" + +[tasks.test] +description = "Run all tests" +depends = ["coverage"] + +[tasks.install-docs] +description = "Install documentation dependencies" +run = "uv pip install -r requirements-docs.txt" + +[tasks.docs] +description = "Build and deploy documentation to GitHub pages" +run = "uv run mkdocs gh-deploy --force" + +[tasks.local] +description = "Serve documentation on a local server" +run = "uv run mkdocs serve" + +[tasks.deploy] +description = "Deploy a CDK stack" +run = """ +#!/usr/bin/env bash +[ -n "$stack" ] || { echo "Usage: mise run deploy stack="; exit 1; } +case "$stack" in + agent) CDK_STACK=BedrockAgentStack ;; + api) CDK_STACK=ApiGatewayDynamodbStack ;; + stream) CDK_STACK=DynamodbStreamStack ;; + eventbridge) CDK_STACK=EventBridgeApiCallerStack ;; + graphql) CDK_STACK=AppSyncDynamodbStack ;; + s3) CDK_STACK=S3SqsStack ;; + sqs) CDK_STACK=SqsStack ;; + *) echo "Error: unknown stack '$stack'"; exit 1 ;; +esac +STACK=$stack uv run cdk deploy --app "python infra/app.py" --require-approval never $CDK_STACK \ + ${AWS_PROFILE:+--profile $AWS_PROFILE} +""" + +[tasks.destroy] +description = "Destroy a deployed CDK stack" +run = """ +#!/usr/bin/env bash +[ -n "$stack" ] || { echo "Usage: mise run destroy stack="; exit 1; } +case "$stack" in + agent) CDK_STACK=BedrockAgentStack ;; + api) CDK_STACK=ApiGatewayDynamodbStack ;; + stream) CDK_STACK=DynamodbStreamStack ;; + eventbridge) CDK_STACK=EventBridgeApiCallerStack ;; + graphql) CDK_STACK=AppSyncDynamodbStack ;; + s3) CDK_STACK=S3SqsStack ;; + sqs) CDK_STACK=SqsStack ;; + *) echo "Error: unknown stack '$stack'"; exit 1 ;; +esac +STACK=$stack uv run cdk destroy --force --app "python infra/app.py" $CDK_STACK \ + ${AWS_PROFILE:+--profile $AWS_PROFILE} +""" diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 1f91a5c..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,66 +0,0 @@ -[project] -name = "templates" -version = "0.1.0" -description = "AWS Lambda Templates" -authors = [{name = "Amr Abed", email = ""}] -license = {text = "MIT"} -readme = "docs/README.md" -requires-python = ">=3.14" -dependencies = [ - "pydantic>=2.13.4", - "pydantic-settings>=2.13.1", - "aws-lambda-powertools>=3.29.0", - "boto3>=1.43.6", - "requests>=2.33.1", -] - -[project.scripts] -new = "scripts.new:main" -rename = "scripts.rename:main" - -[dependency-groups] -infra = [ - "aws-cdk-lib>=2.253.0", - "constructs>=10.6.0", -] -dev = [ - "pytest>=9.0.1", - "ruff>=0.15.12", - "coverage>=7.6.9", - "pre-commit>=4.0.1", - "pyright>=1.1.391", - "pytest-mock>=3.15.1", - "moto>=5.2.0", - "hypothesis>=6.152.4", - "click>=8.3.2", -] -docs = [ - "mkdocs>=1.6.1", - "mkdocstrings[python]>=1.0.4", - "mkdocs-material>=9.6.20", -] - -[tool.uv] -default-groups = ["infra", "dev", "docs"] - -[tool.ruff] -line-length = 120 - -[tool.ruff.lint] -select = ["E", "I"] - -[tool.coverage.run] -branch = true -source = ["templates"] - -[tool.coverage.report] -omit = ["tests/*"] -fail_under = 90 - -[tool.pyright] -exclude = ["**/__pycache__", "**/.pytest_cache", ".venv"] -reportMissingImports = "error" - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..2e18570 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,4 @@ +{ + "exclude": ["**/__pycache__", "**/.pytest_cache", ".venv"], + "reportMissingImports": "error" +} diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..e1350e2 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,11 @@ +pytest>=9.0.1 +ruff>=0.15.12 +coverage>=7.6.9 +pre-commit>=4.0.1 +pyright>=1.1.391 +pytest-mock>=3.15.1 +moto>=5.2.0 +hypothesis>=6.152.4 +click>=8.3.2 +-r requirements.txt +-r requirements-infra.txt diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 0000000..3d31d8f --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,4 @@ +mkdocs>=1.6.1 +mkdocstrings[python]>=1.0.4 +mkdocs-material>=9.6.20 +-r requirements.txt diff --git a/requirements-infra.txt b/requirements-infra.txt new file mode 100644 index 0000000..160ebb7 --- /dev/null +++ b/requirements-infra.txt @@ -0,0 +1,2 @@ +aws-cdk-lib>=2.253.0 +constructs>=10.6.0 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1a2eeea --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +pydantic>=2.13.4 +pydantic-settings>=2.13.1 +aws-lambda-powertools>=3.29.0 +boto3>=1.43.6 +requests>=2.33.1 diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..26b5ad6 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,4 @@ +line-length = 120 + +[lint] +select = ["E", "I"] diff --git a/scripts/new.py b/scripts/new.py index 3fb6efc..bdba5f2 100644 --- a/scripts/new.py +++ b/scripts/new.py @@ -100,34 +100,31 @@ def update_mkdocs_file(name: str, title_name: str): f.write(content) -def update_makefile(name: str, camel_name: str): - """Update Makefile to include new template in build and test targets.""" - with open("Makefile", "r") as f: +def update_mise_toml(name: str): + """Update mise.toml to include new template in deploy and destroy targets.""" + with open("mise.toml", "r") as f: content = f.read() - stack_map_line = f"STACK_MAP_{name} " + " " * (25 - len(name)) + f"= {camel_name}Stack" - if stack_map_line not in content: - # Find the last STACK_MAP entry - lines = content.splitlines() - last_map_idx = -1 - for i, line in enumerate(lines): - if "STACK_MAP_" in line: - last_map_idx = i + if f"|{name}" not in content: + # Update usage messages using regex + content = re.sub( + r"(Usage: mise run (?:deploy|destroy) stack=<[a-z0-9|]+)>", + r"\1|" + name + ">", + content + ) - if last_map_idx != -1: - lines.insert(last_map_idx + 1, stack_map_line) - - # Update deploy/destroy messages - for i, line in enumerate(lines): - if "Usage: make deploy STACK=" in line: - if f"|{name}" not in line: - lines[i] = line.replace(">", f"|{name}>") - if "Usage: make destroy STACK=" in line: - if f"|{name}" not in line: - lines[i] = line.replace(">", f"|{name}>") + # Update case statements + lines = content.splitlines() + new_lines = [] + for line in lines: + if '*) echo "Error: unknown stack' in line: + components = name.split("_") + camel_name = "".join(x.title() for x in components) + new_lines.append(f" {name}) CDK_STACK={camel_name}Stack ;;") + new_lines.append(line) - with open("Makefile", "w") as f: - f.write("\n".join(lines) + "\n") + with open("mise.toml", "w") as f: + f.write("\n".join(new_lines) + "\n") @command(context_settings={"help_option_names": ["-h", "--help"]}, help="Generate new template") @@ -161,7 +158,7 @@ def main(name: str): update_infra_app_file(name, camel_name) update_deploy_workflow(name) update_mkdocs_file(name, title_name) - update_makefile(name, camel_name) + update_mise_toml(name) print(f"Successfully created template '{name}'") diff --git a/scripts/rename.py b/scripts/rename.py index 46379b7..4e42dfb 100644 --- a/scripts/rename.py +++ b/scripts/rename.py @@ -33,10 +33,11 @@ def main(name: str, description: str, author: str, email: str, github: str): replacements = [ ("mkdocs.yml", r"^repo_name: .*", f"repo_name: {github}/{name}"), ("mkdocs.yml", r"^repo_url: .*", f"repo_url: https://github.com/{github}/{name}"), - ("pyproject.toml", r'^name = ".*"', f'name = "{name}"'), - ("pyproject.toml", r'^description = ".*"', f'description = "{description}"'), - ("pyproject.toml", r"^authors = \[.*\]", f'authors = [{{name = "{author}", email = "{email}"}}]'), - ("pyproject.toml", r'^source = \["templates"\]', f'source = ["{source}"]'), + ("mise.toml", r"default='templates'", f"default='{name}'"), + ("mise.toml", r"default='AWS Lambda Templates'", f"default='{description}'"), + ("mise.toml", r"default='Amr Abed'", f"default='{author}'"), + ("mise.toml", r"default='amrabed'", f"default='{github}'"), + (".coveragerc", r"^source = .*", f"source = {source}"), ("docs/README.md", r"^# .*", f"# {description}"), (".github/CODEOWNERS", r"@.*", f"@{github}"), (".github/FUNDING.yml", r"^github: .*", f"github: {github}"), @@ -60,7 +61,7 @@ def main(name: str, description: str, author: str, email: str, github: str): dirs[:] = [d for d in dirs if not d.startswith(".") and d != "venv"] for file in files: - if file.endswith((".py", ".md", ".yml", ".pyt", "Makefile")): + if file.endswith((".py", ".md", ".yml", ".pyt", ".toml", ".txt", ".coveragerc", "mise.toml")): path = Path(root) / file if path.name == "rename.py": continue From b006213f5fc832da6c078ef3c837f12bd8bb8ed9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 13:54:17 +0000 Subject: [PATCH 02/27] Integrate mise for tool management and task automation - Add mise.toml for tool versioning (python, uv) and task automation - Retain pyproject.toml for dependency management and project metadata - Replace Makefile with mise tasks - Update scripts/new.py and scripts/rename.py to support mise.toml - Update GitHub Workflows to use jdx/mise-action - Update documentation and pre-commit hooks to use mise run commands --- .coveragerc | 7 ----- AGENTS.md | 5 ++-- docs/README.md | 2 +- mise.toml | 10 +++---- pyproject.toml | 66 ++++++++++++++++++++++++++++++++++++++++++ pyrightconfig.json | 4 --- requirements-dev.txt | 11 ------- requirements-docs.txt | 4 --- requirements-infra.txt | 2 -- requirements.txt | 5 ---- ruff.toml | 4 --- scripts/new.py | 6 +--- scripts/rename.py | 7 +++-- 13 files changed, 80 insertions(+), 53 deletions(-) delete mode 100644 .coveragerc create mode 100644 pyproject.toml delete mode 100644 pyrightconfig.json delete mode 100644 requirements-dev.txt delete mode 100644 requirements-docs.txt delete mode 100644 requirements-infra.txt delete mode 100644 requirements.txt delete mode 100644 ruff.toml diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c6fdea4..0000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = true -source = templates - -[report] -omit = tests/* -fail_under = 90 diff --git a/AGENTS.md b/AGENTS.md index 9a4ac8f..e71545c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,8 +60,7 @@ mise run project name=my-project description="My description" author="Name" emai ## Dependencies -- Always use uv for dependency management (`uv pip install `) -- Dependencies are listed in `requirements.txt` and its variants +- Always use uv for dependency management (`uv add `) - Use Pydantic for data models - Use Pydantic-settings for environment variable configuration in a `settings.py` file - Use [AWS Lambda Powertools](https://docs.aws.amazon.com/powertools/python) wherever applicable: logger, tracer, metrics, parameters, event types, event handlers, etc. @@ -84,8 +83,8 @@ Use `mise run ` for all common workflows: lint, test, run locally, and dep ## Notes - Python 3.14+ required +- Dependencies are managed via `pyproject.toml` and locked in `uv.lock` - Tooling is managed via `mise.toml` -- Dependencies are managed via `requirements.txt` files ## Coding Conventions diff --git a/docs/README.md b/docs/README.md index 7adfe89..b7946d0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -96,7 +96,7 @@ mise run dev ``` ### Install dependencies -To install the project dependencies, run: +To install the project dependencies defined in `pyproject.toml`, run: ```bash mise run install ``` diff --git a/mise.toml b/mise.toml index 4671b97..78e9cde 100644 --- a/mise.toml +++ b/mise.toml @@ -7,12 +7,12 @@ _.python.venv = { path = ".venv", create = true } [tasks.new] description = "Create new Lambda function template" -run = "uv run python scripts/new.py -n {{ arg(n='template') }}" +run = "uv run new -n {{ arg(n='template') }}" [tasks.project] description = "Rename project (run once)" run = """ -uv run python scripts/rename.py \ +uv run rename \ --name '{{ arg(n='name', default='templates') }}' \ --description '{{ arg(n='description', default='AWS Lambda Templates') }}' \ --author '{{ arg(n='author', default='Amr Abed') }}' \ @@ -22,11 +22,11 @@ uv run python scripts/rename.py \ [tasks.install] description = "Install dependencies and project" -run = "uv pip install -r requirements-dev.txt" +run = "uv sync" [tasks.update] description = "Update dependencies" -run = "uv pip install --upgrade -r requirements-dev.txt -r requirements-docs.txt" +run = "uv lock --upgrade" [tasks.precommit] description = "Install pre-commit hooks" @@ -59,7 +59,7 @@ depends = ["coverage"] [tasks.install-docs] description = "Install documentation dependencies" -run = "uv pip install -r requirements-docs.txt" +run = "uv sync --group docs" [tasks.docs] description = "Build and deploy documentation to GitHub pages" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1f91a5c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,66 @@ +[project] +name = "templates" +version = "0.1.0" +description = "AWS Lambda Templates" +authors = [{name = "Amr Abed", email = ""}] +license = {text = "MIT"} +readme = "docs/README.md" +requires-python = ">=3.14" +dependencies = [ + "pydantic>=2.13.4", + "pydantic-settings>=2.13.1", + "aws-lambda-powertools>=3.29.0", + "boto3>=1.43.6", + "requests>=2.33.1", +] + +[project.scripts] +new = "scripts.new:main" +rename = "scripts.rename:main" + +[dependency-groups] +infra = [ + "aws-cdk-lib>=2.253.0", + "constructs>=10.6.0", +] +dev = [ + "pytest>=9.0.1", + "ruff>=0.15.12", + "coverage>=7.6.9", + "pre-commit>=4.0.1", + "pyright>=1.1.391", + "pytest-mock>=3.15.1", + "moto>=5.2.0", + "hypothesis>=6.152.4", + "click>=8.3.2", +] +docs = [ + "mkdocs>=1.6.1", + "mkdocstrings[python]>=1.0.4", + "mkdocs-material>=9.6.20", +] + +[tool.uv] +default-groups = ["infra", "dev", "docs"] + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["E", "I"] + +[tool.coverage.run] +branch = true +source = ["templates"] + +[tool.coverage.report] +omit = ["tests/*"] +fail_under = 90 + +[tool.pyright] +exclude = ["**/__pycache__", "**/.pytest_cache", ".venv"] +reportMissingImports = "error" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" diff --git a/pyrightconfig.json b/pyrightconfig.json deleted file mode 100644 index 2e18570..0000000 --- a/pyrightconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "exclude": ["**/__pycache__", "**/.pytest_cache", ".venv"], - "reportMissingImports": "error" -} diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index e1350e2..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,11 +0,0 @@ -pytest>=9.0.1 -ruff>=0.15.12 -coverage>=7.6.9 -pre-commit>=4.0.1 -pyright>=1.1.391 -pytest-mock>=3.15.1 -moto>=5.2.0 -hypothesis>=6.152.4 -click>=8.3.2 --r requirements.txt --r requirements-infra.txt diff --git a/requirements-docs.txt b/requirements-docs.txt deleted file mode 100644 index 3d31d8f..0000000 --- a/requirements-docs.txt +++ /dev/null @@ -1,4 +0,0 @@ -mkdocs>=1.6.1 -mkdocstrings[python]>=1.0.4 -mkdocs-material>=9.6.20 --r requirements.txt diff --git a/requirements-infra.txt b/requirements-infra.txt deleted file mode 100644 index 160ebb7..0000000 --- a/requirements-infra.txt +++ /dev/null @@ -1,2 +0,0 @@ -aws-cdk-lib>=2.253.0 -constructs>=10.6.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1a2eeea..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -pydantic>=2.13.4 -pydantic-settings>=2.13.1 -aws-lambda-powertools>=3.29.0 -boto3>=1.43.6 -requests>=2.33.1 diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 26b5ad6..0000000 --- a/ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -line-length = 120 - -[lint] -select = ["E", "I"] diff --git a/scripts/new.py b/scripts/new.py index bdba5f2..2e57bc7 100644 --- a/scripts/new.py +++ b/scripts/new.py @@ -107,11 +107,7 @@ def update_mise_toml(name: str): if f"|{name}" not in content: # Update usage messages using regex - content = re.sub( - r"(Usage: mise run (?:deploy|destroy) stack=<[a-z0-9|]+)>", - r"\1|" + name + ">", - content - ) + content = re.sub(r"(Usage: mise run (?:deploy|destroy) stack=<[a-z0-9|]+)>", r"\1|" + name + ">", content) # Update case statements lines = content.splitlines() diff --git a/scripts/rename.py b/scripts/rename.py index 4e42dfb..1b3b1ee 100644 --- a/scripts/rename.py +++ b/scripts/rename.py @@ -33,11 +33,14 @@ def main(name: str, description: str, author: str, email: str, github: str): replacements = [ ("mkdocs.yml", r"^repo_name: .*", f"repo_name: {github}/{name}"), ("mkdocs.yml", r"^repo_url: .*", f"repo_url: https://github.com/{github}/{name}"), + ("pyproject.toml", r'^name = ".*"', f'name = "{name}"'), + ("pyproject.toml", r'^description = ".*"', f'description = "{description}"'), + ("pyproject.toml", r"^authors = \[.*\]", f'authors = [{{name = "{author}", email = "{email}"}}]'), + ("pyproject.toml", r'^source = \["templates"\]', f'source = ["{source}"]'), ("mise.toml", r"default='templates'", f"default='{name}'"), ("mise.toml", r"default='AWS Lambda Templates'", f"default='{description}'"), ("mise.toml", r"default='Amr Abed'", f"default='{author}'"), ("mise.toml", r"default='amrabed'", f"default='{github}'"), - (".coveragerc", r"^source = .*", f"source = {source}"), ("docs/README.md", r"^# .*", f"# {description}"), (".github/CODEOWNERS", r"@.*", f"@{github}"), (".github/FUNDING.yml", r"^github: .*", f"github: {github}"), @@ -61,7 +64,7 @@ def main(name: str, description: str, author: str, email: str, github: str): dirs[:] = [d for d in dirs if not d.startswith(".") and d != "venv"] for file in files: - if file.endswith((".py", ".md", ".yml", ".pyt", ".toml", ".txt", ".coveragerc", "mise.toml")): + if file.endswith((".py", ".md", ".yml", ".pyt", ".toml")): path = Path(root) / file if path.name == "rename.py": continue From 791c26a44da198fc97ef58a9e9948eb4f13765da Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 22:08:36 +0000 Subject: [PATCH 03/27] Address PR feedback for mise integration - Upgrade mise-action to v4 in GitHub workflows - Refactor mise.toml tasks to use 'usage' for argument parsing - Add project-specific and common shell aliases to mise.toml - Improve scripts/new.py and scripts/rename.py for robust mise.toml updates - Simplify task scripts by utilizing usage environment variables --- .github/workflows/check.yml | 2 +- .github/workflows/deploy.yml | 2 +- .github/workflows/docs.yml | 2 +- mise.toml | 57 +++++++++++++++++++++++++++--------- scripts/new.py | 6 +++- scripts/rename.py | 8 ++--- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0ed131e..780e25d 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: Install mise - uses: jdx/mise-action@v2 + uses: jdx/mise-action@v4 - name: Install dependencies run: mise run install - name: Format and lint diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a73b635..e7c6afc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -45,7 +45,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: Install mise - uses: jdx/mise-action@v2 + uses: jdx/mise-action@v4 - name: Install dependencies run: mise run install - name: Install AWS CDK CLI diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ad309bb..1e8be6e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: Install mise - uses: jdx/mise-action@v2 + uses: jdx/mise-action@v4 - name: Configure Git Credentials run: | git config user.name github-actions[bot] diff --git a/mise.toml b/mise.toml index 78e9cde..13731a7 100644 --- a/mise.toml +++ b/mise.toml @@ -7,17 +7,27 @@ _.python.venv = { path = ".venv", create = true } [tasks.new] description = "Create new Lambda function template" -run = "uv run new -n {{ arg(n='template') }}" +usage = """ +arg "