From 101281763c5e450f60da573688fd5e1316231ceb Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Tue, 11 Aug 2026 00:26:03 +0200 Subject: [PATCH 1/4] feat: validate CDK apps before deployment --- .github/workflows/cdk-deploy-dev.yml | 6 ++-- .github/workflows/cdk-deploy-test.yml | 6 ++-- .projen/deps.json | 7 ++++- .projen/tasks.json | 41 +++++++++++++++++++++++++ .projenrc.py | 44 +++++++++++++++++++++++---- cdk.json | 4 +++ pyproject.toml | 4 +-- src/bin/cicd_helper.py | 13 +++++--- src/bin/env_helper.py | 27 ++++++++-------- uv.lock | 38 ++++++++--------------- 10 files changed, 132 insertions(+), 58 deletions(-) diff --git a/.github/workflows/cdk-deploy-dev.yml b/.github/workflows/cdk-deploy-dev.yml index 0cf4e40..4fd7f6c 100644 --- a/.github/workflows/cdk-deploy-dev.yml +++ b/.github/workflows/cdk-deploy-dev.yml @@ -31,8 +31,8 @@ jobs: - name: Install dependencies run: uv sync - name: Install cdk cli - run: npm install -g aws-cdk - - name: Run CDK synth for the DEV environment - run: uv run projen dev:synth + run: npm install -g aws-cdk@2.1130.0 + - name: Validate CDK for the DEV environment + run: uv run projen dev:validate - name: Deploy CDK to the DEV environment on AWS account 987654321012 run: uv run projen dev:deploy diff --git a/.github/workflows/cdk-deploy-test.yml b/.github/workflows/cdk-deploy-test.yml index 8b1b1c8..943a594 100644 --- a/.github/workflows/cdk-deploy-test.yml +++ b/.github/workflows/cdk-deploy-test.yml @@ -31,8 +31,8 @@ jobs: - name: Install dependencies run: uv sync - name: Install cdk cli - run: npm install -g aws-cdk - - name: Run CDK synth for the TEST environment - run: uv run projen test:synth + run: npm install -g aws-cdk@2.1130.0 + - name: Validate CDK for the TEST environment + run: uv run projen test:validate - name: Deploy CDK to the TEST environment on AWS account 123456789012 run: uv run projen test:deploy diff --git a/.projen/deps.json b/.projen/deps.json index fe80ec2..511a81d 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -5,6 +5,11 @@ "version": "0.99.62", "type": "devenv" }, + { + "name": "pytest", + "version": "9.0.3", + "type": "devenv" + }, { "name": "ruff", "type": "devenv" @@ -19,7 +24,7 @@ }, { "name": "aws-cdk-lib", - "version": "2.254.0", + "version": "2.263.0", "type": "runtime" }, { diff --git a/.projen/tasks.json b/.projen/tasks.json index 4c5438b..0054fc5 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -141,6 +141,20 @@ } ] }, + "dev:validate": { + "name": "dev:validate", + "description": "Validate the stacks on the DEV account", + "env": { + "CDK_DEFAULT_ACCOUNT": "987654321012", + "ENVIRONMENT": "dev" + }, + "steps": [ + { + "exec": "cdk --unstable=validate validate", + "receiveArgs": true + } + ] + }, "diff": { "name": "diff", "description": "Diffs the currently deployed app against your code", @@ -241,6 +255,9 @@ "test": { "name": "test", "description": "Run tests", + "env": { + "PYTHONPATH": "src" + }, "steps": [ { "exec": "pytest" @@ -299,6 +316,30 @@ } ] }, + "test:validate": { + "name": "test:validate", + "description": "Validate the stacks on the TEST account", + "env": { + "CDK_DEFAULT_ACCOUNT": "123456789012", + "ENVIRONMENT": "test" + }, + "steps": [ + { + "exec": "cdk --unstable=validate validate", + "receiveArgs": true + } + ] + }, + "validate": { + "name": "validate", + "description": "Validate the CDK app offline against the default CloudFormation rules", + "steps": [ + { + "exec": "cdk --unstable=validate validate --no-online", + "receiveArgs": true + } + ] + }, "watch": { "name": "watch", "description": "Watches changes in your source code and rebuilds and deploys to the current account", diff --git a/.projenrc.py b/.projenrc.py index 8bff9bf..86847ef 100644 --- a/.projenrc.py +++ b/.projenrc.py @@ -17,6 +17,8 @@ python_version = "3.13" python_major, python_minor = map(int, python_version.split(".")) python_requires = f">={python_version},<{python_major}.{python_minor + 1}" +cdk_version = "2.263.0" +cdk_cli_version = "2.1130.0" # Define the AWS region for the CDK app and github workflows # Default to us-east-1 if AWS_REGION is not set in your environment variables @@ -26,8 +28,12 @@ author_email="danny@towardsthecloud.com", author_name="Danny Steenman", cdk_version_pinning=True, - cdk_version="2.254.0", # Find the latest CDK version here: https://pypi.org/project/aws-cdk-lib - cdk_cli_version="2.1117.0", # Find the latest CDK CLI version https://pypi.org/project/aws-cdk-cli/ + cdk_version=cdk_version, # Find the latest CDK version here: https://pypi.org/project/aws-cdk-lib + cdk_cli_version=cdk_cli_version, # Find the latest CDK CLI version https://pypi.org/project/aws-cdk-cli/ + context={ + "@aws-cdk/core:annotationsInValidationReport": True, + "@aws-cdk/core:validateAgainstDefaultRules": True, + }, module_name=python_module_name, name=project_name, projen_command="uv run projen", @@ -35,7 +41,12 @@ version="2.101.0", app_entrypoint=f"{python_module_name}/app.py", deps=["aws-cdk-github-oidc"], - dev_deps=["projen@0.99.62", "ruff", "ty"], # Find the latest projen version here: https://pypi.org/project/projen/ + dev_deps=[ + "projen@0.99.62", + "pytest@9.0.3", + "ruff", + "ty", + ], # Find the latest projen version here: https://pypi.org/project/projen/ uv=True, uv_options={ "python_exec": f"python{python_version}", @@ -47,7 +58,18 @@ github_options={ "pull_request_lint_options": { "semantic_title_options": { - "types": ["feat", "fix", "chore", "refactor", "perf", "docs", "style", "test", "build", "ci"], + "types": [ + "feat", + "fix", + "chore", + "refactor", + "perf", + "docs", + "style", + "test", + "build", + "ci", + ], }, }, }, @@ -73,6 +95,14 @@ # Set the CDK_DEFAULT_REGION environment variable for the projen tasks, # so the CDK CLI knows which region to use project.tasks.add_environment("CDK_DEFAULT_REGION", aws_region) +project.test_task.env("PYTHONPATH", python_module_name) + +project.add_task( + "validate", + description="Validate the CDK app offline against the default CloudFormation rules", + exec="cdk --unstable=validate validate --no-online", + receive_args=True, +) # Define the target AWS accounts for the different environments target_accounts = { @@ -113,7 +143,9 @@ ) # Add auto-merge step to the auto-approve workflow -auto_approve_workflow = project.try_find_object_file(".github/workflows/auto-approve.yml") +auto_approve_workflow = project.try_find_object_file( + ".github/workflows/auto-approve.yml" +) if auto_approve_workflow: auto_approve_workflow.add_override("jobs.approve.permissions.contents", "write") # Add checkout step before the merge step @@ -143,6 +175,6 @@ ) # Adds GitHub action workflows for deploying the CDK stacks to the target AWS account - github_cicd(gh, account, env, python_version, aws_region) + github_cicd(gh, account, env, python_version, aws_region, cdk_cli_version) project.synth() diff --git a/cdk.json b/cdk.json index 867c37f..ea37381 100644 --- a/cdk.json +++ b/cdk.json @@ -1,5 +1,9 @@ { "app": "python src/app.py", + "context": { + "@aws-cdk/core:annotationsInValidationReport": true, + "@aws-cdk/core:validateAgainstDefaultRules": true + }, "output": "cdk.out", "watch": { "include": [ diff --git a/pyproject.toml b/pyproject.toml index 0692cb8..add65b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" requires-python = ">=3.13,<3.14" dependencies = [ "aws-cdk-github-oidc", - "aws-cdk-lib==2.254.0", + "aws-cdk-lib==2.263.0", "constructs>=10.5.1,<11.0.0" ] @@ -19,4 +19,4 @@ dependencies = [ email = "danny@towardsthecloud.com" [dependency-groups] -dev = [ "projen==0.99.62", "ruff", "ty", "pytest==9.0.3" ] +dev = [ "projen==0.99.62", "pytest==9.0.3", "ruff", "ty" ] diff --git a/src/bin/cicd_helper.py b/src/bin/cicd_helper.py index b008a28..57454fd 100644 --- a/src/bin/cicd_helper.py +++ b/src/bin/cicd_helper.py @@ -1,10 +1,13 @@ from projen import github -def github_cicd(gh, account, env, python_version, aws_region): +def github_cicd(gh, account, env, python_version, aws_region, cdk_cli_version): # Add a GitHub workflow for deploying the CDK stacks to the AWS account cdk_deployment_workflow = github.GithubWorkflow(gh, f"cdk-deploy-{env}") - cdk_deployment_workflow.on(push={"branches": ["main"]} if env != "production" else None, workflow_dispatch={}) + cdk_deployment_workflow.on( + push={"branches": ["main"]} if env != "production" else None, + workflow_dispatch={}, + ) cdk_deployment_workflow.add_jobs( { @@ -46,11 +49,11 @@ def github_cicd(gh, account, env, python_version, aws_region): }, { "name": "Install cdk cli", - "run": "npm install -g aws-cdk", + "run": f"npm install -g aws-cdk@{cdk_cli_version}", }, { - "name": f"Run CDK synth for the {env.upper()} environment", - "run": f"uv run projen {env}:synth", + "name": f"Validate CDK for the {env.upper()} environment", + "run": f"uv run projen {env}:validate", }, { "name": f"Deploy CDK to the {env.upper()} environment on AWS account {account}", diff --git a/src/bin/env_helper.py b/src/bin/env_helper.py index 19e9c07..b887bdf 100644 --- a/src/bin/env_helper.py +++ b/src/bin/env_helper.py @@ -1,25 +1,26 @@ -from typing import Dict - from projen.awscdk import AwsCdkPythonApp -def cdk_action_task(project: AwsCdkPythonApp, target_account: Dict[str, str]): - task_actions = ["synth", "diff", "deploy", "destroy"] +def cdk_action_task(project: AwsCdkPythonApp, target_account: dict[str, str]): stack_name_pattern = f"*Stack-{target_account['ENVIRONMENT']}" + action_commands = { + "synth": ("cdk synth", False), + "validate": ("cdk --unstable=validate validate", True), + "diff": (f"cdk diff --require-approval never {stack_name_pattern}", False), + "deploy": (f"cdk deploy --require-approval never {stack_name_pattern}", False), + "destroy": (f"cdk destroy --force {stack_name_pattern}", False), + } - for action in task_actions: + for action, (exec_command, receive_args) in action_commands.items(): task_name = f"{target_account['ENVIRONMENT']}:{action}" task_description = f"{action.capitalize()} the stacks on the {target_account['ENVIRONMENT'].upper()} account" - exec_command = f"cdk {action} --require-approval never {stack_name_pattern}" - if action == "destroy": - exec_command = f"cdk destroy --force {stack_name_pattern}" - if action == "synth": - exec_command = "cdk synth" - - project.add_task( + task = project.add_task( task_name, description=task_description, env=target_account, - exec=exec_command, ) + if receive_args: + task.exec(exec_command, receive_args=True) + else: + task.exec(exec_command) diff --git a/uv.lock b/uv.lock index 175b801..b4adaa9 100644 --- a/uv.lock +++ b/uv.lock @@ -13,16 +13,16 @@ wheels = [ [[package]] name = "aws-cdk-asset-awscli-v1" -version = "2.2.273" +version = "2.2.282" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsii" }, { name = "publication" }, { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/11/925a1ae8dd7c9fd7e775b405f357970bdf975f54550923c6c755ac24a00d/aws_cdk_asset_awscli_v1-2.2.273.tar.gz", hash = "sha256:6580dad3416e53712db434f81add6fb4a314e1a80f9c57cc42606df1f64c8e0f", size = 20370823, upload-time = "2026-03-30T16:58:42.105Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/30/90558d9e05c2b1a5a8d7d87332b4bed4a2e5d2eb04cc7064f6e9e0c8a2f2/aws_cdk_asset_awscli_v1-2.2.282.tar.gz", hash = "sha256:f86e61653927f77fb235b5ec148c955c610117430c869d182c8b20f7e07e2df2", size = 20740538, upload-time = "2026-05-25T21:33:20.444Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/eb/817ecd9e0987465114d17808bb8d10907ef64c9ea6029addfab0ab9aa055/aws_cdk_asset_awscli_v1-2.2.273-py3-none-any.whl", hash = "sha256:1a0994afa7b48f63b580603be64c7a99d19ed6777bdf81d3c2435d8b43cf0d71", size = 20369281, upload-time = "2026-03-30T16:58:39.474Z" }, + { url = "https://files.pythonhosted.org/packages/c5/86/dcb45969f1b34351cfd9afdb6b35bff38a3e929c8bc42b07036879f3a62e/aws_cdk_asset_awscli_v1-2.2.282-py3-none-any.whl", hash = "sha256:24139da0eb1be59f8cfda22c6343d51e8d50bb89b5052b049cfab92683de7790", size = 20738955, upload-time = "2026-05-25T21:33:17.673Z" }, ] [[package]] @@ -41,16 +41,15 @@ wheels = [ [[package]] name = "aws-cdk-cloud-assembly-schema" -version = "53.24.0" +version = "54.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsii" }, { name = "publication" }, - { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/67/a386fee11c1d51ad57d2c045f228f6a57b0fc846eb8b441fc98fbdf1a4b1/aws_cdk_cloud_assembly_schema-53.24.0.tar.gz", hash = "sha256:f999f4c777deaca6631c61993bf5583022ff57c3a94a65930e2fc6b68cb7c407", size = 212924, upload-time = "2026-05-14T17:07:18.047Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/c9/732b7ca25bcc8a2bb80aeaa9c34ab2fd111a53477742d2f7b68937b7a180/aws_cdk_cloud_assembly_schema-54.17.0.tar.gz", hash = "sha256:ecf54cbd656c8c85a8df47291be791e60c92e8aca193757667024e7805adf55d", size = 282890, upload-time = "2026-08-07T13:29:27.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/21/34/b180fe10ae8c314d5f8c2e095a57669d54bcb036dc63b001eace16c88052/aws_cdk_cloud_assembly_schema-53.24.0-py3-none-any.whl", hash = "sha256:360c4804f3073601ac320d1773432bc45b34201d7c8fb85aff7ed536801efb0c", size = 212811, upload-time = "2026-05-14T17:07:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/72/e2/590fa96d944601c88eb2e6160071af413a0347ea4f561f043f14e0220744/aws_cdk_cloud_assembly_schema-54.17.0-py3-none-any.whl", hash = "sha256:d727b55da80b44ec02c6eb74b3f7271656e3a47f761b4d6b41784303cbf94308", size = 281957, upload-time = "2026-08-07T13:29:25.57Z" }, ] [[package]] @@ -71,7 +70,7 @@ wheels = [ [[package]] name = "aws-cdk-lib" -version = "2.254.0" +version = "2.263.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aws-cdk-asset-awscli-v1" }, @@ -80,11 +79,10 @@ dependencies = [ { name = "constructs" }, { name = "jsii" }, { name = "publication" }, - { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/94/667be78bf5f39aef15ff34778eda0443bb4ad2498f33ccb6f7629f343f43/aws_cdk_lib-2.254.0.tar.gz", hash = "sha256:ddbef134cad91f8985444f77f052f0337af5f132101ad7aea2215b4775ff7828", size = 49658861, upload-time = "2026-05-13T21:59:39.35Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/62/41de6ea7bf3c10a18a3d70c42c0fe770c8e7c4b20cb9a7b4d95e295b50d6/aws_cdk_lib-2.263.0.tar.gz", hash = "sha256:fc87a36758c93c95845bb4889c21a899eb639b78e43d09d965d9d924233e60f6", size = 55074638, upload-time = "2026-07-31T16:47:16.594Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/3c/13c490cba548fde101663fb6d9050eeee67686a9730e74cba5711ba12068/aws_cdk_lib-2.254.0-py3-none-any.whl", hash = "sha256:626095eaa742e0b9d894c3a1bf06a6e7d1245a986165a72408871d41886c6d07", size = 50343718, upload-time = "2026-05-13T21:58:54.123Z" }, + { url = "https://files.pythonhosted.org/packages/10/c3/e8d1cc686828e8213be2929db1d21b95beb50fcde36b6ecff309eae75916/aws_cdk_lib-2.263.0-py3-none-any.whl", hash = "sha256:a8d7928c7a01c25f6cb85c98e465df6ffd2b9e696bdb256257eeca2157c80609", size = 55742744, upload-time = "2026-07-31T16:46:31.48Z" }, ] [[package]] @@ -108,7 +106,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "aws-cdk-github-oidc" }, - { name = "aws-cdk-lib", specifier = "==2.254.0" }, + { name = "aws-cdk-lib", specifier = "==2.263.0" }, { name = "constructs", specifier = ">=10.5.1,<11.0.0" }, ] @@ -156,15 +154,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/38/6de46d122a2fcd275a5f1fa4ad1d8d2058afd6b72d8db5f0c125515cbb5c/constructs-10.6.0-py3-none-any.whl", hash = "sha256:ad4ffabdb53c17cde00fb94e441a1ba9fddac57c92ad49d263f8dbd416cec513", size = 66969, upload-time = "2026-03-23T09:00:53.041Z" }, ] -[[package]] -name = "importlib-resources" -version = "6.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" @@ -176,20 +165,19 @@ wheels = [ [[package]] name = "jsii" -version = "1.130.0" +version = "1.139.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "cattrs" }, - { name = "importlib-resources" }, { name = "publication" }, { name = "python-dateutil" }, { name = "typeguard" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0b/36/d84bb41b72b5a830dc87f1daea521ff4da024a08c1bd0b9b34989fe84bcf/jsii-1.130.0.tar.gz", hash = "sha256:7436ae382e2de27970b34a4ccfef953a45980c5070241c1bd610bf3af68a2d6b", size = 445207, upload-time = "2026-05-14T18:35:31.792Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/71/7c612c16291a6dc654bac00f56bef24c45f86e9a7c9668dc7d36f187e808/jsii-1.139.0.tar.gz", hash = "sha256:163c5d3ec00fd4ec89a33b9097f20a6f27626dd69d6875a8f7cc7577b8021ad0", size = 531387, upload-time = "2026-07-17T02:34:33.293Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/34/2dc16666ee53c1158fde17c2b713a85dc90eab029fb832b9564751f40eeb/jsii-1.130.0-py3-none-any.whl", hash = "sha256:ce50e11ea588fe6b2d0766d90edaf4c78b9e97e2e1f075fbd8bc29349c6503c8", size = 418405, upload-time = "2026-05-14T18:35:30.283Z" }, + { url = "https://files.pythonhosted.org/packages/33/3e/fce01768f79b2d5d0cf6258b55045f4b083ee86fd5de24c1af38168312ab/jsii-1.139.0-py3-none-any.whl", hash = "sha256:11468f767c6da698ed9888a04352850af33ccccfec7656475626caf36fca8bbb", size = 501693, upload-time = "2026-07-17T02:34:31.747Z" }, ] [[package]] From f0f6cd9ce4357e62521056e52d921ecbdb8f7510 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Tue, 11 Aug 2026 00:31:08 +0200 Subject: [PATCH 2/4] refactor: centralize CDK validation task config --- .projen/tasks.json | 3 --- .projenrc.py | 9 ++++++--- pyproject.toml | 5 +++-- src/bin/env_helper.py | 19 +++++++++---------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.projen/tasks.json b/.projen/tasks.json index 0054fc5..c913550 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -255,9 +255,6 @@ "test": { "name": "test", "description": "Run tests", - "env": { - "PYTHONPATH": "src" - }, "steps": [ { "exec": "pytest" diff --git a/.projenrc.py b/.projenrc.py index 86847ef..1238bfb 100644 --- a/.projenrc.py +++ b/.projenrc.py @@ -9,7 +9,7 @@ from projen.awscdk import AwsCdkPythonApp from src.bin.cicd_helper import github_cicd -from src.bin.env_helper import cdk_action_task +from src.bin.env_helper import CDK_VALIDATE_COMMAND, cdk_action_task # Define the python module name and set the python version project_name = "aws-cdk-python-starter-kit" @@ -95,12 +95,15 @@ # Set the CDK_DEFAULT_REGION environment variable for the projen tasks, # so the CDK CLI knows which region to use project.tasks.add_environment("CDK_DEFAULT_REGION", aws_region) -project.test_task.env("PYTHONPATH", python_module_name) + +pyproject = project.try_find_object_file("pyproject.toml") +if pyproject: + pyproject.add_override("tool.pytest.ini_options.pythonpath", [python_module_name]) project.add_task( "validate", description="Validate the CDK app offline against the default CloudFormation rules", - exec="cdk --unstable=validate validate --no-online", + exec=f"{CDK_VALIDATE_COMMAND} --no-online", receive_args=True, ) diff --git a/pyproject.toml b/pyproject.toml index add65b0..7d2b6de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,5 @@ # ~~ Generated by projen. To modify, edit .projenrc.py and run "uv run projen". -tool = { } - [project] name = "aws-cdk-python-starter-kit" version = "2.101.0" @@ -20,3 +18,6 @@ dependencies = [ [dependency-groups] dev = [ "projen==0.99.62", "pytest==9.0.3", "ruff", "ty" ] + +[tool.pytest.ini_options] +pythonpath = [ "src" ] diff --git a/src/bin/env_helper.py b/src/bin/env_helper.py index b887bdf..8dac425 100644 --- a/src/bin/env_helper.py +++ b/src/bin/env_helper.py @@ -1,17 +1,19 @@ from projen.awscdk import AwsCdkPythonApp +CDK_VALIDATE_COMMAND = "cdk --unstable=validate validate" + def cdk_action_task(project: AwsCdkPythonApp, target_account: dict[str, str]): stack_name_pattern = f"*Stack-{target_account['ENVIRONMENT']}" action_commands = { - "synth": ("cdk synth", False), - "validate": ("cdk --unstable=validate validate", True), - "diff": (f"cdk diff --require-approval never {stack_name_pattern}", False), - "deploy": (f"cdk deploy --require-approval never {stack_name_pattern}", False), - "destroy": (f"cdk destroy --force {stack_name_pattern}", False), + "synth": "cdk synth", + "validate": CDK_VALIDATE_COMMAND, + "diff": f"cdk diff --require-approval never {stack_name_pattern}", + "deploy": f"cdk deploy --require-approval never {stack_name_pattern}", + "destroy": f"cdk destroy --force {stack_name_pattern}", } - for action, (exec_command, receive_args) in action_commands.items(): + for action, exec_command in action_commands.items(): task_name = f"{target_account['ENVIRONMENT']}:{action}" task_description = f"{action.capitalize()} the stacks on the {target_account['ENVIRONMENT'].upper()} account" @@ -20,7 +22,4 @@ def cdk_action_task(project: AwsCdkPythonApp, target_account: dict[str, str]): description=task_description, env=target_account, ) - if receive_args: - task.exec(exec_command, receive_args=True) - else: - task.exec(exec_command) + task.exec(exec_command, receive_args=True if action == "validate" else None) From 11a7bcaf50885d1456a7a05e01c2ead8c8ddd36b Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Tue, 11 Aug 2026 00:36:10 +0200 Subject: [PATCH 3/4] refactor: keep test setup unchanged --- .projen/deps.json | 7 +------ .projenrc.py | 6 +----- pyproject.toml | 7 +++---- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/.projen/deps.json b/.projen/deps.json index 511a81d..b22208b 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -5,11 +5,6 @@ "version": "0.99.62", "type": "devenv" }, - { - "name": "pytest", - "version": "9.0.3", - "type": "devenv" - }, { "name": "ruff", "type": "devenv" @@ -34,7 +29,7 @@ }, { "name": "pytest", - "version": "7.4.3", + "version": "9.0.3", "type": "test" } ], diff --git a/.projenrc.py b/.projenrc.py index 1238bfb..0093745 100644 --- a/.projenrc.py +++ b/.projenrc.py @@ -43,10 +43,10 @@ deps=["aws-cdk-github-oidc"], dev_deps=[ "projen@0.99.62", - "pytest@9.0.3", "ruff", "ty", ], # Find the latest projen version here: https://pypi.org/project/projen/ + pytest_options={"version": "9.0.3"}, uv=True, uv_options={ "python_exec": f"python{python_version}", @@ -96,10 +96,6 @@ # so the CDK CLI knows which region to use project.tasks.add_environment("CDK_DEFAULT_REGION", aws_region) -pyproject = project.try_find_object_file("pyproject.toml") -if pyproject: - pyproject.add_override("tool.pytest.ini_options.pythonpath", [python_module_name]) - project.add_task( "validate", description="Validate the CDK app offline against the default CloudFormation rules", diff --git a/pyproject.toml b/pyproject.toml index 7d2b6de..2460268 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,7 @@ # ~~ Generated by projen. To modify, edit .projenrc.py and run "uv run projen". +tool = { } + [project] name = "aws-cdk-python-starter-kit" version = "2.101.0" @@ -17,7 +19,4 @@ dependencies = [ email = "danny@towardsthecloud.com" [dependency-groups] -dev = [ "projen==0.99.62", "pytest==9.0.3", "ruff", "ty" ] - -[tool.pytest.ini_options] -pythonpath = [ "src" ] +dev = [ "projen==0.99.62", "ruff", "ty", "pytest==9.0.3" ] From 494d7cd29688ff65b06f127cfb2ae15c0dec75e9 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Tue, 11 Aug 2026 14:32:32 +0200 Subject: [PATCH 4/4] chore: align Projen and disable CDK telemetry --- .projen/deps.json | 2 +- .projen/tasks.json | 75 +++++++++++++++++++++++++++++++++++----------- .projenrc.py | 3 +- cdk.json | 3 +- pyproject.toml | 2 +- uv.lock | 9 +++--- 6 files changed, 68 insertions(+), 26 deletions(-) diff --git a/.projen/deps.json b/.projen/deps.json index b22208b..60c7cdf 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -2,7 +2,7 @@ "dependencies": [ { "name": "projen", - "version": "0.99.62", + "version": "0.101.11", "type": "devenv" }, { diff --git a/.projen/tasks.json b/.projen/tasks.json index c913550..655de10 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -1,4 +1,10 @@ { + "manifestVersion": 3, + "env": { + "VIRTUAL_ENV": ".venv", + "PATH": "$(echo .venv/bin:$PATH)", + "CDK_DEFAULT_REGION": "us-east-1" + }, "tasks": { "build": { "name": "build", @@ -65,7 +71,10 @@ "description": "Synthesize project files", "steps": [ { - "exec": "python .projenrc.py" + "execArgs": [ + "python", + ".projenrc.py" + ] } ] }, @@ -74,7 +83,10 @@ "description": "Deploys your CDK app to the AWS cloud", "steps": [ { - "exec": "cdk deploy", + "execArgs": [ + "cdk", + "deploy" + ], "receiveArgs": true } ] @@ -84,7 +96,10 @@ "description": "Destroys your cdk app in the AWS cloud", "steps": [ { - "exec": "cdk destroy", + "execArgs": [ + "cdk", + "destroy" + ], "receiveArgs": true } ] @@ -160,7 +175,10 @@ "description": "Diffs the currently deployed app against your code", "steps": [ { - "exec": "cdk diff" + "execArgs": [ + "cdk", + "diff" + ] } ] }, @@ -190,7 +208,10 @@ "description": "Install dependencies with frozen lockfile", "steps": [ { - "exec": "uv sync" + "execArgs": [ + "uv", + "sync" + ] } ] }, @@ -199,7 +220,10 @@ "description": "Creates the distribution package", "steps": [ { - "exec": "uv build" + "execArgs": [ + "uv", + "build" + ] } ] }, @@ -221,7 +245,10 @@ "description": "Uploads the package to PyPI.", "steps": [ { - "exec": "uv publish" + "execArgs": [ + "uv", + "publish" + ] } ] }, @@ -230,7 +257,12 @@ "description": "Uploads the package against a test PyPI endpoint.", "steps": [ { - "exec": "uv publish --index testpypi" + "execArgs": [ + "uv", + "publish", + "--index", + "testpypi" + ] } ] }, @@ -239,7 +271,10 @@ "description": "Synthesizes your cdk app into cdk.out", "steps": [ { - "exec": "cdk synth" + "execArgs": [ + "cdk", + "synth" + ] } ] }, @@ -248,7 +283,11 @@ "description": "Synthesizes your cdk app into cdk.out and suppresses the template in stdout (part of \"yarn build\")", "steps": [ { - "exec": "cdk synth -q" + "execArgs": [ + "cdk", + "synth", + "-q" + ] } ] }, @@ -342,18 +381,20 @@ "description": "Watches changes in your source code and rebuilds and deploys to the current account", "steps": [ { - "exec": "cdk deploy --hotswap" + "execArgs": [ + "cdk", + "deploy", + "--hotswap" + ] }, { - "exec": "cdk watch" + "execArgs": [ + "cdk", + "watch" + ] } ] } }, - "env": { - "VIRTUAL_ENV": ".venv", - "PATH": "$(echo .venv/bin:$PATH)", - "CDK_DEFAULT_REGION": "us-east-1" - }, "//": "~~ Generated by projen. To modify, edit .projenrc.py and run \"uv run projen\"." } diff --git a/.projenrc.py b/.projenrc.py index 0093745..9fa4a9a 100644 --- a/.projenrc.py +++ b/.projenrc.py @@ -33,6 +33,7 @@ context={ "@aws-cdk/core:annotationsInValidationReport": True, "@aws-cdk/core:validateAgainstDefaultRules": True, + "cli-telemetry": False, }, module_name=python_module_name, name=project_name, @@ -42,7 +43,7 @@ app_entrypoint=f"{python_module_name}/app.py", deps=["aws-cdk-github-oidc"], dev_deps=[ - "projen@0.99.62", + "projen@0.101.11", "ruff", "ty", ], # Find the latest projen version here: https://pypi.org/project/projen/ diff --git a/cdk.json b/cdk.json index ea37381..837fefb 100644 --- a/cdk.json +++ b/cdk.json @@ -2,7 +2,8 @@ "app": "python src/app.py", "context": { "@aws-cdk/core:annotationsInValidationReport": true, - "@aws-cdk/core:validateAgainstDefaultRules": true + "@aws-cdk/core:validateAgainstDefaultRules": true, + "cli-telemetry": false }, "output": "cdk.out", "watch": { diff --git a/pyproject.toml b/pyproject.toml index 2460268..6348ff4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,4 +19,4 @@ dependencies = [ email = "danny@towardsthecloud.com" [dependency-groups] -dev = [ "projen==0.99.62", "ruff", "ty", "pytest==9.0.3" ] +dev = [ "projen==0.101.11", "ruff", "ty", "pytest==9.0.3" ] diff --git a/uv.lock b/uv.lock index b4adaa9..38aa616 100644 --- a/uv.lock +++ b/uv.lock @@ -112,7 +112,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "projen", specifier = "==0.99.62" }, + { name = "projen", specifier = "==0.101.11" }, { name = "pytest", specifier = "==9.0.3" }, { name = "ruff" }, { name = "ty" }, @@ -200,17 +200,16 @@ wheels = [ [[package]] name = "projen" -version = "0.99.62" +version = "0.101.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "constructs" }, { name = "jsii" }, { name = "publication" }, - { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5d/c6/89d291618a10347fee0e6d6de98220c8f7a1ffdf2a82dc52be51fbe89b45/projen-0.99.62.tar.gz", hash = "sha256:b00a56e4b46ad655a3682fa14a875e47d0809f5e7add9aa75712dc0b065af743", size = 4416957, upload-time = "2026-05-18T10:40:26.121Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/71/4be3673189287e80dd9c69858c71b2f6cb6a47877001be05e6222d8499ce/projen-0.101.11.tar.gz", hash = "sha256:4f4fdf92cba4f984065d787e56f831a042003db6dce483082150fa5d5f792e73", size = 5259131, upload-time = "2026-07-10T14:38:34.116Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/95/10a1f64078026c330a23fa596526f2ec102069222d9093994bc16d5eef71/projen-0.99.62-py3-none-any.whl", hash = "sha256:e566c6d73039cc7a140b4a7622f144092019281169a49a69f1d7fe84a0f144ca", size = 4426000, upload-time = "2026-05-18T10:40:22.83Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0f/9feb085c4e0bfcfe59211a90897eee138124b35544b42ad663fceb0010e8/projen-0.101.11-py3-none-any.whl", hash = "sha256:5b5657bf192e469b08f7fe4597e19623d9fb7103ae1a63ee5e6aef7507acea92", size = 5265790, upload-time = "2026-07-10T14:38:31.108Z" }, ] [[package]]