From 6efdf417f100941b9c6e488b82acb6d25203ebff Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 1 Apr 2026 23:54:33 +0000 Subject: [PATCH 1/3] Align Claude command and template knowledge Co-authored-by: buddingengineers12345 --- .claude/commands/ci.md | 1 - template/CLAUDE.md.jinja | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.claude/commands/ci.md b/.claude/commands/ci.md index 417c203..45750cd 100644 --- a/.claude/commands/ci.md +++ b/.claude/commands/ci.md @@ -6,7 +6,6 @@ Execute `just ci` which runs in this order: 3. `just lint` — ruff lint check 4. `just type` — basedpyright type check 5. `just test` — pytest -6. `just precommit` — pre-commit on all files After running, summarize: - Which steps passed and which failed diff --git a/template/CLAUDE.md.jinja b/template/CLAUDE.md.jinja index 783d103..2121cdc 100644 --- a/template/CLAUDE.md.jinja +++ b/template/CLAUDE.md.jinja @@ -20,8 +20,7 @@ just precommit-install | Format | `just fmt` | | Type check | `just type` | | Full CI | `just ci` | -{% if include_docs %}| Serve docs | `just docs` | -{% endif %} +{% if include_docs %}| Serve docs | `just docs` |{% endif %} ## Package structure From 683007d123872a71fc94135e9cc3b33a715581ea Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 1 Apr 2026 23:58:55 +0000 Subject: [PATCH 2/3] Make copier tasks uv-first for broader Python installs Co-authored-by: buddingengineers12345 --- README.md | 1 - copier.yml | 4 +--- pyproject.toml | 1 - template/.github/workflows/ci.yml.jinja | 1 - template/.github/workflows/docs.yml.jinja | 1 - template/.github/workflows/lint.yml.jinja | 1 - template/README.md.jinja | 1 - template/mkdocs.yml.jinja | 1 - tests/test_template.py | 4 +++- 9 files changed, 4 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 810c776..86213cb 100644 --- a/README.md +++ b/README.md @@ -58,4 +58,3 @@ This template repository and generated projects are expected to commit a `uv.loc ### Codecov in generated projects The template can wire GitHub Actions to upload coverage. Configure a **repository secret** named `CODECOV_TOKEN` in GitHub (Codecov’s token); you do not need to paste that token into Copier answers. - diff --git a/copier.yml b/copier.yml index 7acd79e..a8fa7e5 100644 --- a/copier.yml +++ b/copier.yml @@ -147,9 +147,7 @@ github_actions_python_versions: # safe; failing tasks should not leave the repository in a broken state. _tasks: - ["git", "init"] - - command: python -m ensurepip --upgrade - - command: python -m pip install --upgrade pip - - command: python -m pip install --upgrade uv + - command: uv self update || true - command: uv lock - command: >- {% if include_docs -%} diff --git a/pyproject.toml b/pyproject.toml index 45e79b1..57efe6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,4 +31,3 @@ ignore = ["E501"] minversion = "8.0" testpaths = ["tests"] addopts = ["-q"] - diff --git a/template/.github/workflows/ci.yml.jinja b/template/.github/workflows/ci.yml.jinja index a0f399f..0cfdfdf 100644 --- a/template/.github/workflows/ci.yml.jinja +++ b/template/.github/workflows/ci.yml.jinja @@ -102,4 +102,3 @@ jobs: exit 1 fi echo "All checks passed!" - diff --git a/template/.github/workflows/docs.yml.jinja b/template/.github/workflows/docs.yml.jinja index a0305a0..129370b 100644 --- a/template/.github/workflows/docs.yml.jinja +++ b/template/.github/workflows/docs.yml.jinja @@ -36,4 +36,3 @@ jobs: with: name: site path: site - diff --git a/template/.github/workflows/lint.yml.jinja b/template/.github/workflows/lint.yml.jinja index 748c7df..35197c7 100644 --- a/template/.github/workflows/lint.yml.jinja +++ b/template/.github/workflows/lint.yml.jinja @@ -29,4 +29,3 @@ jobs: - name: Ruff lint run: uv run ruff check . - diff --git a/template/README.md.jinja b/template/README.md.jinja index b8cba55..eea4e4a 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -35,4 +35,3 @@ just ci ## License {{ license }} - diff --git a/template/mkdocs.yml.jinja b/template/mkdocs.yml.jinja index 5c2ed51..3e9ab19 100644 --- a/template/mkdocs.yml.jinja +++ b/template/mkdocs.yml.jinja @@ -16,4 +16,3 @@ plugins: python: options: docstring_style: google - diff --git a/tests/test_template.py b/tests/test_template.py index e007bcf..149b1bf 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -110,7 +110,9 @@ def test_generate_default_project(temp_project_dir: Path) -> None: assert claude_md.is_file(), "Missing CLAUDE.md" claude_content = claude_md.read_text(encoding="utf-8") assert "Test Project" in claude_content, "CLAUDE.md should include rendered project name" - assert "uv sync --frozen --extra dev" in claude_content, "CLAUDE.md should document uv sync setup" + assert "uv sync --frozen --extra dev" in claude_content, ( + "CLAUDE.md should document uv sync setup" + ) def test_ci_checks_default_project(temp_project_dir: Path) -> None: From 3505abc90b3636d6d65e8097d308a67bf5f06036 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Apr 2026 00:11:19 +0000 Subject: [PATCH 3/3] Bootstrap uv in copier post-generation tasks Co-authored-by: buddingengineers12345 --- copier.yml | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/copier.yml b/copier.yml index a8fa7e5..ebfbe60 100644 --- a/copier.yml +++ b/copier.yml @@ -143,10 +143,53 @@ github_actions_python_versions: # ------------------------------------------------------------------------- # Post-generation tasks # ------------------------------------------------------------------------- -# Commands run after template rendering. Keep tasks idempotent and -# safe; failing tasks should not leave the repository in a broken state. +# Commands run after template rendering. +# +# Notes / rationale: +# - Generated projects are "uv-first" (lock-file-first workflow). These tasks should succeed even +# when the host Python lacks `ensurepip`/`pip` (common on minimal distro Pythons). +# - To avoid template generation failing on machines without `uv`, we bootstrap `uv` first. +# We try `pip` if available; otherwise we fall back to Astral's installer script. +# - Keep tasks idempotent. It's okay if `uv self update` fails (offline / restricted envs). _tasks: - ["git", "init"] + - command: >- + sh -c ' + # Bootstrap `uv` if missing. + # + # Copier executes tasks via /bin/sh, so this must be POSIX-sh compatible. + # We try (in order): + # - existing `uv` on PATH + # - `python -m pip install uv` (if pip is available) + # - Astral install script via curl/wget + if command -v uv >/dev/null 2>&1; then + exit 0 + fi + + if command -v python >/dev/null 2>&1 && python -m pip --version >/dev/null 2>&1; then + python -m pip install --upgrade uv && exit 0 + fi + + if command -v python3 >/dev/null 2>&1 && python3 -m pip --version >/dev/null 2>&1; then + python3 -m pip install --upgrade uv && exit 0 + fi + + if command -v curl >/dev/null 2>&1; then + curl -LsSf https://astral.sh/uv/install.sh | sh || exit 1 + elif command -v wget >/dev/null 2>&1; then + wget -qO- https://astral.sh/uv/install.sh | sh || exit 1 + else + echo "uv is required but was not found, and neither curl nor wget is available to install it." >&2 + exit 1 + fi + + # Astral installer typically drops an env file that prepends ~/.local/bin to PATH. + if [ -f "$HOME/.local/bin/env" ]; then + . "$HOME/.local/bin/env" + fi + + command -v uv >/dev/null 2>&1 + ' - command: uv self update || true - command: uv lock - command: >-