From 4ef3e5cc36a4af9a1aadc7e8be09697e9ea3f1cb Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Sat, 24 Jan 2026 11:38:57 +0000 Subject: [PATCH 1/4] copier --- .coderabbit.yaml | 4 + .copier-answers.yml | 2 +- .devcontainer/Dockerfile | 9 +- .devcontainer/devcontainer.json | 16 ++-- .devcontainer/install-ci-tooling.py | 14 +-- .github/actions/install_deps/action.yml | 4 +- .../update-devcontainer-hash/action.yml | 3 - .../build-docker-image.yaml | 2 +- .github/workflows/ci.yaml | 2 +- .github/workflows/pre-commit.yaml | 2 +- .pre-commit-config.yaml | 8 +- copier.yml | 19 +++- extensions/context.py | 94 +++++++++---------- pyproject.toml | 14 +-- template/.coderabbit.yaml | 4 + template/.devcontainer/Dockerfile | 9 +- .../.devcontainer/devcontainer.json.jinja | 22 ++--- .../.devcontainer/install-ci-tooling.py.jinja | 4 +- .../actions/check-skip-duplicates/action.yml | 44 +++++++++ .../.github/actions/install_deps/action.yml | 4 +- .../update-devcontainer-hash/action.yml | 3 - template/.github/workflows/pre-commit.yaml | 2 +- template/.pre-commit-config.yaml | 8 +- template/ty.toml | 18 ++++ tests/copier_data/data1.yaml | 1 + tests/copier_data/data2.yaml | 1 + tests/copier_data/data3.yaml | 1 + ty.toml | 18 ++++ uv.lock | 44 +++++++-- 29 files changed, 252 insertions(+), 124 deletions(-) create mode 100644 template/.github/actions/check-skip-duplicates/action.yml create mode 100644 template/ty.toml create mode 100644 ty.toml diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 213afdd5..9904260d 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -1,9 +1,12 @@ # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +early_access: true reviews: profile: assertive path_instructions: - path: "**/vendor_files/**" instructions: "These files came from a vendor and we're not allowed to change them. Refer to it if you need to understand how the main code interacts with it, but do not make comments about it." + - path: "**/*.py" + instructions: "Do not express concerns about assert statements being removed by using the -O python flag; we never use that flag. Do not express concerns about ruff rules; a pre-commit hook already runs a ruff check. Do not warn about unnecessary super().init() calls; pyright prefers those to be present." tools: eslint: # when the code contains typescript, eslint will be run by pre-commit, and coderabbit often generates false positives enabled: false @@ -14,6 +17,7 @@ reviews: flake8: # we use ruff instead (when we use Python) enabled: false poem: false + in_progress_fortune: false # the commit status is driven by our repository config and required checks, we don't want CodeRabbit messing with it commit_status: false auto_review: diff --git a/.copier-answers.yml b/.copier-answers.yml index c151c79c..7c504b91 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: v0.0.90 +_commit: v0.0.94 _src_path: gh:LabAutomationAndScreening/copier-base-template.git description: Copier template for creating Python libraries and executables install_claude_cli: false diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 955146c0..70842f4a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,19 +1,22 @@ # base image tags available at https://mcr.microsoft.com/v2/devcontainers/universal/tags/list # added the platform flag to override any local settings since this image is only compatible with linux/amd64. since this image is only x64 compatible, suppressing the hadolint rule # hadolint ignore=DL3029 -FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:2.13.1-focal +FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.1-noble SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# temporary hack until yarn updates its GPG key +RUN rm /etc/apt/sources.list.d/yarn.list || true + RUN apt-get update -y && apt-get install -y \ - "bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.10' | head -n 1)" --no-install-recommends \ + "bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.11' | head -n 1)" --no-install-recommends \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Create the venv folder and set permissions for anyone to modify---this is necessary to be able to break out the venv folder as a separate docker volume for better performance on Windows hosts ARG REPO_NAME=copier-base-template ENV VENV_PATH=/workspaces/${REPO_NAME}/.venv -RUN mkdir -p /workspace && \ +RUN mkdir -p /workspaces && \ mkdir -p ${VENV_PATH} && \ chmod -R 777 /workspaces ${VENV_PATH} && \ chgrp -R 0 /workspaces ${VENV_PATH} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 25e01643..f7645f17 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,24 +16,24 @@ "extensions": [ // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.16.1", + "coderabbit.coderabbit-vscode@0.16.6", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", "github.copilot@1.388.0", - "github.copilot-chat@0.34.2025112401", + "github.copilot-chat@0.36.2026010502", // Python - "ms-python.python@2025.17.2025100201", - "ms-python.vscode-pylance@2025.8.3", + "ms-python.python@2025.21.2026010501", + "ms-python.vscode-pylance@2025.10.100", "ms-vscode-remote.remote-containers@0.414.0", - "charliermarsh.ruff@2025.28.0", + "charliermarsh.ruff@2025.32.0", // Misc file formats - "bierner.markdown-mermaid@1.28.0", + "bierner.markdown-mermaid@1.29.0", "samuelcolvin.jinjahtml@0.20.0", "tamasfe.even-better-toml@0.19.2", "emilast.LogFileHighlighter@3.3.3", - "esbenp.prettier-vscode@11.0.0" + "esbenp.prettier-vscode@11.0.2" ], "settings": { "editor.accessibilitySupport": "off", // turn off sounds @@ -58,5 +58,5 @@ "initializeCommand": "sh .devcontainer/initialize-command.sh", "onCreateCommand": "sh .devcontainer/on-create-command.sh", "postStartCommand": "sh .devcontainer/post-start-command.sh" - // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 99b3f7c4 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 69bb472f # spellchecker:disable-line } diff --git a/.devcontainer/install-ci-tooling.py b/.devcontainer/install-ci-tooling.py index 0de75239..5d6a223e 100644 --- a/.devcontainer/install-ci-tooling.py +++ b/.devcontainer/install-ci-tooling.py @@ -7,11 +7,11 @@ import tempfile from pathlib import Path -UV_VERSION = "0.9.17" -PNPM_VERSION = "10.25.0" -COPIER_VERSION = "9.11.0" -COPIER_TEMPLATE_EXTENSIONS_VERSION = "0.3.3" -PRE_COMMIT_VERSION = "4.5.0" +UV_VERSION = "0.9.26" +PNPM_VERSION = "10.28.1" +COPIER_VERSION = "==9.11.2" +COPIER_TEMPLATE_EXTENSIONS_VERSION = "==0.3.3" +PRE_COMMIT_VERSION = "4.5.1" GITHUB_WINDOWS_RUNNER_BIN_PATH = r"C:\Users\runneradmin\.local\bin" INSTALL_SSM_PLUGIN_BY_DEFAULT = False parser = argparse.ArgumentParser(description="Install CI tooling for the repo") @@ -76,9 +76,9 @@ def main(): uv_path, "tool", "install", - f"copier=={COPIER_VERSION}", + f"copier{COPIER_VERSION}", "--with", - f"copier-template-extensions=={COPIER_TEMPLATE_EXTENSIONS_VERSION}", + f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", ], check=True, env=uv_env, diff --git a/.github/actions/install_deps/action.yml b/.github/actions/install_deps/action.yml index 48796359..b212d095 100644 --- a/.github/actions/install_deps/action.yml +++ b/.github/actions/install_deps/action.yml @@ -58,13 +58,13 @@ runs: - name: Setup python if: ${{ inputs.python-version != 'notUsing' }} - uses: actions/setup-python@v6.1.0 + uses: actions/setup-python@v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Setup node if: ${{ inputs.node-version != 'notUsing' }} - uses: actions/setup-node@v6.1.0 + uses: actions/setup-node@v6.2.0 with: node-version: ${{ inputs.node-version }} diff --git a/.github/actions/update-devcontainer-hash/action.yml b/.github/actions/update-devcontainer-hash/action.yml index 4e6d434c..148062b4 100644 --- a/.github/actions/update-devcontainer-hash/action.yml +++ b/.github/actions/update-devcontainer-hash/action.yml @@ -5,9 +5,6 @@ inputs: description: 'Branch to checkout and update' required: true -permissions: - contents: write - outputs: new-sha: description: 'The SHA of the branch tip after update' diff --git a/.github/reusable_workflows/build-docker-image.yaml b/.github/reusable_workflows/build-docker-image.yaml index f4f4a7a0..cd44408a 100644 --- a/.github/reusable_workflows/build-docker-image.yaml +++ b/.github/reusable_workflows/build-docker-image.yaml @@ -156,7 +156,7 @@ jobs: - name: Upload Docker Image Artifact if: ${{ inputs.save-as-artifact }} - uses: actions/upload-artifact@v5.0.0 + uses: actions/upload-artifact@v6.0.0 with: name: ${{ steps.calculate-build-context-hash.outputs.image_name_no_slashes }} path: ${{ steps.calculate-build-context-hash.outputs.image_name_no_slashes }}.tar diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d49e7666..fa80fe8a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -113,7 +113,7 @@ jobs: timeout-minutes: 8 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it - name: Cache Pre-commit hooks - uses: actions/cache@v4.3.0 + uses: actions/cache@v5.0.2 env: cache-name: cache-pre-commit-hooks with: diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 40c0a513..50295750 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -59,7 +59,7 @@ jobs: timeout-minutes: 8 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it - name: Cache Pre-commit hooks - uses: actions/cache@v4.3.0 + uses: actions/cache@v5.0.2 env: cache-name: cache-pre-commit-hooks with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9e1bbd5..e0dbbb7f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: # Reformatting (should generally come before any file format or other checks, because reformatting can change things) - repo: https://github.com/crate-ci/typos - rev: 802d5794ff9cf7b15610c47eca99cd1ab757d8d4 # frozen: v1 + rev: b31d3aa6e8e43e6a9cf7a1d137baf189dec0922b # frozen: v1 hooks: - id: typos exclude: | @@ -195,12 +195,12 @@ repos: - id: check-case-conflict - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 16a6ad2fead09286ee6eb6b0a3fab55655a6c22a # frozen: 0.35.0 + rev: b035497fb64e3f9faa91e833331688cc185891e6 # frozen: 0.36.0 hooks: - id: check-github-workflows - repo: https://github.com/maresb/check-json5 - rev: 893a2b5a0a27c3540bd8fcafe2968ccc05237179 # 1.0 + rev: bd4737432a2175617a9eeaa510ab369cbc1cbd3d # frozen: v1.0.1 hooks: - id: check-json5 files: | @@ -249,7 +249,7 @@ repos: description: Runs hadolint to lint Dockerfiles - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 1a1f58ba4c35362efe8fed2279715a905baee93d # frozen: v0.14.8 + rev: 5ba58aca0bd5bc7c0e1c0fc45af2e88d6a2bde83 # frozen: v0.14.10 hooks: - id: ruff name: ruff-src diff --git a/copier.yml b/copier.yml index 7750ac88..33d14b15 100644 --- a/copier.yml +++ b/copier.yml @@ -1,3 +1,9 @@ +# Questions specific to this template + + + + + # Questions managed by upstream template repo_name: type: str @@ -27,6 +33,11 @@ ssh_port_number: # Pick a random port, but ensure it's not in the excluded port range on Windows (powershell: `netsh int ipv4 show excludedportrange protocol=tcp`) default: "{{ ( (range(49152, 49752) | list) + (range(49852, 50000) | list) + (range(50060, 50160) | list) + (range(50160, 50260) | list) + (range(50260, 50360) | list) + (range(50914, 51014) | list) + (range(51114, 51214) | list) + (range(51214, 51314) | list) + (range(51314, 51414) | list) + (range(51623, 51723) | list) + (range(51723, 51823) | list) + (range(65269, 65369) | list) + (range(65369, 65469) | list) ) | random }}" +pull_from_ecr: + type: bool + help: Will you need to pull images from a central AWS Elastic Container Registry? + default: no + use_windows_in_ci: type: bool help: Should CI in the instantiated template also use Windows runners? @@ -72,24 +83,24 @@ python_ci_versions: aws_identity_center_id: type: str help: What's the ID of your Organization's AWS Identity center, e.g. d-9145c20053? - when: "{{ python_package_registry == 'AWS CodeArtifact' or install_aws_ssm_port_forwarding_plugin }}" + when: "{{ python_package_registry == 'AWS CodeArtifact' or install_aws_ssm_port_forwarding_plugin or pull_from_ecr }}" aws_org_home_region: type: str help: What is the home region of the AWS Organization (where all of the central infrastructure is deployed)? default: us-east-1 - when: "{{ python_package_registry == 'AWS CodeArtifact' or install_aws_ssm_port_forwarding_plugin }}" + when: "{{ python_package_registry == 'AWS CodeArtifact' or install_aws_ssm_port_forwarding_plugin or pull_from_ecr }}" aws_central_infrastructure_account_id: type: str help: What's the ID of your Organization's AWS Account containing Central Infrastructure (e.g. CodeArtifact)? - when: "{{ python_package_registry == 'AWS CodeArtifact' }}" + when: "{{ python_package_registry == 'AWS CodeArtifact' or pull_from_ecr }}" default: "000000000000" core_infra_base_access_profile_name: type: str help: What's the AWS Identity Center Profile name for base access to the Central Infrastructure account (i.e. to read from CodeArtifact)? - when: "{{ python_package_registry == 'AWS CodeArtifact' }}" + when: "{{ python_package_registry == 'AWS CodeArtifact' or pull_from_ecr }}" default: CoreInfraBaseAccess diff --git a/extensions/context.py b/extensions/context.py index 9c9bcffb..c01dd319 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -10,65 +10,65 @@ class ContextUpdater(ContextHook): @override def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: - context["uv_version"] = "0.9.17" - context["pnpm_version"] = "10.25.0" - context["pre_commit_version"] = "4.5.0" - context["pyright_version"] = "1.1.407" - context["pytest_version"] = "9.0.2" - context["pytest_randomly_version"] = "4.0.1" - context["pytest_cov_version"] = "7.0.0" - context["copier_version"] = "9.11.0" - context["copier_template_extensions_version"] = "0.3.3" + context["uv_version"] = "0.9.26" + context["pnpm_version"] = "10.28.1" + context["pre_commit_version"] = "4.5.1" + context["pyright_version"] = ">=1.1.408" + context["pytest_version"] = ">=9.0.2" + context["pytest_randomly_version"] = ">=4.0.1" + context["pytest_cov_version"] = ">=7.0.0" + context["ty_version"] = ">=0.0.13" + context["copier_version"] = "==9.11.2" + context["copier_template_extensions_version"] = "==0.3.3" context["sphinx_version"] = "9.0.4" - context["pulumi_version"] = "3.208.0" - context["pulumi_aws_version"] = "7.12.0" - context["pulumi_aws_native_version"] = "1.38.0" - context["pulumi_command_version"] = "1.1.3" - context["pulumi_github_version"] = "6.8.0" - context["pulumi_okta_version"] = "6.1.0" - context["boto3_version"] = "1.41.2" - context["ephemeral_pulumi_deploy_version"] = "0.0.5" - context["pydantic_version"] = "2.12.5" - context["pyinstaller_version"] = "6.17.0" + context["pulumi_version"] = ">=3.214.1" + context["pulumi_aws_version"] = ">=7.15.0" + context["pulumi_aws_native_version"] = ">=1.47.0" + context["pulumi_command_version"] = ">=1.1.3" + context["pulumi_github_version"] = ">=6.10.0" + context["pulumi_okta_version"] = ">=6.2.0" + context["boto3_version"] = ">=1.42.11" + context["ephemeral_pulumi_deploy_version"] = ">=0.0.6" + context["pydantic_version"] = ">=2.12.5" + context["pyinstaller_version"] = ">=6.17.0" context["setuptools_version"] = "80.7.1" - context["strawberry_graphql_version"] = ">=0.287.0" - context["fastapi_version"] = ">=0.124.2" + context["strawberry_graphql_version"] = ">=0.289.2" + context["fastapi_version"] = ">=0.128.0" context["fastapi_offline_version"] = ">=1.7.4" - context["uvicorn_version"] = ">=0.38.0" - context["lab_auto_pulumi_version"] = "0.1.17" + context["uvicorn_version"] = ">=0.40.0" + context["lab_auto_pulumi_version"] = ">=0.1.18" context["ariadne_codegen_version"] = ">=0.17.0" - context["pytest_mock_version"] = "3.15.1" - context["uuid_utils_version"] = ">=0.12.0" + context["pytest_mock_version"] = ">=3.15.1" + context["uuid_utils_version"] = ">=0.14.0" context["syrupy_version"] = ">=5.0.0" context["structlog_version"] = ">=25.5.0" context["httpx_version"] = "0.28.1" - context["python_kiota_bundle_version"] = ">=1.9.7" - context["vcrpy_version"] = ">=8.1.0" + context["python_kiota_bundle_version"] = ">=1.9.8" + context["vcrpy_version"] = ">=8.1.1" context["pytest_recording_version"] = ">=0.13.4" context["pytest_asyncio_version"] = ">=1.3.0" + context["pytest_reserial_version"] = ">=0.6.0" - context["node_version"] = "24.11.1" - context["nuxt_ui_version"] = "^4.2.1" + context["default_node_version"] = "24.11.1" + context["nuxt_ui_version"] = "^4.3.0" context["nuxt_version"] = "^4.2.2" - context["nuxt_icon_version"] = "^2.1.0" + context["nuxt_icon_version"] = "^2.1.1" context["typescript_version"] = "^5.9.3" context["playwright_version"] = "^1.57.0" - context["vue_version"] = "^3.5.25" - context["vue_tsc_version"] = "^3.1.2" + context["vue_version"] = "^3.5.26" + context["vue_tsc_version"] = "^3.2.1" context["vue_devtools_api_version"] = "^8.0.0" - context["vue_router_version"] = "^4.6.0" + context["vue_router_version"] = "^4.6.4" context["dotenv_cli_version"] = "^11.0.0" - context["faker_version"] = "^10.1.0" + context["faker_version"] = "^10.2.0" context["vitest_version"] = "^3.2.4" context["eslint_version"] = "~9.38.0" - context["nuxt_eslint_version"] = "^1.10.0" - context["zod_version"] = "^4.1.12" + context["nuxt_eslint_version"] = "^1.12.1" + context["zod_version"] = "^4.3.5" context["zod_from_json_schema_version"] = "^0.5.1" - context["types_node_version"] = "^25.0.0" context["nuxt_apollo_version"] = "5.0.0-alpha.15" - context["graphql_codegen_cli_version"] = "^6.0.0" - context["graphql_codegen_typescript_version"] = "^5.0.0" - context["graphql_codegen_typescript_operations_version"] = "^5.0.0" + context["graphql_codegen_cli_version"] = "^6.1.0" + context["graphql_codegen_typescript_version"] = "^5.0.7" context["graphql_tools_mock_version"] = "^9.1.0" context["tailwindcss_version"] = "^4.1.11" context["iconify_vue_version"] = "^5.0.0" @@ -78,21 +78,21 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["vue_test_utils_version"] = "^2.4.6" context["nuxt_test_utils_version"] = "3.19.1" context["vue_eslint_parser_version"] = "^10.1.3" - context["happy_dom_version"] = "^20.0.2" + context["happy_dom_version"] = "^20.0.11" context["node_kiota_bundle_version"] = "1.0.0-preview.99" context["gha_checkout"] = "v6.0.1" - context["gha_setup_python"] = "v6.1.0" - context["gha_cache"] = "v4.3.0" - context["gha_upload_artifact"] = "v5.0.0" - context["gha_download_artifact"] = "v6.0.0" + context["gha_setup_python"] = "v6.2.0" + context["gha_cache"] = "v5.0.2" + context["gha_upload_artifact"] = "v6.0.0" + context["gha_download_artifact"] = "v7.0.0" context["gha_github_script"] = "v7.0.1" context["gha_setup_buildx"] = "v3.11.1" context["buildx_version"] = "v0.27.0" context["gha_docker_build_push"] = "v6.18.0" context["gha_configure_aws_credentials"] = "v5.1.1" context["gha_amazon_ecr_login"] = "v2.0.1" - context["gha_setup_node"] = "v6.1.0" + context["gha_setup_node"] = "v6.2.0" context["gha_action_gh_release"] = "v2.2.1" context["gha_mutex"] = "1ebad517141198e08d47cf72f3c0975316620a65 # v1.0.0-alpha.10" context["gha_pypi_publish"] = "v1.13.0" @@ -104,7 +104,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["gha_long_timeout_minutes"] = "15" context["gha_xlong_timeout_minutes"] = "45" - context["debian_release_name"] = "bookworm" + context["debian_release_name"] = "trixie" context["alpine_image_version"] = "3.23" context["nginx_image_version"] = "1.29.4" diff --git a/pyproject.toml b/pyproject.toml index 1866b074..85362486 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,15 +5,15 @@ description = "Copier template for creating Python libraries and executables" readme = "README.md" requires-python = ">=3.12.7" dependencies = [ + # Specific to this template + + # Managed by upstream template "pytest>=9.0.2", "pytest-cov>=7.0.0", "pytest-randomly>=4.0.1", - "pyright[nodejs]>=1.1.407", - "copier>=9.11.0", - "copier-template-extensions>=0.3.3" - - # Specific to this template - - + "pyright[nodejs]>=1.1.408", + "ty>=0.0.13", + "copier==9.11.2", + "copier-template-extensions==0.3.3" ] diff --git a/template/.coderabbit.yaml b/template/.coderabbit.yaml index 213afdd5..9904260d 100644 --- a/template/.coderabbit.yaml +++ b/template/.coderabbit.yaml @@ -1,9 +1,12 @@ # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +early_access: true reviews: profile: assertive path_instructions: - path: "**/vendor_files/**" instructions: "These files came from a vendor and we're not allowed to change them. Refer to it if you need to understand how the main code interacts with it, but do not make comments about it." + - path: "**/*.py" + instructions: "Do not express concerns about assert statements being removed by using the -O python flag; we never use that flag. Do not express concerns about ruff rules; a pre-commit hook already runs a ruff check. Do not warn about unnecessary super().init() calls; pyright prefers those to be present." tools: eslint: # when the code contains typescript, eslint will be run by pre-commit, and coderabbit often generates false positives enabled: false @@ -14,6 +17,7 @@ reviews: flake8: # we use ruff instead (when we use Python) enabled: false poem: false + in_progress_fortune: false # the commit status is driven by our repository config and required checks, we don't want CodeRabbit messing with it commit_status: false auto_review: diff --git a/template/.devcontainer/Dockerfile b/template/.devcontainer/Dockerfile index 955146c0..70842f4a 100644 --- a/template/.devcontainer/Dockerfile +++ b/template/.devcontainer/Dockerfile @@ -1,19 +1,22 @@ # base image tags available at https://mcr.microsoft.com/v2/devcontainers/universal/tags/list # added the platform flag to override any local settings since this image is only compatible with linux/amd64. since this image is only x64 compatible, suppressing the hadolint rule # hadolint ignore=DL3029 -FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:2.13.1-focal +FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.1-noble SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# temporary hack until yarn updates its GPG key +RUN rm /etc/apt/sources.list.d/yarn.list || true + RUN apt-get update -y && apt-get install -y \ - "bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.10' | head -n 1)" --no-install-recommends \ + "bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.11' | head -n 1)" --no-install-recommends \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Create the venv folder and set permissions for anyone to modify---this is necessary to be able to break out the venv folder as a separate docker volume for better performance on Windows hosts ARG REPO_NAME=copier-base-template ENV VENV_PATH=/workspaces/${REPO_NAME}/.venv -RUN mkdir -p /workspace && \ +RUN mkdir -p /workspaces && \ mkdir -p ${VENV_PATH} && \ chmod -R 777 /workspaces ${VENV_PATH} && \ chgrp -R 0 /workspaces ${VENV_PATH} diff --git a/template/.devcontainer/devcontainer.json.jinja b/template/.devcontainer/devcontainer.json.jinja index 12fc0580..7db172da 100644 --- a/template/.devcontainer/devcontainer.json.jinja +++ b/template/.devcontainer/devcontainer.json.jinja @@ -29,32 +29,32 @@ "-AmazonWebServices.aws-toolkit-vscode", // the AWS CLI feature installs this automatically, but it's causing problems in VS Code{% endraw %}{% endif %}{% raw %} // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.16.1", + "coderabbit.coderabbit-vscode@0.16.6", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", "github.copilot@1.388.0", - "github.copilot-chat@0.34.2025112401",{% endraw %}{% if install_claude_cli %}{% raw %} - "anthropic.claude-code@2.0.27",{% endraw %}{% endif %}{% raw %} + "github.copilot-chat@0.36.2026010502",{% endraw %}{% if install_claude_cli %}{% raw %} + "anthropic.claude-code@2.0.75",{% endraw %}{% endif %}{% raw %} // Python - "ms-python.python@2025.17.2025100201", - "ms-python.vscode-pylance@2025.8.3", + "ms-python.python@2025.21.2026010501", + "ms-python.vscode-pylance@2025.10.100", "ms-vscode-remote.remote-containers@0.414.0", - "charliermarsh.ruff@2025.28.0", + "charliermarsh.ruff@2025.32.0", {% endraw %}{% if is_child_of_copier_base_template is not defined and template_uses_vuejs is defined and template_uses_vuejs is sameas(true) %}{% raw %} // VueJS - "vue.volar@3.0.6", - "vitest.explorer@1.16.1", + "vue.volar@3.2.1", + "vitest.explorer@1.36.0", {% endraw %}{% endif %}{% raw %}{% endraw %}{% if is_child_of_copier_base_template is not defined and template_uses_javascript is defined and template_uses_javascript is sameas(true) %}{% raw %} // All javascript - "dbaeumer.vscode-eslint@3.0.19", + "dbaeumer.vscode-eslint@3.0.21", {% endraw %}{% endif %}{% raw %} // Misc file formats - "bierner.markdown-mermaid@1.28.0", + "bierner.markdown-mermaid@1.29.0", "samuelcolvin.jinjahtml@0.20.0", "tamasfe.even-better-toml@0.19.2", "emilast.LogFileHighlighter@3.3.3", - "esbenp.prettier-vscode@11.0.0" + "esbenp.prettier-vscode@11.0.2" ], "settings": { "editor.accessibilitySupport": "off", // turn off sounds diff --git a/template/.devcontainer/install-ci-tooling.py.jinja b/template/.devcontainer/install-ci-tooling.py.jinja index d0e4d0db..fdadcec7 100644 --- a/template/.devcontainer/install-ci-tooling.py.jinja +++ b/template/.devcontainer/install-ci-tooling.py.jinja @@ -76,9 +76,9 @@ def main(): uv_path, "tool", "install", - f"copier=={COPIER_VERSION}", + f"copier{COPIER_VERSION}", "--with", - f"copier-template-extensions=={COPIER_TEMPLATE_EXTENSIONS_VERSION}", + f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", ], check=True, env=uv_env, diff --git a/template/.github/actions/check-skip-duplicates/action.yml b/template/.github/actions/check-skip-duplicates/action.yml new file mode 100644 index 00000000..5638f11b --- /dev/null +++ b/template/.github/actions/check-skip-duplicates/action.yml @@ -0,0 +1,44 @@ +name: Check Skip Duplicates +description: 'Check that will output a variable to allow you to skip duplicate runs. Example: If you have both push and pull_request triggers enabled and you dont want to run 2 jobs for the same commit if a PR is already open you can add this to your jobs to skip that extra execution.' + +outputs: + should-run: + description: 'Flag that determines if this execution should run or not' + value: ${{ steps.check.outputs.should_run }} + +runs: + using: composite + steps: + - name: Check if push has associated open PR + id: check + env: + GH_TOKEN: ${{ github.token }} + REF_NAME: ${{ github.ref_name }} + REPO_NAME: ${{ github.repository }} + EVENT_NAME: ${{ github.event_name }} + shell: bash + run: | + # For non-push events, always run + if [ "$EVENT_NAME" != "push" ]; then + echo "should_run=true" >> $GITHUB_OUTPUT + echo "Event is $EVENT_NAME, will run CI" + exit 0 + fi + + # For push events, check if there's an open PR for this branch + pr_json=$(gh pr list \ + --repo "$REPO_NAME" \ + --head "$REF_NAME" \ + --state open \ + --json number \ + --limit 1) + + pr_number=$(echo "$pr_json" | jq -r '.[0].number // ""') + + if [ -n "$pr_number" ]; then + echo "should_run=false" >> $GITHUB_OUTPUT + echo "Push to branch with open PR #$pr_number detected, skipping (PR event will run CI)" + else + echo "should_run=true" >> $GITHUB_OUTPUT + echo "Push to branch without open PR, will run CI" + fi diff --git a/template/.github/actions/install_deps/action.yml b/template/.github/actions/install_deps/action.yml index 48796359..b212d095 100644 --- a/template/.github/actions/install_deps/action.yml +++ b/template/.github/actions/install_deps/action.yml @@ -58,13 +58,13 @@ runs: - name: Setup python if: ${{ inputs.python-version != 'notUsing' }} - uses: actions/setup-python@v6.1.0 + uses: actions/setup-python@v6.2.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Setup node if: ${{ inputs.node-version != 'notUsing' }} - uses: actions/setup-node@v6.1.0 + uses: actions/setup-node@v6.2.0 with: node-version: ${{ inputs.node-version }} diff --git a/template/.github/actions/update-devcontainer-hash/action.yml b/template/.github/actions/update-devcontainer-hash/action.yml index 4e6d434c..148062b4 100644 --- a/template/.github/actions/update-devcontainer-hash/action.yml +++ b/template/.github/actions/update-devcontainer-hash/action.yml @@ -5,9 +5,6 @@ inputs: description: 'Branch to checkout and update' required: true -permissions: - contents: write - outputs: new-sha: description: 'The SHA of the branch tip after update' diff --git a/template/.github/workflows/pre-commit.yaml b/template/.github/workflows/pre-commit.yaml index 40c0a513..50295750 100644 --- a/template/.github/workflows/pre-commit.yaml +++ b/template/.github/workflows/pre-commit.yaml @@ -59,7 +59,7 @@ jobs: timeout-minutes: 8 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it - name: Cache Pre-commit hooks - uses: actions/cache@v4.3.0 + uses: actions/cache@v5.0.2 env: cache-name: cache-pre-commit-hooks with: diff --git a/template/.pre-commit-config.yaml b/template/.pre-commit-config.yaml index a9e1bbd5..e0dbbb7f 100644 --- a/template/.pre-commit-config.yaml +++ b/template/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: # Reformatting (should generally come before any file format or other checks, because reformatting can change things) - repo: https://github.com/crate-ci/typos - rev: 802d5794ff9cf7b15610c47eca99cd1ab757d8d4 # frozen: v1 + rev: b31d3aa6e8e43e6a9cf7a1d137baf189dec0922b # frozen: v1 hooks: - id: typos exclude: | @@ -195,12 +195,12 @@ repos: - id: check-case-conflict - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 16a6ad2fead09286ee6eb6b0a3fab55655a6c22a # frozen: 0.35.0 + rev: b035497fb64e3f9faa91e833331688cc185891e6 # frozen: 0.36.0 hooks: - id: check-github-workflows - repo: https://github.com/maresb/check-json5 - rev: 893a2b5a0a27c3540bd8fcafe2968ccc05237179 # 1.0 + rev: bd4737432a2175617a9eeaa510ab369cbc1cbd3d # frozen: v1.0.1 hooks: - id: check-json5 files: | @@ -249,7 +249,7 @@ repos: description: Runs hadolint to lint Dockerfiles - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 1a1f58ba4c35362efe8fed2279715a905baee93d # frozen: v0.14.8 + rev: 5ba58aca0bd5bc7c0e1c0fc45af2e88d6a2bde83 # frozen: v0.14.10 hooks: - id: ruff name: ruff-src diff --git a/template/ty.toml b/template/ty.toml new file mode 100644 index 00000000..45ec6841 --- /dev/null +++ b/template/ty.toml @@ -0,0 +1,18 @@ +[src] +exclude = [ + # excludes managed by this repository + + # excludes managed by template + "**/node_modules", + "**/.precommit_cache", + "**/.ruff_cache", + "**/.npm_cache", + "**/.pipx_cache", + "**/__pycache__", + "**/vendor_files", + "**/generated/graphql", + "**/generated/open_api", + "**/.venv", + "**/venv", + "**/copier_template_resources" +] diff --git a/tests/copier_data/data1.yaml b/tests/copier_data/data1.yaml index cc5b46e2..82e0890f 100644 --- a/tests/copier_data/data1.yaml +++ b/tests/copier_data/data1.yaml @@ -5,6 +5,7 @@ is_open_source: true description: Doing amazing things install_claude_cli: false ssh_port_number: 12345 +pull_from_ecr: false use_windows_in_ci: false install_aws_ssm_port_forwarding_plugin: true configure_vcrpy: true diff --git a/tests/copier_data/data2.yaml b/tests/copier_data/data2.yaml index 19e929c0..fbcf50a6 100644 --- a/tests/copier_data/data2.yaml +++ b/tests/copier_data/data2.yaml @@ -5,6 +5,7 @@ is_open_source: false description: Doing crazy things! So many things! install_claude_cli: true ssh_port_number: 54321 +pull_from_ecr: true use_windows_in_ci: true install_aws_ssm_port_forwarding_plugin: false configure_vcrpy: false diff --git a/tests/copier_data/data3.yaml b/tests/copier_data/data3.yaml index 095dfbf7..1387eb4e 100644 --- a/tests/copier_data/data3.yaml +++ b/tests/copier_data/data3.yaml @@ -5,6 +5,7 @@ is_open_source: true description: Doing amazing things install_claude_cli: false ssh_port_number: 12345 +pull_from_ecr: false use_windows_in_ci: false install_aws_ssm_port_forwarding_plugin: false configure_vcrpy: false diff --git a/ty.toml b/ty.toml new file mode 100644 index 00000000..45ec6841 --- /dev/null +++ b/ty.toml @@ -0,0 +1,18 @@ +[src] +exclude = [ + # excludes managed by this repository + + # excludes managed by template + "**/node_modules", + "**/.precommit_cache", + "**/.ruff_cache", + "**/.npm_cache", + "**/.pipx_cache", + "**/__pycache__", + "**/vendor_files", + "**/generated/graphql", + "**/generated/open_api", + "**/.venv", + "**/venv", + "**/copier_template_resources" +] diff --git a/uv.lock b/uv.lock index 9f07ae0a..9630f24c 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,7 @@ wheels = [ [[package]] name = "copier" -version = "9.11.0" +version = "9.11.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, @@ -39,9 +39,9 @@ dependencies = [ { name = "pyyaml" }, { name = "questionary" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/61/226642b1efad2a39008ee5b913cd82a6f22a564b652e8f0645488a27a2e2/copier-9.11.0.tar.gz", hash = "sha256:e73d6989fa140b621a5c571984c46122704086a9caa84a6e07699a5234d297ab", size = 592030, upload-time = "2025-11-20T21:08:01.419Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/ab/dc4349bdde6850cf81e28e72d921b542346d0c96af835493a21ef0c6d512/copier-9.11.2.tar.gz", hash = "sha256:0e27c45db99f68e0e761e4a088d09cc1de78a67be5d32fb8041d466a54cce364", size = 593108, upload-time = "2026-01-20T10:12:23.081Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/ee/657b24e9b2406f572db273e943237c39c86da7d06ac7bc0686cacea1f59d/copier-9.11.0-py3-none-any.whl", hash = "sha256:628adac090f7b333bb64bf5cab03456b99971a77e4d5b2b979e30b8451cbda9d", size = 56432, upload-time = "2025-11-20T21:07:59.618Z" }, + { url = "https://files.pythonhosted.org/packages/07/fe/75192a53862a756e85d775428bac3d4a9c35157deb84a5db09a70a23998c/copier-9.11.2-py3-none-any.whl", hash = "sha256:ae860df9e954e04e8b5d0b79711dceb3b5e0c304490fcae224adb68d56963e5a", size = 56698, upload-time = "2026-01-20T10:12:21.286Z" }, ] [[package]] @@ -55,16 +55,18 @@ dependencies = [ { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-randomly" }, + { name = "ty" }, ] [package.metadata] requires-dist = [ - { name = "copier", specifier = ">=9.11.0" }, - { name = "copier-template-extensions", specifier = ">=0.3.3" }, - { name = "pyright", extras = ["nodejs"], specifier = ">=1.1.407" }, + { name = "copier", specifier = "==9.11.2" }, + { name = "copier-template-extensions", specifier = "==0.3.3" }, + { name = "pyright", extras = ["nodejs"], specifier = ">=1.1.408" }, { name = "pytest", specifier = ">=9.0.2" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-randomly", specifier = ">=4.0.1" }, + { name = "ty", specifier = ">=0.0.13" }, ] [[package]] @@ -384,15 +386,15 @@ wheels = [ [[package]] name = "pyright" -version = "1.1.407" +version = "1.1.408" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" }, + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, ] [package.optional-dependencies] @@ -493,6 +495,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/e7/2dd8f59d1d328773505f78b85405ddb1cfe74126425d076ce72e65540b8b/questionary-2.0.1-py3-none-any.whl", hash = "sha256:8ab9a01d0b91b68444dff7f6652c1e754105533f083cbe27597c8110ecc230a2", size = 34248, upload-time = "2023-09-08T12:19:01.612Z" }, ] +[[package]] +name = "ty" +version = "0.0.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/dc/b607f00916f5a7c52860b84a66dc17bc6988e8445e96b1d6e175a3837397/ty-0.0.13.tar.gz", hash = "sha256:7a1d135a400ca076407ea30012d1f75419634160ed3b9cad96607bf2956b23b3", size = 4999183, upload-time = "2026-01-21T13:21:16.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/df/3632f1918f4c0a33184f107efc5d436ab6da147fd3d3b94b3af6461efbf4/ty-0.0.13-py3-none-linux_armv6l.whl", hash = "sha256:1b2b8e02697c3a94c722957d712a0615bcc317c9b9497be116ef746615d892f2", size = 9993501, upload-time = "2026-01-21T13:21:26.628Z" }, + { url = "https://files.pythonhosted.org/packages/92/87/6a473ced5ac280c6ce5b1627c71a8a695c64481b99aabc798718376a441e/ty-0.0.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f15cdb8e233e2b5adfce673bb21f4c5e8eaf3334842f7eea3c70ac6fda8c1de5", size = 9860986, upload-time = "2026-01-21T13:21:24.425Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9b/d89ae375cf0a7cd9360e1164ce017f8c753759be63b6a11ed4c944abe8c6/ty-0.0.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0819e89ac9f0d8af7a062837ce197f0461fee2fc14fd07e2c368780d3a397b73", size = 9350748, upload-time = "2026-01-21T13:21:28.502Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a6/9ad58518056fab344b20c0bb2c1911936ebe195318e8acc3bc45ac1c6b6b/ty-0.0.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de79f481084b7cc7a202ba0d7a75e10970d10ffa4f025b23f2e6b7324b74886", size = 9849884, upload-time = "2026-01-21T13:21:21.886Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c3/8add69095fa179f523d9e9afcc15a00818af0a37f2b237a9b59bc0046c34/ty-0.0.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4fb2154cff7c6e95d46bfaba283c60642616f20d73e5f96d0c89c269f3e1bcec", size = 9822975, upload-time = "2026-01-21T13:21:14.292Z" }, + { url = "https://files.pythonhosted.org/packages/a4/05/4c0927c68a0a6d43fb02f3f0b6c19c64e3461dc8ed6c404dde0efb8058f7/ty-0.0.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00be58d89337c27968a20d58ca553458608c5b634170e2bec82824c2e4cf4d96", size = 10294045, upload-time = "2026-01-21T13:21:30.505Z" }, + { url = "https://files.pythonhosted.org/packages/b4/86/6dc190838aba967557fe0bfd494c595d00b5081315a98aaf60c0e632aaeb/ty-0.0.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72435eade1fa58c6218abb4340f43a6c3ff856ae2dc5722a247d3a6dd32e9737", size = 10916460, upload-time = "2026-01-21T13:21:07.788Z" }, + { url = "https://files.pythonhosted.org/packages/04/40/9ead96b7c122e1109dfcd11671184c3506996bf6a649306ec427e81d9544/ty-0.0.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77a548742ee8f621d718159e7027c3b555051d096a49bb580249a6c5fc86c271", size = 10597154, upload-time = "2026-01-21T13:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7d/e832a2c081d2be845dc6972d0c7998914d168ccbc0b9c86794419ab7376e/ty-0.0.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da067c57c289b7cf914669704b552b6207c2cc7f50da4118c3e12388642e6b3f", size = 10410710, upload-time = "2026-01-21T13:21:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/31/e3/898be3a96237a32f05c4c29b43594dc3b46e0eedfe8243058e46153b324f/ty-0.0.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d1b50a01fffa140417fca5a24b658fbe0734074a095d5b6f0552484724474343", size = 9826299, upload-time = "2026-01-21T13:21:00.845Z" }, + { url = "https://files.pythonhosted.org/packages/bb/eb/db2d852ce0ed742505ff18ee10d7d252f3acfd6fc60eca7e9c7a0288a6d8/ty-0.0.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f33c46f52e5e9378378eca0d8059f026f3c8073ace02f7f2e8d079ddfe5207e", size = 9831610, upload-time = "2026-01-21T13:21:05.842Z" }, + { url = "https://files.pythonhosted.org/packages/9e/61/149f59c8abaddcbcbb0bd13b89c7741ae1c637823c5cf92ed2c644fcadef/ty-0.0.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:168eda24d9a0b202cf3758c2962cc295878842042b7eca9ed2965259f59ce9f2", size = 9978885, upload-time = "2026-01-21T13:21:10.306Z" }, + { url = "https://files.pythonhosted.org/packages/a0/cd/026d4e4af60a80918a8d73d2c42b8262dd43ab2fa7b28d9743004cb88d57/ty-0.0.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d4917678b95dc8cb399cc459fab568ba8d5f0f33b7a94bf840d9733043c43f29", size = 10506453, upload-time = "2026-01-21T13:20:56.633Z" }, + { url = "https://files.pythonhosted.org/packages/63/06/8932833a4eca2df49c997a29afb26721612de8078ae79074c8fe87e17516/ty-0.0.13-py3-none-win32.whl", hash = "sha256:c1f2ec40daa405508b053e5b8e440fbae5fdb85c69c9ab0ee078f8bc00eeec3d", size = 9433482, upload-time = "2026-01-21T13:20:58.717Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fd/e8d972d1a69df25c2cecb20ea50e49ad5f27a06f55f1f5f399a563e71645/ty-0.0.13-py3-none-win_amd64.whl", hash = "sha256:8b7b1ab9f187affbceff89d51076038363b14113be29bda2ddfa17116de1d476", size = 10319156, upload-time = "2026-01-21T13:21:03.266Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c2/05fdd64ac003a560d4fbd1faa7d9a31d75df8f901675e5bed1ee2ceeff87/ty-0.0.13-py3-none-win_arm64.whl", hash = "sha256:1c9630333497c77bb9bcabba42971b96ee1f36c601dd3dcac66b4134f9fa38f0", size = 9808316, upload-time = "2026-01-21T13:20:54.053Z" }, +] + [[package]] name = "typing-extensions" version = "4.12.2" From 38d0b932ad49d6a7a4e91923adb2a222dc9a1df9 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Sat, 24 Jan 2026 11:47:23 +0000 Subject: [PATCH 2/4] ge --- template/pyproject.toml.jinja | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/template/pyproject.toml.jinja b/template/pyproject.toml.jinja index a6d8bffc..44e0fd72 100644 --- a/template/pyproject.toml.jinja +++ b/template/pyproject.toml.jinja @@ -25,14 +25,14 @@ dev = [ # Managed by upstream template - "pyright>={% endraw %}{{ pyright_version }}{% raw %}", - "pytest>={% endraw %}{{ pytest_version }}{% raw %}", - "pytest-cov>={% endraw %}{{ pytest_cov_version }}{% raw %}", - "pytest-randomly>={% endraw %}{{ pytest_randomly_version }}{% raw %}",{% endraw %}{% if configure_vcrpy %}{% raw %} + "pyright{% endraw %}{{ pyright_version }}{% raw %}", + "pytest{% endraw %}{{ pytest_version }}{% raw %}", + "pytest-cov{% endraw %}{{ pytest_cov_version }}{% raw %}", + "pytest-randomly{% endraw %}{{ pytest_randomly_version }}{% raw %}",{% endraw %}{% if configure_vcrpy %}{% raw %} "pytest-recording{% endraw %}{{ pytest_recording_version }}{% raw %}", "vcrpy{% endraw %}{{ vcrpy_version }}{% raw %}",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if create_docs %}{% raw %} "sphinx=={% endraw %}{{ sphinx_version }}{% raw %}",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if is_frozen_executable %}{% raw %} - "pyinstaller>={% endraw %}{{ pyinstaller_version }}{% raw %}",{% endraw %}{% endif %}{% raw %} + "pyinstaller{% endraw %}{{ pyinstaller_version }}{% raw %}",{% endraw %}{% endif %}{% raw %} ] [tool.setuptools] From bdabdedc4129fa665ee1c5f150648f0aed46cf71 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Sat, 24 Jan 2026 12:02:10 +0000 Subject: [PATCH 3/4] ci --- template/.github/workflows/ci.yaml.jinja | 28 +++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/template/.github/workflows/ci.yaml.jinja b/template/.github/workflows/ci.yaml.jinja index be48ba08..8449ecf2 100644 --- a/template/.github/workflows/ci.yaml.jinja +++ b/template/.github/workflows/ci.yaml.jinja @@ -21,7 +21,8 @@ jobs: contents: write # needed updating dependabot branches lint: - needs: [ get-values ] + needs: + - get-values name: Pre-commit uses: ./.github/workflows/pre-commit.yaml permissions: @@ -31,7 +32,8 @@ jobs: python-version: {% endraw %}{{ python_version }}{% raw %} test: - needs: [ lint ] + needs: + - lint strategy: matrix: os: @@ -79,7 +81,8 @@ jobs: slug: {% endraw %}{{ full_repo_url | replace("https://github.com/", "") }}{% raw %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if is_frozen_executable %}{% raw %} executable: - needs: [ test ] + needs: + - test strategy: matrix: os: @@ -117,7 +120,8 @@ jobs: {% endraw %}{% if create_docs %}{% raw %} build-docs: - needs: [ lint ] + needs: + - lint strategy: matrix: python-version: @@ -152,17 +156,25 @@ jobs: permissions: statuses: write # needed for updating status on Dependabot PRs needs: - - test - - get-values{% endraw %}{% if create_docs %} + - get-values + - test{% endraw %}{% if create_docs %} - build-docs{% endif %}{% if is_frozen_executable %} - executable{% endif %}{% raw %} if: always() timeout-minutes: {% endraw %}{{ gha_short_timeout_minutes }}{% raw %} steps: - name: fail if prior job failure - if: needs.test.result != 'success'{% endraw %}{% if create_docs %} || needs.build-docs.result != 'success'{% endif %}{% if is_frozen_executable %} || needs.executable.result != 'success'{% endif %}{% raw %} run: | - exit 1 + failure_pattern="^(failure|cancelled)$" + + if [[ "${{ needs.get-values.result }}" =~ $failure_pattern ]] ||{% endraw %}{% if create_docs %}{% raw %} + [[ "${{ needs.build-docs.result }}" =~ $failure_pattern ]] ||{% endraw %}{% endif %}{% raw %}{% endraw %}{% if is_frozen_executable %}{% raw %} + [[ "${{ needs.executable.result }}" =~ $failure_pattern ]] ||{% endraw %}{% endif %}{% raw %} + [[ "${{ needs.test.result }}" =~ $failure_pattern ]]; then + echo "❌ One or more jobs failed or were cancelled" + exit 1 + fi + echo "✅ All jobs completed successfully or were skipped" - name: Mark updated Dependabot commit of devcontainer hash as succeeded if: needs.get-values.outputs.dependabot-commit-created == 'true' env: From 03eae7bcdc106cfab26357a8a56fd02f74f3e947 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Sat, 24 Jan 2026 12:10:19 +0000 Subject: [PATCH 4/4] lint --- template/.github/workflows/ci.yaml.jinja | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/template/.github/workflows/ci.yaml.jinja b/template/.github/workflows/ci.yaml.jinja index 8449ecf2..e721260f 100644 --- a/template/.github/workflows/ci.yaml.jinja +++ b/template/.github/workflows/ci.yaml.jinja @@ -157,6 +157,7 @@ jobs: statuses: write # needed for updating status on Dependabot PRs needs: - get-values + - lint - test{% endraw %}{% if create_docs %} - build-docs{% endif %}{% if is_frozen_executable %} - executable{% endif %}{% raw %} @@ -167,7 +168,8 @@ jobs: run: | failure_pattern="^(failure|cancelled)$" - if [[ "${{ needs.get-values.result }}" =~ $failure_pattern ]] ||{% endraw %}{% if create_docs %}{% raw %} + if [[ "${{ needs.get-values.result }}" =~ $failure_pattern ]] || + [[ "${{ needs.lint.result }}" =~ $failure_pattern ]] ||{% endraw %}{% if create_docs %}{% raw %} [[ "${{ needs.build-docs.result }}" =~ $failure_pattern ]] ||{% endraw %}{% endif %}{% raw %}{% endraw %}{% if is_frozen_executable %}{% raw %} [[ "${{ needs.executable.result }}" =~ $failure_pattern ]] ||{% endraw %}{% endif %}{% raw %} [[ "${{ needs.test.result }}" =~ $failure_pattern ]]; then