diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 000000000..dba71e970 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1 @@ +@../AGENTS.md diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 29e580a93..083c17fdf 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -9,10 +9,10 @@ reviews: instructions: "Never express concerns about potential ruff rule violations, even those rules mentioned in other agent instructions; a pre-commit hook already runs a ruff check. Do not warn about unnecessary super().__init__() calls; pyright prefers those to be present. Do not warn about missing type hints; a pre-commit hook already checks for that." - path: "**/.copier-answers.yml" instructions: "Do not comment about the `_commit` value needing to be a clean release tag. A CI job will fail if that is not the case." - - path: ".copier-managed-files.json" + - path: ".config/.copier-managed-files.json" instructions: "This file is auto-generated by copier on every `copier copy` or `copier update`. Do not edit manually and do not request changes to its content." instructions: | - If any changed files are listed in .copier-managed-files.json, add a single summary comment + If any changed files are listed in .config/.copier-managed-files.json, add a single summary comment (not one per file) noting which files are template-managed and that the changes may warrant backporting. The manifest has a "templates" array — each entry has "src" (template URL), optional "parent_src" (its parent template, forming a chain), and "managed_files". If a file diff --git a/.coveragerc b/.config/.coveragerc similarity index 100% rename from .coveragerc rename to .config/.coveragerc diff --git a/.prettierrc b/.config/.prettierrc similarity index 100% rename from .prettierrc rename to .config/.prettierrc diff --git a/_typos.toml b/.config/_typos.toml similarity index 100% rename from _typos.toml rename to .config/_typos.toml diff --git a/pylintrc.toml b/.config/pylintrc.toml similarity index 100% rename from pylintrc.toml rename to .config/pylintrc.toml diff --git a/pyrefly.mutmut.toml b/.config/pyrefly.mutmut.toml similarity index 67% rename from pyrefly.mutmut.toml rename to .config/pyrefly.mutmut.toml index 698d43b3c..977e2d28e 100644 --- a/pyrefly.mutmut.toml +++ b/.config/pyrefly.mutmut.toml @@ -4,7 +4,8 @@ use-ignore-files = false disable-project-excludes-heuristics = true python-platform = "linux" -project-includes = ["mutants/src/**"] +project-includes = ["../mutants/src/**"] project-excludes = [ - "**/generated/**", + # paths are relative to this config file (in .config/), so prefix with ../ to anchor at the repo root + "../**/generated/**", ] diff --git a/pyrefly.toml b/.config/pyrefly.toml similarity index 73% rename from pyrefly.toml rename to .config/pyrefly.toml index a170a4d79..93e412a0b 100644 --- a/pyrefly.toml +++ b/.config/pyrefly.toml @@ -1,19 +1,20 @@ project-excludes = [ + # paths are relative to this config file (in .config/), so prefix with ../ to anchor at the repo root # excludes managed by this repository - "**/template", + "../**/template", # excludes managed by template - "**/vendor_files", - "**/generated", - "**/copier_template_resources", - "**/.claude/plugins", # similar to vendor_files, but these are gitignored and can contain arbitrary code, so exclude from type checking but not mutation testing + "../**/vendor_files", + "../**/generated", + "../**/copier_template_resources", + "../**/.claude/plugins", # similar to vendor_files, but these are gitignored and can contain arbitrary code, so exclude from type checking but not mutation testing ] # without this explicit "project-includes" and "search-path", pyrefly struggles to understand the tests folder project-includes = [ - "src", - "tests" + "../src", + "../tests" ] -search-path = ["."] +search-path = [".."] disable-project-excludes-heuristics = true # with this being enabled by default, pyrefly things the src is excluded because it's an editable local install python-platform = "linux" infer-with-first-use = false # more similar to pyright. must define the empty list type when instantiated diff --git a/ruff-non-src.toml b/.config/ruff-non-src.toml similarity index 100% rename from ruff-non-src.toml rename to .config/ruff-non-src.toml diff --git a/ruff.toml b/.config/ruff.toml similarity index 100% rename from ruff.toml rename to .config/ruff.toml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ca94793fd..6292d5052 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -28,13 +28,13 @@ "-AmazonWebServices.aws-toolkit-vscode", // the AWS CLI feature installs this automatically, but it's causing problems in VS Code // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.20.4", + "coderabbit.coderabbit-vscode@0.20.7", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", - "anthropic.claude-code@2.1.197", + "anthropic.claude-code@2.1.205", // Python "ms-python.python@2026.5.2026052901", - "meta.pyrefly@1.1.1", + "meta.pyrefly@1.1.9001", "ms-vscode-remote.remote-containers@0.414.0", "charliermarsh.ruff@2026.56.0", // Misc file formats @@ -57,7 +57,9 @@ "python.terminal.activateEnvironment": false, // uv manages the environment "ruff.nativeServer": "on", // TODO: see if there's a way to specify different configurations for different folders - "ruff.configuration": "/workspaces/copier-base-template/ruff-non-src.toml", // use the non-src configuration since it's less restrictive and won't show false positives and underline things + "ruff.configuration": "/workspaces/copier-base-template/.config/ruff-non-src.toml", // use the non-src configuration since it's less restrictive and won't show false positives and underline things + "python.pyrefly.configPath": "/workspaces/copier-base-template/.config/pyrefly.toml", + "prettier.configPath": ".config/.prettierrc", "[jsonc][json]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true @@ -68,5 +70,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): f239a981 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 007af1ff # spellchecker:disable-line } diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to .github/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 96% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index 8272cfaba..7f0008176 100644 --- a/CONTRIBUTING.md +++ b/.github/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: @@ -107,7 +107,7 @@ We love hearing new ideas! If you have an idea for a feature: ## 📜 License -By contributing, you agree that your contributions will be licensed under the same license as the project: [LICENSE](./LICENSE). +By contributing, you agree that your contributions will be licensed under the same license as the project: [LICENSE](../LICENSE). --- diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0f5adf6ff..442495503 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -153,7 +153,7 @@ jobs: - name: Confirm instantiated template has copier answers file run: | - if [ ! -f "./new-template/.copier-answers.yml" ]; then + if [ ! -f "./new-template/.config/.copier-answers.yml" ]; then echo "Copier answers file not found in instantiated template location" exit 1 fi @@ -167,6 +167,7 @@ jobs: rm -rf .github # apparently this folder doesn't get removed with the previous command for some reason rm -rf .devcontainer # apparently this folder doesn't get removed with the previous command for some reason rm -rf .claude # apparently this folder doesn't get removed with the previous command for some reason + rm -rf .config # apparently this folder doesn't get removed with the previous command for some reason ls -la - name: Move the instantiated template into the repo root run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index da97ac53f..2c95472b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,6 +45,7 @@ repos: rev: 359573a3ff38f71c93e160f2ace96d118f6ff42e # frozen: v1 hooks: - id: typos + args: [--write-changes, --force-exclude, --config, .config/_typos.toml] exclude: | (?x)^( .*\.min.js| @@ -108,6 +109,7 @@ repos: rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3 hooks: - id: prettier + args: [--config, .config/.prettierrc] # TODO: get template YAML and MD files more in line with prettier expectations so we can start using prettier on those too exclude: | (?x)^( @@ -234,7 +236,7 @@ repos: hooks: - id: ruff name: ruff-src - args: [--fix, --config=./ruff.toml] + args: [--fix, --config=./.config/ruff.toml] files: src/.+\.py$ exclude: | (?x)^( @@ -244,7 +246,7 @@ repos: )$ - id: ruff name: ruff-non-src # tests, scripts and other non-source code - args: [--fix, --config=./ruff-non-src.toml] + args: [--fix, --config=./.config/ruff-non-src.toml] files: ^(?!src/)(?!.+/src/).+\.py$ exclude: | (?x)^( @@ -253,6 +255,7 @@ repos: template/.*| )$ - id: ruff-format + args: [--config=./.config/ruff.toml] exclude: | (?x)^( .*/generated/graphql/.*| @@ -272,7 +275,7 @@ repos: template/.*| )$ args: - - --rcfile=./pylintrc.toml + - --rcfile=./.config/pylintrc.toml verbose: true - repo: local @@ -299,7 +302,7 @@ repos: hooks: - id: pyrefly name: pyrefly - entry: bash -c "uv run pyrefly check" + entry: bash -c "uv run pyrefly check -c ./.config/pyrefly.toml" files: '.+\.py$' exclude: | (?x)^( diff --git a/AGENTS.md b/AGENTS.md index b3157a918..86b00d393 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -170,7 +170,7 @@ For more details, see README.md and docs/QUICKSTART.md. # Copier-Managed Files -Files generated from upstream copier templates are listed in `.copier-managed-files.json` (if present). +Files generated from upstream copier templates are listed in `.config/.copier-managed-files.json` (if present). The manifest has a `templates` array — one entry per template in the chain. Each entry has `src` (the template URL), `managed_files` (files it placed), and optionally `parent_src` (the template that generated it, forming the chain). diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 43c994c2d..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md diff --git a/copier.yaml b/copier.yaml index 8be0dca31..2eddb8c32 100644 --- a/copier.yaml +++ b/copier.yaml @@ -86,7 +86,7 @@ template_publishes_releases: copier_answers_directory: type: str help: What directory within the instantiated template contains the .copier-answers.yml file? Use '.' for the root, or a subdirectory path (e.g. 'frontend'). - default: "." + default: ".config" _tasks: - command: | @@ -115,13 +115,13 @@ _tasks: fi done - command: | - if [ -f ruff.toml ]; then + if [ -f .config/ruff.toml ]; then echo "Updating ruff target-version from python_version..." py_major_minor="$(printf '%s' '{{ python_version }}' | cut -d. -f1,2)" py_tag="py$(printf '%s' "$py_major_minor" | tr -d '.')" - sed -i -E 's/^target-version = "py[0-9]+"/target-version = "'"$py_tag"'"/' ruff.toml + sed -i -E 's/^target-version = "py[0-9]+"/target-version = "'"$py_tag"'"/' .config/ruff.toml else - echo "ruff.toml not found; skipping Ruff target-version update." + echo ".config/ruff.toml not found; skipping Ruff target-version update." fi - command: | python3 '{{ _copier_conf.src_path }}/src/copier_base_template/copier_tasks/copier_provenance.py' \ @@ -131,6 +131,8 @@ _tasks: _min_copier_version: "9.8" +_answers_file: ".config/.copier-answers.yml" + _subdirectory: template _templates_suffix: .jinja-base diff --git a/extensions/context.py b/extensions/context.py index 046f8d865..76367b75c 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -45,9 +45,10 @@ def hook( # noqa: PLR0915 # yes, this is a lot of statements, but it's all just context["strawberry_graphql_version"] = ( "==0.298.0" # problems with strawberry pydantic in later versions...lost the context for exactly why...it was figured out a while ago, but has to do with being able to override resolvers and have the schema still keep the desired nullability ) - context["fastapi_version"] = ">=0.138.2" + context["fastapi_version"] = ">=0.139.0" context["fastapi_offline_version"] = ">=1.7.7" - context["uvicorn_version"] = ">=0.49.0" + context["starlette_version"] = ">=1.3.1" + context["uvicorn_version"] = ">=0.51.0" context["lab_auto_pulumi_version"] = ">=0.2.3" context["ariadne_codegen_version"] = ">=0.18.0" context["pytest_mock_version"] = ">=3.15.1" @@ -62,7 +63,7 @@ def hook( # noqa: PLR0915 # yes, this is a lot of statements, but it's all just context["pytest_asyncio_version"] = ">=1.4.0" context["pytest_timeout_version"] = ">=2.4.0" context["pytest_reserial_version"] = ">=0.6.1" - context["python_faker_version"] = ">=40.23.0" + context["python_faker_version"] = ">=40.28.1" ####### context["nuxt_ui_version"] = "^4.8.1" context["nuxt_version"] = "^4.4.6" diff --git a/pyproject.toml b/pyproject.toml index bfce5ee3d..249bb70b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "pytest>=9.1.1", "pytest-cov>=7.1.0", "pytest-randomly>=4.1.0", - "faker>=40.23.0", + "faker>=40.28.1", "pyright[nodejs]>=1.1.411", "pyrefly>=1.1.1", "mutmut>=3.6.0", @@ -41,7 +41,7 @@ do_not_mutate = [ "*/generated/*" , # do not mutate generated code, this is cr # mutants tree and excludes do_not_mutate files, so every reported type error falls inside a mutant # function and mutmut can attribute it. Without it, pyrefly checks the real source from the mutants/ # cwd and reports errors on non-mutant lines, crashing with "Could not find mutant for type error". -type_check_command = ['uv', 'run', 'pyrefly', 'check', '--output-format=json', '-c', '../pyrefly.mutmut.toml'] +type_check_command = ['uv', 'run', 'pyrefly', 'check', '--output-format=json', '-c', '../.config/pyrefly.mutmut.toml'] do_not_mutate_patterns = [ # disable mutations of all logger.info/debug/... statements 'logger\.\w+', diff --git a/pytest.ini b/pytest.ini index 74b83a9f3..c6e82920e 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,7 +1,7 @@ [pytest] # Settings managed by the base template norecursedirs = node_modules .precommit_cache .npm_cache .pipenv_cache venv .venv .history -addopts = --cov=src --cov-report html --cov-report term-missing:skip-covered --cov-config=./.coveragerc +addopts = --cov=src --cov-report html --cov-report term-missing:skip-covered --cov-config=./.config/.coveragerc log_cli = 1 log_cli_level = INFO diff --git a/src/copier_base_template/copier_tasks/copier_provenance.py b/src/copier_base_template/copier_tasks/copier_provenance.py index 0bbc1c8ca..6847d2ec1 100644 --- a/src/copier_base_template/copier_tasks/copier_provenance.py +++ b/src/copier_base_template/copier_tasks/copier_provenance.py @@ -49,9 +49,19 @@ class CommentFormat: ".node-version": CommentFormat("none", "none"), } +_MANIFEST_RELPATH = Path(".config") / ".copier-managed-files.json" + + +def _find_manifest(base_directory: Path) -> Path: + config_manifest = base_directory / _MANIFEST_RELPATH + if config_manifest.exists(): + return config_manifest + return base_directory / ".copier-managed-files.json" + + _HEADER_BASE = """\ ============== WARNING ============================================================================== -File is managed by a copier template. See .copier-managed-files.json for details. +File is managed by a copier template. See .config/.copier-managed-files.json for details. You are welcome to make changes to this file in your repo if they are custom to your project, but if the change should be shared with other projects, please backport it to the template repo. @@ -65,7 +75,7 @@ def _build_header(template_src: str) -> str: lines: list[str] = list(_HEADER_BASE.split("\n")) # Replace the generic "File is managed" line with two lines: URL line + "See ..." line. lines[1] = f"File is managed by copier template: {template_src}" - lines.insert(2, "See .copier-managed-files.json for details.") + lines.insert(2, "See .config/.copier-managed-files.json for details.") return "\n".join(lines) @@ -225,7 +235,10 @@ def apply_file_markers( def _read_parent_src(src_template_directory: Path) -> str | None: - answers_path = src_template_directory.parent / ".copier-answers.yml" + template_root = src_template_directory.parent + answers_path = template_root / ".config" / ".copier-answers.yml" + if not answers_path.exists(): + answers_path = template_root / ".copier-answers.yml" if not answers_path.exists(): return None text = answers_path.read_text(encoding="utf-8") @@ -240,7 +253,8 @@ def update_manifest( managed_files: list[str], parent_src: str | None = None, ) -> None: - manifest_path = dst_directory / ".copier-managed-files.json" + manifest_path = dst_directory / _MANIFEST_RELPATH + manifest_path.parent.mkdir(parents=True, exist_ok=True) existing: dict[str, Any] = {} if manifest_path.exists(): @@ -269,13 +283,13 @@ def main() -> None: args = parser.parse_args() # header_src drives what URL appears in file headers (empty → generic "managed by a copier template" text). - # manifest_src is the key written to .copier-managed-files.json and is always non-empty. + # manifest_src is the key written to .config/.copier-managed-files.json and is always non-empty. header_src = args.template_src manifest_src = args.template_src or str(args.src_template_dir) ancestor_managed_by_src: dict[str, set[str]] = {} ancestor_parent_by_src: dict[str, str] = {} - ancestor_manifest_path = args.src_template_dir.parent / ".copier-managed-files.json" + ancestor_manifest_path = _find_manifest(args.src_template_dir.parent) if ancestor_manifest_path.exists(): data: dict[str, Any] = json.loads(ancestor_manifest_path.read_text(encoding="utf-8")) # The ancestor manifest may contain paths with a "template/" prefix (from self-stamp diff --git a/src/copier_base_template/openapi/openapi_schema_simplifier.py b/src/copier_base_template/openapi/openapi_schema_simplifier.py index fdecd1bb2..bcca2f04c 100644 --- a/src/copier_base_template/openapi/openapi_schema_simplifier.py +++ b/src/copier_base_template/openapi/openapi_schema_simplifier.py @@ -3,6 +3,20 @@ # This is unit tested in the https://github.com/LabAutomationAndScreening/copier-base-template repo. It is excluded from coverage checks in other repos, so be cautious about making changes downstream as opposed to the copier base template...really it's for parsing OpenAPI schema...so I can't think of a reason you'd need custom changes that are repo-specific that shouldn't be backported to the template +def _merge_typed_members(typed_dicts: list[dict[str, JsonValue]]) -> dict[str, JsonValue] | None: + merged: dict[str, JsonValue] = {} + for typed_member in typed_dicts: + for key, value in typed_member.items(): + if key == "type": + continue + if key not in merged: + merged[key] = value + continue + if merged[key] != value: + return None # branches disagree on this key; a single merged schema would silently drop one value + return merged + + def _collapse_anyof(schema: dict[str, JsonValue]) -> None: any_of = schema.get("anyOf") if not isinstance(any_of, list): @@ -24,9 +38,11 @@ def _collapse_anyof(schema: dict[str, JsonValue]) -> None: return # enum/const apply to every type, so merging them would wrongly reject null and the sibling types typed_dicts.append(member) member_types.append(member_type) + merged = _merge_typed_members(typed_dicts) + if merged is None: + return # branches carry conflicting per-key values; collapsing would be lossy, so leave the union as-is del schema["anyOf"] - for typed_member in typed_dicts: - schema.update({key: value for key, value in typed_member.items() if key != "type"}) + schema.update(merged) schema["type"] = [*member_types, "null"] diff --git a/template/.config/.coveragerc b/template/.config/.coveragerc new file mode 120000 index 000000000..15224beee --- /dev/null +++ b/template/.config/.coveragerc @@ -0,0 +1 @@ +../../.config/.coveragerc \ No newline at end of file diff --git a/template/.config/.prettierrc b/template/.config/.prettierrc new file mode 120000 index 000000000..b7bd64859 --- /dev/null +++ b/template/.config/.prettierrc @@ -0,0 +1 @@ +../../.config/.prettierrc \ No newline at end of file diff --git a/template/.config/_typos.toml b/template/.config/_typos.toml new file mode 120000 index 000000000..8ce792db1 --- /dev/null +++ b/template/.config/_typos.toml @@ -0,0 +1 @@ +../../.config/_typos.toml \ No newline at end of file diff --git a/template/.config/pylintrc.toml b/template/.config/pylintrc.toml new file mode 120000 index 000000000..5265fd8eb --- /dev/null +++ b/template/.config/pylintrc.toml @@ -0,0 +1 @@ +../../.config/pylintrc.toml \ No newline at end of file diff --git a/template/.config/pyrefly.toml b/template/.config/pyrefly.toml new file mode 120000 index 000000000..3791d0a23 --- /dev/null +++ b/template/.config/pyrefly.toml @@ -0,0 +1 @@ +../../.config/pyrefly.toml \ No newline at end of file diff --git a/template/.config/ruff-non-src.toml b/template/.config/ruff-non-src.toml new file mode 120000 index 000000000..1f0fcd63a --- /dev/null +++ b/template/.config/ruff-non-src.toml @@ -0,0 +1 @@ +../../.config/ruff-non-src.toml \ No newline at end of file diff --git a/template/.config/ruff.toml b/template/.config/ruff.toml new file mode 120000 index 000000000..279de52b1 --- /dev/null +++ b/template/.config/ruff.toml @@ -0,0 +1 @@ +../../.config/ruff.toml \ No newline at end of file diff --git a/template/.coveragerc b/template/.coveragerc deleted file mode 120000 index 50785142b..000000000 --- a/template/.coveragerc +++ /dev/null @@ -1 +0,0 @@ -../.coveragerc \ No newline at end of file diff --git a/template/.devcontainer/devcontainer.json.jinja-base b/template/.devcontainer/devcontainer.json.jinja-base index 5df31b919..731d23455 100644 --- a/template/.devcontainer/devcontainer.json.jinja-base +++ b/template/.devcontainer/devcontainer.json.jinja-base @@ -34,14 +34,14 @@ "-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.20.4", + "coderabbit.coderabbit-vscode@0.20.7", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905",{% endraw %}{% if install_claude_cli %}{% raw %} - "anthropic.claude-code@2.1.197",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if (is_child_of_copier_base_template is defined and is_child_of_copier_base_template is sameas(true)) or (is_child_of_copier_base_template is not defined and template_uses_python is defined and template_uses_python is sameas(true)) %}{% raw %} + "anthropic.claude-code@2.1.205",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if (is_child_of_copier_base_template is defined and is_child_of_copier_base_template is sameas(true)) or (is_child_of_copier_base_template is not defined and template_uses_python is defined and template_uses_python is sameas(true)) %}{% raw %} // Python "ms-python.python@2026.5.2026052901", - "meta.pyrefly@1.1.1", + "meta.pyrefly@1.1.9001", "ms-vscode-remote.remote-containers@0.414.0", "charliermarsh.ruff@2026.56.0",{% endraw %}{% endif %}{% raw %} {% 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 %} @@ -72,7 +72,9 @@ "python.terminal.activateEnvironment": false, // uv manages the environment "ruff.nativeServer": "on", // TODO: see if there's a way to specify different configurations for different folders - "ruff.configuration": "/workspaces/{% endraw %}{{ repo_name }}{% raw %}/ruff-non-src.toml", // use the non-src configuration since it's less restrictive and won't show false positives and underline things{% endraw %}{% endif %}{% raw %} + "ruff.configuration": "/workspaces/{% endraw %}{{ repo_name }}{% raw %}/.config/ruff-non-src.toml", // use the non-src configuration since it's less restrictive and won't show false positives and underline things + "python.pyrefly.configPath": "/workspaces/{% endraw %}{{ repo_name }}{% raw %}/.config/pyrefly.toml",{% endraw %}{% endif %}{% raw %} + "prettier.configPath": ".config/.prettierrc", "[jsonc][json][javascript][typescript][graphql][css][scss][html][vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true diff --git a/template/.github/CODE_OF_CONDUCT.md b/template/.github/CODE_OF_CONDUCT.md new file mode 120000 index 000000000..7d5eea0c6 --- /dev/null +++ b/template/.github/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +../../.github/CODE_OF_CONDUCT.md \ No newline at end of file diff --git a/template/.github/CONTRIBUTING.md b/template/.github/CONTRIBUTING.md new file mode 120000 index 000000000..95181235e --- /dev/null +++ b/template/.github/CONTRIBUTING.md @@ -0,0 +1 @@ +../../.github/CONTRIBUTING.md \ No newline at end of file diff --git a/template/.github/workflows/ci.yaml.jinja-base b/template/.github/workflows/ci.yaml.jinja-base index 2cf08a798..2548683c1 100644 --- a/template/.github/workflows/ci.yaml.jinja-base +++ b/template/.github/workflows/ci.yaml.jinja-base @@ -145,6 +145,7 @@ jobs: rm -rf .github # apparently this folder doesn't get removed with the previous command for some reason rm -rf .devcontainer # apparently this folder doesn't get removed with the previous command for some reason rm -rf .claude # apparently this folder doesn't get removed with the previous command for some reason + rm -rf .config # apparently this folder doesn't get removed with the previous command for some reason ls -la - name: Move the instantiated template into the repo root diff --git a/template/.prettierrc b/template/.prettierrc deleted file mode 120000 index 5b5fb8c8b..000000000 --- a/template/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -../.prettierrc \ No newline at end of file diff --git a/template/CODE_OF_CONDUCT.md b/template/CODE_OF_CONDUCT.md deleted file mode 120000 index 0400d5746..000000000 --- a/template/CODE_OF_CONDUCT.md +++ /dev/null @@ -1 +0,0 @@ -../CODE_OF_CONDUCT.md \ No newline at end of file diff --git a/template/CONTRIBUTING.md b/template/CONTRIBUTING.md deleted file mode 120000 index 44fcc6343..000000000 --- a/template/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -../CONTRIBUTING.md \ No newline at end of file diff --git a/template/README.md.jinja-base b/template/README.md.jinja-base index 359a10ede..ebd889029 100644 --- a/template/README.md.jinja-base +++ b/template/README.md.jinja-base @@ -23,4 +23,4 @@ To create a new repository using this template: ## Updating from the template This repository uses a copier template. To pull in the latest updates from the template, use the command: -`copier update --trust --conflict rej --defaults`{% endraw %} +`copier update --answers-file .config/.copier-answers.yml --trust --conflict rej --defaults`{% endraw %} diff --git a/template/_typos.toml b/template/_typos.toml deleted file mode 120000 index 2264b5db8..000000000 --- a/template/_typos.toml +++ /dev/null @@ -1 +0,0 @@ -../_typos.toml \ No newline at end of file diff --git a/template/copier.yml.jinja-base b/template/copier.yml.jinja-base index e95d435e1..c134fcfc6 100644 --- a/template/copier.yml.jinja-base +++ b/template/copier.yml.jinja-base @@ -199,13 +199,13 @@ _tasks: python3 '{{ _copier_conf.src_path }}/src/copier_tasks/ensure_pnpm_minimum_release_age_exclude.py' --patterns "$PNPM_PATTERNS" when: "{{ pnpm_minimum_release_age_exclude }}"{% endraw %}{% endif %}{% raw %} - command: | - if [ -f ruff.toml ]; then + if [ -f .config/ruff.toml ]; then echo "Updating ruff target-version from python_version..." py_major_minor="$(printf '%s' '{{ python_version }}' | cut -d. -f1,2)" py_tag="py$(printf '%s' "$py_major_minor" | tr -d '.')" - sed -i -E 's/^target-version = "py[0-9]+"/target-version = "'"$py_tag"'"/' ruff.toml + sed -i -E 's/^target-version = "py[0-9]+"/target-version = "'"$py_tag"'"/' .config/ruff.toml else - echo "ruff.toml not found; skipping Ruff target-version update." + echo ".config/ruff.toml not found; skipping Ruff target-version update." fi - command: | python3 '{{ _copier_conf.src_path }}/src/copier_tasks/copier_provenance.py' \ @@ -216,6 +216,8 @@ _tasks: # Additional Settings _min_copier_version: "9.8" +_answers_file: "{% endraw %}{{ copier_answers_directory }}{% raw %}/.copier-answers.yml" + _subdirectory: template _templates_suffix: .jinja diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index 109983ea2..f319432ad 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -38,6 +38,7 @@ class ContextUpdater(ContextHook): context["strawberry_graphql_version"] = "{{ strawberry_graphql_version }}" context["fastapi_version"] = "{{ fastapi_version }}" context["fastapi_offline_version"] = "{{ fastapi_offline_version }}" + context["starlette_version"] = "{{ starlette_version }}" context["uvicorn_version"] = "{{ uvicorn_version }}" context["lab_auto_pulumi_version"] = "{{ lab_auto_pulumi_version }}" context["ariadne_codegen_version"] = "{{ ariadne_codegen_version }}" diff --git a/template/pylintrc.toml b/template/pylintrc.toml deleted file mode 120000 index b19da0e8f..000000000 --- a/template/pylintrc.toml +++ /dev/null @@ -1 +0,0 @@ -../pylintrc.toml \ No newline at end of file diff --git a/template/pyrefly.toml b/template/pyrefly.toml deleted file mode 120000 index c99e7d412..000000000 --- a/template/pyrefly.toml +++ /dev/null @@ -1 +0,0 @@ -../pyrefly.toml \ No newline at end of file diff --git a/template/ruff-non-src.toml b/template/ruff-non-src.toml deleted file mode 120000 index df741ebb4..000000000 --- a/template/ruff-non-src.toml +++ /dev/null @@ -1 +0,0 @@ -../ruff-non-src.toml \ No newline at end of file diff --git a/template/ruff.toml b/template/ruff.toml deleted file mode 120000 index 851b505b5..000000000 --- a/template/ruff.toml +++ /dev/null @@ -1 +0,0 @@ -../ruff.toml \ No newline at end of file diff --git a/template/template/.claude/CLAUDE.md b/template/template/.claude/CLAUDE.md new file mode 120000 index 000000000..86a7b102c --- /dev/null +++ b/template/template/.claude/CLAUDE.md @@ -0,0 +1 @@ +../../../.claude/CLAUDE.md \ No newline at end of file diff --git a/template/template/.config/.prettierrc b/template/template/.config/.prettierrc new file mode 120000 index 000000000..b7bd64859 --- /dev/null +++ b/template/template/.config/.prettierrc @@ -0,0 +1 @@ +../../.config/.prettierrc \ No newline at end of file diff --git a/template/template/.config/_typos.toml b/template/template/.config/_typos.toml new file mode 120000 index 000000000..d5b8d0dca --- /dev/null +++ b/template/template/.config/_typos.toml @@ -0,0 +1 @@ +../../../.config/_typos.toml \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}.coveragerc{% endif %} b/template/template/.config/{% if template_uses_python %}.coveragerc{% endif %} new file mode 120000 index 000000000..068ac56bb --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}.coveragerc{% endif %} @@ -0,0 +1 @@ +../../../.config/.coveragerc \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}pylintrc.toml{% endif %} b/template/template/.config/{% if template_uses_python %}pylintrc.toml{% endif %} new file mode 120000 index 000000000..743d8fb64 --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}pylintrc.toml{% endif %} @@ -0,0 +1 @@ +../../../.config/pylintrc.toml \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} b/template/template/.config/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} new file mode 120000 index 000000000..e5b8bb01a --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} @@ -0,0 +1 @@ +../../../.config/pyrefly.mutmut.toml \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}pyrefly.toml{% endif %} b/template/template/.config/{% if template_uses_python %}pyrefly.toml{% endif %} new file mode 120000 index 000000000..afe96477d --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}pyrefly.toml{% endif %} @@ -0,0 +1 @@ +../../../.config/pyrefly.toml \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}ruff-non-src.toml{% endif %} b/template/template/.config/{% if template_uses_python %}ruff-non-src.toml{% endif %} new file mode 120000 index 000000000..b2a8aefe1 --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}ruff-non-src.toml{% endif %} @@ -0,0 +1 @@ +../../../.config/ruff-non-src.toml \ No newline at end of file diff --git a/template/template/.config/{% if template_uses_python %}ruff.toml{% endif %} b/template/template/.config/{% if template_uses_python %}ruff.toml{% endif %} new file mode 120000 index 000000000..8d22cd896 --- /dev/null +++ b/template/template/.config/{% if template_uses_python %}ruff.toml{% endif %} @@ -0,0 +1 @@ +../../../.config/ruff.toml \ No newline at end of file diff --git a/template/template/.github/CONTRIBUTING.md b/template/template/.github/CONTRIBUTING.md new file mode 120000 index 000000000..724d1770d --- /dev/null +++ b/template/template/.github/CONTRIBUTING.md @@ -0,0 +1 @@ +../../../.github/CONTRIBUTING.md \ No newline at end of file diff --git a/template/template/.github/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} b/template/template/.github/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} new file mode 120000 index 000000000..61f306b84 --- /dev/null +++ b/template/template/.github/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} @@ -0,0 +1 @@ +../../../.github/CODE_OF_CONDUCT.md \ No newline at end of file diff --git a/template/template/.prettierrc b/template/template/.prettierrc deleted file mode 120000 index 5b5fb8c8b..000000000 --- a/template/template/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -../.prettierrc \ No newline at end of file diff --git a/template/template/CLAUDE.md b/template/template/CLAUDE.md deleted file mode 120000 index 6100270f8..000000000 --- a/template/template/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -../../CLAUDE.md \ No newline at end of file diff --git a/template/template/CONTRIBUTING.md b/template/template/CONTRIBUTING.md deleted file mode 120000 index f939e75f2..000000000 --- a/template/template/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -../../CONTRIBUTING.md \ No newline at end of file diff --git a/template/template/_typos.toml b/template/template/_typos.toml deleted file mode 120000 index 15e4306a8..000000000 --- a/template/template/_typos.toml +++ /dev/null @@ -1 +0,0 @@ -../../_typos.toml \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}.coveragerc{% endif %} b/template/template/{% if template_uses_python %}.coveragerc{% endif %} deleted file mode 120000 index ae7ed41e9..000000000 --- a/template/template/{% if template_uses_python %}.coveragerc{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../.coveragerc \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}pylintrc.toml{% endif %} b/template/template/{% if template_uses_python %}pylintrc.toml{% endif %} deleted file mode 120000 index 0d434ddfd..000000000 --- a/template/template/{% if template_uses_python %}pylintrc.toml{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../pylintrc.toml \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} b/template/template/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} deleted file mode 120000 index 69658ec0f..000000000 --- a/template/template/{% if template_uses_python %}pyrefly.mutmut.toml{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../pyrefly.mutmut.toml \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}pyrefly.toml{% endif %} b/template/template/{% if template_uses_python %}pyrefly.toml{% endif %} deleted file mode 120000 index 0653122e2..000000000 --- a/template/template/{% if template_uses_python %}pyrefly.toml{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../pyrefly.toml \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}ruff-non-src.toml{% endif %} b/template/template/{% if template_uses_python %}ruff-non-src.toml{% endif %} deleted file mode 120000 index f8a8f3e15..000000000 --- a/template/template/{% if template_uses_python %}ruff-non-src.toml{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../ruff-non-src.toml \ No newline at end of file diff --git a/template/template/{% if template_uses_python %}ruff.toml{% endif %} b/template/template/{% if template_uses_python %}ruff.toml{% endif %} deleted file mode 120000 index e768b4aa2..000000000 --- a/template/template/{% if template_uses_python %}ruff.toml{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../../ruff.toml \ No newline at end of file diff --git a/template/template/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} b/template/template/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} deleted file mode 120000 index a3613c99f..000000000 --- a/template/template/{% raw %}{% if is_open_source %}CODE_OF_CONDUCT.md{% endif %}{% endraw %} +++ /dev/null @@ -1 +0,0 @@ -../../CODE_OF_CONDUCT.md \ No newline at end of file diff --git a/template/{% if install_claude_cli %}CLAUDE.md{% endif %} b/template/{% if install_claude_cli %}CLAUDE.md{% endif %} deleted file mode 120000 index 949a29f15..000000000 --- a/template/{% if install_claude_cli %}CLAUDE.md{% endif %} +++ /dev/null @@ -1 +0,0 @@ -../CLAUDE.md \ No newline at end of file diff --git a/tests/unit/copier_tasks/test_copier_provenance.py b/tests/unit/copier_tasks/test_copier_provenance.py index 274196b19..d183fef53 100644 --- a/tests/unit/copier_tasks/test_copier_provenance.py +++ b/tests/unit/copier_tasks/test_copier_provenance.py @@ -12,7 +12,7 @@ expected_hash_comment = """\ # ============== WARNING ============================================================================== -# File is managed by a copier template. See .copier-managed-files.json for details. +# File is managed by a copier template. See .config/.copier-managed-files.json for details. # # You are welcome to make changes to this file in your repo if they are custom to your project, # but if the change should be shared with other projects, please backport it to the template repo. @@ -20,7 +20,7 @@ expected_batch_comment = """\ REM ============== WARNING ============================================================================== -REM File is managed by a copier template. See .copier-managed-files.json for details. +REM File is managed by a copier template. See .config/.copier-managed-files.json for details. REM REM You are welcome to make changes to this file in your repo if they are custom to your project, REM but if the change should be shared with other projects, please backport it to the template repo. @@ -29,7 +29,7 @@ expected_block_comment = """\ /* * ============== WARNING ============================================================================== - * File is managed by a copier template. See .copier-managed-files.json for details. + * File is managed by a copier template. See .config/.copier-managed-files.json for details. * * You are welcome to make changes to this file in your repo if they are custom to your project, * but if the change should be shared with other projects, please backport it to the template repo. @@ -39,7 +39,7 @@ expected_jinja_comment = """\ {# ============== WARNING ============================================================================== - File is managed by a copier template. See .copier-managed-files.json for details. + File is managed by a copier template. See .config/.copier-managed-files.json for details. You are welcome to make changes to this file in your repo if they are custom to your project, but if the change should be shared with other projects, please backport it to the template repo. @@ -49,7 +49,7 @@ expected_markdown_comment = """\