From 1ffe82eb6565e66c5dcde3d64edb332625da80ee Mon Sep 17 00:00:00 2001 From: laundry <40748509+laundry2@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:58:00 +0800 Subject: [PATCH] fix(setup): run pre-commit through uv and clarify Node advice (#5767) --- Makefile | 2 +- README.md | 2 ++ README_zh.md | 2 ++ backend/tests/test_check_script.py | 14 +++++++++++++ backend/tests/test_make_install.py | 32 ++++++++++++++++++++++++++++++ scripts/AGENTS.md | 3 +++ scripts/check.py | 9 ++++++--- 7 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 backend/tests/test_make_install.py diff --git a/Makefile b/Makefile index 5d7d0d74a..72ee584e7 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ install: @cd frontend && $(FRONTEND_PNPM) install @echo "Installing pre-commit hooks..." @uv tool install pre-commit - @pre-commit install --overwrite + @uv tool run pre-commit install --overwrite @echo "✓ All dependencies installed" @echo "" @echo "==========================================" diff --git a/README.md b/README.md index 9c03f7c5b..7485b0fe4 100644 --- a/README.md +++ b/README.md @@ -463,6 +463,8 @@ such a checkout, use `bash ./scripts/.sh ...`. make install # Install backend + frontend dependencies + pre-commit hooks ``` + Hook setup calls pre-commit through uv, so uv's tool directory need not be on `PATH`. + 3. **(Optional) Pre-pull sandbox image**: ```bash # Recommended if using Docker/Container-based sandbox diff --git a/README_zh.md b/README_zh.md index 488b41a97..d37f96f91 100644 --- a/README_zh.md +++ b/README_zh.md @@ -303,6 +303,8 @@ make down # 停止并移除容器 make install # 安装 backend + frontend 依赖 ``` + pre-commit 由 uv 调用,不要求其工具目录在 `PATH` 中。 + 3. **(可选)预拉取 sandbox 镜像**: ```bash # 如果使用 Docker / Container sandbox,建议先执行 diff --git a/backend/tests/test_check_script.py b/backend/tests/test_check_script.py index d6f5163c8..6c2a848f8 100644 --- a/backend/tests/test_check_script.py +++ b/backend/tests/test_check_script.py @@ -148,3 +148,17 @@ def test_check_status_labels_corepack_fallback(monkeypatch, capsys): assert check_script.main() == 0 assert "OK pnpm 10.26.2 (via Corepack)" in capsys.readouterr().out + + +def test_old_node_check_suggests_a_version_manager_command(monkeypatch, capsys): + check_script = _load_script(CHECK_SCRIPT_PATH, "deerflow_check_script_old_node") + monkeypatch.setattr(check_script.shutil, "which", lambda name: f"/fake/{name}") + monkeypatch.setattr( + check_script, + "run_command", + lambda command: {"node": "v20.19.5", "uv": "uv 0.9.0", "nginx": "nginx/1.31.3"}[command[0]], + ) + monkeypatch.setattr(check_script, "run_pnpm_version", lambda: ("10.26.2", True, None)) + + assert check_script.main() == 1 + assert "nvm install 22 && nvm use 22" in capsys.readouterr().out diff --git a/backend/tests/test_make_install.py b/backend/tests/test_make_install.py new file mode 100644 index 000000000..ad935f01d --- /dev/null +++ b/backend/tests/test_make_install.py @@ -0,0 +1,32 @@ +"""The root install target invokes uv tools without relying on their PATH.""" + +from __future__ import annotations + +import os +import shutil +import subprocess +import sys +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parents[2] +MAKE = shutil.which("make") + + +@pytest.mark.skipif(MAKE is None or os.name == "nt", reason="requires POSIX make") +def test_make_install_runs_precommit_without_uv_tool_bin_on_path(tmp_path: Path) -> None: + bin_dir = tmp_path / "bin" + bin_dir.mkdir() + tool = bin_dir / "tool" + tool.write_text('#!/bin/sh\nprintf "%s %s\\n" "${0##*/}" "$*" >> "$INSTALL_TRACE"\n', encoding="utf-8") + tool.chmod(0o755) + for name in ("uv", "pnpm"): + (bin_dir / name).symlink_to(tool) + + trace_path = tmp_path / "commands.log" + env = {**os.environ, "PATH": str(bin_dir), "INSTALL_TRACE": str(trace_path)} + result = subprocess.run([MAKE, "install", f"PYTHON={sys.executable}"], cwd=REPO_ROOT, env=env, capture_output=True, text=True, check=False) + + assert result.returncode == 0, result.stdout + result.stderr + assert "uv tool run pre-commit install --overwrite" in trace_path.read_text(encoding="utf-8") diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md index b8180d639..f4f20c6d7 100644 --- a/scripts/AGENTS.md +++ b/scripts/AGENTS.md @@ -15,6 +15,9 @@ synchronized environment with `uv run --no-sync`. Production Compose probes Gateway `/health`, and `deploy.sh` waits for all services before reporting success; failures print Compose status and recent Gateway logs. +Root `make install` runs pre-commit through uv, so uv's tool bin directory +need not be on `PATH`. + ## Shell Script Invocation Contract Root Makefile recipes must invoke repository `.sh` files through diff --git a/scripts/check.py b/scripts/check.py index f6bb4a71e..d82e59631 100644 --- a/scripts/check.py +++ b/scripts/check.py @@ -97,15 +97,18 @@ def main() -> int: print( f" FAIL Node.js {node_version.lstrip('v')} found, but version 22+ is required" ) - print(" Install from: https://nodejs.org/") + print(" With nvm: nvm install 22 && nvm use 22") + print(" Other install methods: https://nodejs.org/en/download") failed = True else: print(" INFO Unable to determine Node.js version") - print(" Install from: https://nodejs.org/") + print(" With nvm: nvm install 22 && nvm use 22") + print(" Other install methods: https://nodejs.org/en/download") failed = True else: print(" FAIL Node.js not found (version 22+ required)") - print(" Install from: https://nodejs.org/") + print(" With nvm: nvm install 22 && nvm use 22") + print(" Other install methods: https://nodejs.org/en/download") failed = True print()