diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 629df4b2..41790bea 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -59,5 +59,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): 627a6cd3 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 77217583 # spellchecker:disable-line } diff --git a/.devcontainer/install-ci-tooling.py b/.devcontainer/install-ci-tooling.py index fc667e64..4a41f88d 100644 --- a/.devcontainer/install-ci-tooling.py +++ b/.devcontainer/install-ci-tooling.py @@ -5,7 +5,7 @@ import subprocess import sys -UV_VERSION = "0.8.22" +UV_VERSION = "0.9.0" COPIER_VERSION = "9.10.2" COPIER_TEMPLATE_EXTENSIONS_VERSION = "0.3.3" PRE_COMMIT_VERSION = "4.3.0" diff --git a/.gitignore b/.gitignore index aa359644..fa36212d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,8 +44,6 @@ pytest.log tests/__coverage__ test/__coverage__ coverage-report-pytest -.pytest_cache/ -.mypy_cache/ .coverage .coverage.* coverage.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 249101a5..ea4376ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -74,6 +74,7 @@ repos: .devcontainer/devcontainer-lock.json| .copier-answers.yml| .*\.xml| + .*\.svg| .*/vendor_files/.*| )$ - id: pretty-format-json @@ -148,6 +149,7 @@ repos: (?x)^( .*/__snapshots__/.*| .*/vendor_files/.*| + .*\.svg| )$ # Invalid File Checks diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd88f1f5..8272cfab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ By participating in this project, you agree to abide by our [Code of Conduct](./ 1. **Fork the repository** on GitHub. 2. **Set up the Dev Container (Recommended Method)** - - Create a Github Codespace (`Code`->`Codespaces` in the Github web console of your cloned repository) OR click on the "Open in Devcontainer" link in the [Readme](./README.md) + - Create a GitHub Codespace (`Code`->`Codespaces` in the GitHub web console of your cloned repository) OR click on the "Open in Devcontainer" link in the [Readme](./README.md) 3. **Make Your Changes** - Create a branch for your feature or bug fix: diff --git a/README.md b/README.md index fe608122..1e285286 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ 1. Inside that devcontainer, run `python .devcontainer/install-ci-tooling.py` to install necessary tooling to instantiate the template (you can copy/paste the script from this repo...and you can paste it in the root of the repo if you want) 1. Delete all files currently in the repository. Optional...but makes it easiest to avoid git conflicts. 1. Run copier to instantiate the template: `copier copy --trust gh:LabAutomationAndScreening/copier-base-template.git .` -1. Run `python .devcontainer/manual-setup-deps.py --only-create-lock` to generate the lock file(s) +1. Run `python .devcontainer/manual-setup-deps.py --only-create-lock --allow-uv-to-install-python` to generate the lock file(s) 1. Stage all files to prepare for commit (`git add .`) 1. Run `python3 .github/workflows/hash_git_files.py . --for-devcontainer-config-update` to update the hash for your devcontainer file 1. Commit the changes (optional) diff --git a/_typos.toml b/_typos.toml index 37a91521..cf8a11d2 100644 --- a/_typos.toml +++ b/_typos.toml @@ -22,5 +22,5 @@ extend-exclude = [ ".copier-answers.yml", # this is an autogenerated file, and sometimes the commit sha gets confused as being a word "**/__snapshots__/**", # Snapshots need to remain static "**/tests/**/cassettes/**/*.yaml", # URLs and other responses in VCR.py generated files should not be altered - "**/vendor_files/**" # if vendors mispell things, there may be other implications in other parts of their code, just leave vendor files alone + "**/vendor_files/**" # if vendors misspell things, there may be other implications in other parts of their code, just leave vendor files alone ] diff --git a/copier.yaml b/copier.yaml index 20ad0c7e..68345691 100644 --- a/copier.yaml +++ b/copier.yaml @@ -16,6 +16,11 @@ description: type: str help: What is this copier template used for? +install_claude_cli: + type: bool + help: Should the Claude CLI be installed in the devcontainer? + default: no + python_version: type: str help: What version of Python? diff --git a/extensions/context.py b/extensions/context.py index 41b4867f..451528a0 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -11,29 +11,29 @@ class ContextUpdater(ContextHook): @override def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: # These are duplicated in the install-ci-tooling.py script in this repository - context["uv_version"] = "0.8.22" + context["uv_version"] = "0.9.0" context["pre_commit_version"] = "4.3.0" # These also in pyproject.toml context["copier_version"] = "9.10.2" context["copier_template_extensions_version"] = "0.3.3" ####### - context["pnpm_version"] = "10.17.1" + context["pnpm_version"] = "10.18.1" # These are duplicated in the pyproject.toml of this repository - context["pyright_version"] = "1.1.405" + context["pyright_version"] = "1.1.406" context["pytest_version"] = "8.4.2" context["pytest_randomly_version"] = "4.0.1" context["pytest_cov_version"] = "7.0.0" ####### context["sphinx_version"] = "8.1.3" context["pulumi_version"] = "3.197.0" - context["pulumi_aws_version"] = "7.7.0" + context["pulumi_aws_version"] = "7.8.0" context["pulumi_aws_native_version"] = "1.33.0" context["pulumi_command_version"] = "1.1.0" context["pulumi_github_version"] = "6.7.3" context["pulumi_okta_version"] = "5.2.0" context["boto3_version"] = "1.40.41" context["ephemeral_pulumi_deploy_version"] = "0.0.5" - context["pydantic_version"] = "2.11.7" + context["pydantic_version"] = "2.12.0" context["pyinstaller_version"] = "6.16.0" context["setuptools_version"] = "80.7.1" context["strawberry_graphql_version"] = "0.282.0" @@ -46,13 +46,13 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["uuid_utils_version"] = "0.11.0" ####### context["node_version"] = "24.7.0" - context["nuxt_ui_version"] = "^4.0.0" + context["nuxt_ui_version"] = "^4.0.1" context["nuxt_version"] = "^4.1.0" context["nuxt_icon_version"] = "^2.0.0" - context["typescript_version"] = "^5.8.2" + context["typescript_version"] = "^5.9.3" context["playwright_version"] = "^1.55.0" context["vue_version"] = "^3.5.21" - context["vue_tsc_version"] = "^3.1.0" + context["vue_tsc_version"] = "^3.1.1" context["vue_devtools_api_version"] = "^8.0.0" context["vue_router_version"] = "^4.5.1" context["dotenv_cli_version"] = "^10.0.0" @@ -73,7 +73,8 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["nuxt_fonts_version"] = "^0.11.4" context["nuxtjs_color_mode_version"] = "^3.5.2" context["vue_test_utils_version"] = "^2.4.6" - context["nuxt_test_utils_version"] = "^3.17.2" + context["nuxt_test_utils_version"] = "3.19.1" + context["vue_eslint_parser_version"] = "^10.1.3" ####### # These are duplicated in the CI files for this repository context["gha_checkout"] = "v5.0.0" diff --git a/pyproject.toml b/pyproject.toml index 847a68c3..9de0d8fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "pytest>=8.4.2", "pytest-cov>=7.0.0", "pytest-randomly>=4.0.1", - "pyright[nodejs]>=1.1.405", + "pyright[nodejs]>=1.1.406", "copier>=9.10.2", "copier-template-extensions>=0.3.3" ] diff --git a/ruff-test.toml b/ruff-test.toml index 9994e410..407ecf89 100644 --- a/ruff-test.toml +++ b/ruff-test.toml @@ -12,7 +12,7 @@ ignore = [ "S101", # assert is definitely needed in test cases "S311", # pseudo-randomness is fine for test cases "TID252", # sometimes you can't use absolute imports in test cases for importing things within the tests, because they're not a true package or have conflicting namespaces - "TRY003", # tests dont need to create a custom exception classes, generally you want to throw an AssertionError with a message anyway + "TRY003", # tests don't need to create custom exception classes, generally you want to throw an AssertionError with a message anyway ] unfixable = [ diff --git a/template/.devcontainer/devcontainer.json.jinja-base b/template/.devcontainer/devcontainer.json.jinja-base index 0be60334..cae3281f 100644 --- a/template/.devcontainer/devcontainer.json.jinja-base +++ b/template/.devcontainer/devcontainer.json.jinja-base @@ -3,10 +3,10 @@ "service": "devcontainer", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "features": { - "ghcr.io/devcontainers/features/aws-cli:1.1.1": { + "ghcr.io/devcontainers/features/aws-cli:1.1.2": { // https://github.com/devcontainers/features/blob/main/src/aws-cli/devcontainer-feature.json // view latest version https://raw.githubusercontent.com/aws/aws-cli/v2/CHANGELOG.rst - "version": "2.27.14" + "version": "2.31.11" }, "ghcr.io/devcontainers/features/python:1.7.1": { // https://github.com/devcontainers/features/blob/main/src/python/devcontainer-feature.json @@ -14,11 +14,12 @@ "installTools": false, "optimize": true }{% 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 %}, - "ghcr.io/devcontainers/features/node:1.6.1": { + "ghcr.io/devcontainers/features/node:1.6.3": { // https://github.com/devcontainers/features/tree/main/src/node "version": "{% endraw %}{{ node_version }}{% raw %}", "pnpmVersion": "{% endraw %}{{ pnpm_version }}{% raw %}" - }{% endraw %}{% endif %}{% raw %} + }{% endraw %}{% endif %}{% raw %}{% endraw %}{% if install_claude_cli %}{% raw %}, + "ghcr.io/anthropics/devcontainer-features/claude-code:1.0.5": {}{% endraw %}{% endif %}{% raw %} }, "customizations": { "vscode": { @@ -28,14 +29,14 @@ "eamodio.gitlens@15.5.1", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", - "github.copilot@1.366.1775", - "github.copilot-chat@0.31.2025090401", + "github.copilot@1.378.1798", + "github.copilot-chat@0.32.2025100703", // Python - "ms-python.python@2025.13.2025090201", - "ms-python.vscode-pylance@2025.7.102", + "ms-python.python@2025.17.2025100201", + "ms-python.vscode-pylance@2025.8.3", "ms-vscode-remote.remote-containers@0.414.0", - "charliermarsh.ruff@2025.24.0", + "charliermarsh.ruff@2025.28.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", @@ -49,7 +50,8 @@ "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.0"{% endraw %}{% if install_claude_cli %}{% raw %}, + "anthropic.claude-code@2.0.10"{% endraw %}{% endif %}{% raw %} ], "settings": { "editor.accessibilitySupport": "off", // turn off sounds diff --git a/template/.devcontainer/docker-compose.yml.jinja-base b/template/.devcontainer/docker-compose.yml.jinja-base index 28dfd1af..17d94259 100644 --- a/template/.devcontainer/docker-compose.yml.jinja-base +++ b/template/.devcontainer/docker-compose.yml.jinja-base @@ -16,7 +16,8 @@ - "{% endraw %}{{ ssh_port_number }}{% raw %}:2222" environment: - AWS_PROFILE=localstack - - AWS_DEFAULT_REGION={% endraw %}{{ aws_region_for_stack if (aws_region_for_stack is defined and aws_region_for_stack != "") else "us-east-1" }}{% raw %} + - AWS_DEFAULT_REGION={% endraw %}{{ aws_region_for_stack if (aws_region_for_stack is defined and aws_region_for_stack != "") else "us-east-1" }}{% raw %}{% endraw %}{% if install_claude_cli %}{% raw %} + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}{% endraw %}{% endif %}{% raw %} volumes: diff --git a/template/.devcontainer/install-ci-tooling.py.jinja-base b/template/.devcontainer/install-ci-tooling.py.jinja-base index 194d1580..0623c0c9 100644 --- a/template/.devcontainer/install-ci-tooling.py.jinja-base +++ b/template/.devcontainer/install-ci-tooling.py.jinja-base @@ -36,13 +36,21 @@ _ = parser.add_argument( default=False, help="Skip installing the SSM plugin for AWS CLI", ) +_ = parser.add_argument( + "--allow-uv-to-install-python", + action="store_true", + default=False, + help="Allow uv to install new versions of Python on the fly. This is typically only needed when instantiating the copier template.", +) def main(): args = parser.parse_args(sys.argv[1:]) is_windows = platform.system() == "Windows" uv_env = dict(os.environ) - uv_env.update({"UV_PYTHON_PREFERENCE": "only-system", "UV_PYTHON": args.python_version}) + uv_env.update({"UV_PYTHON": args.python_version}) + if not args.allow_uv_to_install_python: + uv_env.update({"UV_PYTHON_PREFERENCE": "only-system"}) uv_path = ((GITHUB_WINDOWS_RUNNER_BIN_PATH + "\\") if is_windows else "") + "uv" if is_windows: pwsh = shutil.which("pwsh") or shutil.which("powershell") diff --git a/template/README.md.jinja-base b/template/README.md.jinja-base index c1c5d09c..c46b976b 100644 --- a/template/README.md.jinja-base +++ b/template/README.md.jinja-base @@ -10,7 +10,7 @@ To create a new repository using this template: 1. Inside that devcontainer, run `python .devcontainer/install-ci-tooling.py` to install necessary tooling to instantiate the template (you can copy/paste the script from this repo...and you can paste it in the root of the repo if you want) 1. Delete all files currently in the repository. Optional...but makes it easiest to avoid git conflicts. 1. Run copier to instantiate the template: `copier copy --trust gh:{% endraw %}{{ repo_org_name }}/{{ repo_name }}{% raw %}.git .` -1. Run `python .devcontainer/manual-setup-deps.py --only-create-lock` to generate the lock file(s) +1. Run `python .devcontainer/manual-setup-deps.py --only-create-lock --allow-uv-to-install-python` to generate the lock file(s) 1. Stage all files to prepare for commit (`git add .`) 1. Run `python3 .github/workflows/hash_git_files.py . --for-devcontainer-config-update` to update the hash for your devcontainer file 1. Commit the changes (optional) diff --git a/template/copier.yml.jinja-base b/template/copier.yml.jinja-base index b339d3f6..33e644a2 100644 --- a/template/copier.yml.jinja-base +++ b/template/copier.yml.jinja-base @@ -11,6 +11,11 @@ description: type: str help: What is the description of this repository? +install_claude_cli: + type: bool + help: Should the Claude CLI be installed in the devcontainer? + default: no + is_open_source: type: bool help: Is this library open source? diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index 7d7f3236..5e2e1c28 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -69,6 +69,7 @@ class ContextUpdater(ContextHook): context["nuxtjs_color_mode_version"] = "{{ nuxtjs_color_mode_version }}" context["vue_test_utils_version"] = "{{ vue_test_utils_version }}" context["nuxt_test_utils_version"] = "{{ nuxt_test_utils_version }}" + context["vue_eslint_parser_version"] = "{{ vue_eslint_parser_version }}" context["gha_checkout"] = "{{ gha_checkout }}" context["gha_setup_python"] = "{{ gha_setup_python }}" diff --git a/template/tests/copier_data/data1.yaml.jinja-base b/template/tests/copier_data/data1.yaml.jinja-base index 03f69be4..e363d330 100644 --- a/template/tests/copier_data/data1.yaml.jinja-base +++ b/template/tests/copier_data/data1.yaml.jinja-base @@ -3,6 +3,7 @@ repo_name: the_best_repo repo_org_name: great-company is_open_source: true description: Doing amazing things +install_claude_cli: false ssh_port_number: 12345 use_windows_in_ci: false {% endraw %}{% if template_might_want_to_install_aws_ssm_port_forwarding_plugin %}{% raw %}install_aws_ssm_port_forwarding_plugin: true{% endraw %}{% endif %}{% raw %} diff --git a/template/tests/copier_data/data2.yaml.jinja-base b/template/tests/copier_data/data2.yaml.jinja-base index ca8dd220..aa7f10e0 100644 --- a/template/tests/copier_data/data2.yaml.jinja-base +++ b/template/tests/copier_data/data2.yaml.jinja-base @@ -3,6 +3,7 @@ repo_name: another_repo repo_org_name: initech is_open_source: false description: Doing crazy things! So many things! +install_claude_cli: true ssh_port_number: 54321 use_windows_in_ci: true {% endraw %}{% if template_might_want_to_install_aws_ssm_port_forwarding_plugin %}{% raw %}install_aws_ssm_port_forwarding_plugin: false{% endraw %}{% endif %}{% raw %} diff --git a/tests/copier_data/data1.yaml b/tests/copier_data/data1.yaml index be1986bc..bc5cd650 100644 --- a/tests/copier_data/data1.yaml +++ b/tests/copier_data/data1.yaml @@ -1,5 +1,6 @@ repo_name: the_best_repo description: Doing amazing things +install_claude_cli: true ssh_port_number: 12345 python_ci_versions: - 3.13.2 diff --git a/tests/copier_data/data2.yaml b/tests/copier_data/data2.yaml index f5a2a439..ad33f4ec 100644 --- a/tests/copier_data/data2.yaml +++ b/tests/copier_data/data2.yaml @@ -1,5 +1,6 @@ repo_name: another_repo description: Doing terrible things! +install_claude_cli: false ssh_port_number: 54321 python_ci_versions: - "3.12.7" diff --git a/uv.lock b/uv.lock index d8bcb811..f842dea2 100644 --- a/uv.lock +++ b/uv.lock @@ -61,7 +61,7 @@ dependencies = [ requires-dist = [ { name = "copier", specifier = ">=9.10.2" }, { name = "copier-template-extensions", specifier = ">=0.3.3" }, - { name = "pyright", extras = ["nodejs"], specifier = ">=1.1.405" }, + { name = "pyright", extras = ["nodejs"], specifier = ">=1.1.406" }, { name = "pytest", specifier = ">=8.4.2" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-randomly", specifier = ">=4.0.1" }, @@ -384,15 +384,15 @@ wheels = [ [[package]] name = "pyright" -version = "1.1.405" +version = "1.1.406" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/6c/ba4bbee22e76af700ea593a1d8701e3225080956753bee9750dcc25e2649/pyright-1.1.405.tar.gz", hash = "sha256:5c2a30e1037af27eb463a1cc0b9f6d65fec48478ccf092c1ac28385a15c55763", size = 4068319, upload-time = "2025-09-04T03:37:06.776Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/16/6b4fbdd1fef59a0292cbb99f790b44983e390321eccbc5921b4d161da5d1/pyright-1.1.406.tar.gz", hash = "sha256:c4872bc58c9643dac09e8a2e74d472c62036910b3bd37a32813989ef7576ea2c", size = 4113151, upload-time = "2025-10-02T01:04:45.488Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1a/524f832e1ff1962a22a1accc775ca7b143ba2e9f5924bb6749dce566784a/pyright-1.1.405-py3-none-any.whl", hash = "sha256:a2cb13700b5508ce8e5d4546034cb7ea4aedb60215c6c33f56cec7f53996035a", size = 5905038, upload-time = "2025-09-04T03:37:04.913Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a2/e309afbb459f50507103793aaef85ca4348b66814c86bc73908bdeb66d12/pyright-1.1.406-py3-none-any.whl", hash = "sha256:1d81fb43c2407bf566e97e57abb01c811973fdb21b2df8df59f870f688bdca71", size = 5980982, upload-time = "2025-10-02T01:04:43.137Z" }, ] [package.optional-dependencies]