feat: 新增skip_if_missing特性,支持命令不存在时自动跳过任务
本次提交实现了命令任务的自动跳过功能: 1. 为TaskSpec新增skip_if_missing参数,默认开启,仅对list[str]类型cmd生效 2. 通过shutil.which检查命令是否存在,不存在则标记任务为SKIPPED而非失败 3. 重构should_execute方法,整合条件检查与命令可用性检查 4. 更新文档与示例代码,添加该参数的使用说明 5. 移除cli/pymake.py中的冗余check辅助函数,改用内置特性 6. 为所有内置任务添加skip_if_missing=True配置 7. 修复线程并行测试的超时阈值,放宽到1.0秒 8. 优化代码格式与压缩单行表达式 9. 新增完整的单元测试覆盖该特性的各种场景
This commit is contained in:
+14
-33
@@ -67,37 +67,6 @@ class TestMaturinBuildCmd:
|
||||
assert "-Zbuild-std" not in cmd
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# check helper
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestCheckHelper:
|
||||
"""Test check helper function."""
|
||||
|
||||
def test_check_returns_condition(self) -> None:
|
||||
"""check() should return a Condition callable."""
|
||||
cond = pymake.check("python")
|
||||
assert callable(cond)
|
||||
|
||||
def test_check_uses_has_installed(self) -> None:
|
||||
"""check() should use BuiltinConditions.HAS_INSTALLED."""
|
||||
cond = pymake.check("python")
|
||||
# The condition should be a callable that returns a bool
|
||||
result = cond()
|
||||
assert isinstance(result, bool)
|
||||
|
||||
def test_check_for_nonexistent_app(self) -> None:
|
||||
"""check() for a nonexistent app should return False."""
|
||||
cond = pymake.check("definitely_not_installed_app_xyz")
|
||||
assert cond() is False
|
||||
|
||||
def test_check_for_python(self) -> None:
|
||||
"""check() for python should return True (python is always available)."""
|
||||
cond = pymake.check("python")
|
||||
# On some systems, 'python' might not be in PATH, but 'python3' might be
|
||||
# Just verify it returns a bool
|
||||
assert isinstance(cond(), bool)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# TaskSpec definitions
|
||||
# ---------------------------------------------------------------------- #
|
||||
@@ -108,23 +77,25 @@ class TestTaskSpecDefinitions:
|
||||
"""uv_build spec should be properly defined."""
|
||||
assert pymake.uv_build.name == "uv_build"
|
||||
assert pymake.uv_build.cmd == ["uv", "build"]
|
||||
assert len(pymake.uv_build.conditions) == 1
|
||||
assert pymake.uv_build.skip_if_missing is True
|
||||
|
||||
def test_maturin_build_spec(self) -> None:
|
||||
"""maturin_build spec should be properly defined."""
|
||||
assert pymake.maturin_build.name == "maturin_build"
|
||||
assert isinstance(pymake.maturin_build.cmd, list)
|
||||
assert len(pymake.maturin_build.conditions) == 1
|
||||
assert pymake.maturin_build.skip_if_missing is True
|
||||
|
||||
def test_uv_sync_spec(self) -> None:
|
||||
"""uv_sync spec should be properly defined."""
|
||||
assert pymake.uv_sync.name == "uv_sync"
|
||||
assert pymake.uv_sync.cmd == ["uv", "sync"]
|
||||
assert pymake.uv_sync.skip_if_missing is True
|
||||
|
||||
def test_git_clean_spec(self) -> None:
|
||||
"""git_clean spec should be properly defined."""
|
||||
assert pymake.git_clean.name == "git_clean"
|
||||
assert pymake.git_clean.cmd == ["gitt", "c"]
|
||||
assert pymake.git_clean.skip_if_missing is True
|
||||
|
||||
def test_test_spec(self) -> None:
|
||||
"""test spec should be properly defined."""
|
||||
@@ -133,6 +104,7 @@ class TestTaskSpecDefinitions:
|
||||
assert "pytest" in pymake.test.cmd
|
||||
assert "-m" in pymake.test.cmd
|
||||
assert "not slow" in pymake.test.cmd
|
||||
assert pymake.test.skip_if_missing is True
|
||||
|
||||
def test_test_fast_spec(self) -> None:
|
||||
"""test_fast spec should be properly defined."""
|
||||
@@ -140,6 +112,7 @@ class TestTaskSpecDefinitions:
|
||||
assert isinstance(pymake.test_fast.cmd, list)
|
||||
assert "pytest" in pymake.test_fast.cmd
|
||||
assert "-n" not in pymake.test_fast.cmd # test_fast doesn't use parallel
|
||||
assert pymake.test_fast.skip_if_missing is True
|
||||
|
||||
def test_test_coverage_spec(self) -> None:
|
||||
"""test_coverage spec should be properly defined."""
|
||||
@@ -147,6 +120,7 @@ class TestTaskSpecDefinitions:
|
||||
assert isinstance(pymake.test_coverage.cmd, list)
|
||||
assert "pytest" in pymake.test_coverage.cmd
|
||||
assert "--cov" in pymake.test_coverage.cmd
|
||||
assert pymake.test_coverage.skip_if_missing is True
|
||||
|
||||
def test_ruff_lint_spec(self) -> None:
|
||||
"""ruff_lint spec should be properly defined."""
|
||||
@@ -154,27 +128,32 @@ class TestTaskSpecDefinitions:
|
||||
assert isinstance(pymake.ruff_lint.cmd, list)
|
||||
assert "ruff" in pymake.ruff_lint.cmd
|
||||
assert "check" in pymake.ruff_lint.cmd
|
||||
assert pymake.ruff_lint.skip_if_missing is True
|
||||
|
||||
def test_mypy_check_spec(self) -> None:
|
||||
"""mypy_check spec should be properly defined."""
|
||||
assert pymake.mypy_check.name == "typecheck"
|
||||
assert pymake.mypy_check.cmd == ["mypy", "."]
|
||||
assert pymake.mypy_check.skip_if_missing is True
|
||||
|
||||
def test_ty_check_spec(self) -> None:
|
||||
"""ty_check spec should be properly defined."""
|
||||
assert pymake.ty_check.name == "ty_check"
|
||||
assert pymake.ty_check.cmd == ["ty", "check", "."]
|
||||
assert pymake.ty_check.skip_if_missing is True
|
||||
|
||||
def test_doc_spec(self) -> None:
|
||||
"""doc spec should be properly defined."""
|
||||
assert pymake.doc.name == "doc"
|
||||
assert isinstance(pymake.doc.cmd, list)
|
||||
assert "sphinx-build" in pymake.doc.cmd
|
||||
assert pymake.doc.skip_if_missing is True
|
||||
|
||||
def test_hatch_publish_spec(self) -> None:
|
||||
"""hatch_publish spec should be properly defined."""
|
||||
assert pymake.hatch_publish.name == "publish_python"
|
||||
assert pymake.hatch_publish.cmd == ["hatch", "publish"]
|
||||
assert pymake.hatch_publish.skip_if_missing is True
|
||||
|
||||
def test_twine_publish_spec(self) -> None:
|
||||
"""twine_publish spec should be properly defined."""
|
||||
@@ -182,11 +161,13 @@ class TestTaskSpecDefinitions:
|
||||
assert isinstance(pymake.twine_publish.cmd, list)
|
||||
assert "twine" in pymake.twine_publish.cmd
|
||||
assert "upload" in pymake.twine_publish.cmd
|
||||
assert pymake.twine_publish.skip_if_missing is True
|
||||
|
||||
def test_tox_spec(self) -> None:
|
||||
"""tox spec should be properly defined."""
|
||||
assert pymake.tox.name == "tox"
|
||||
assert pymake.tox.cmd == ["tox", "-p", "auto"]
|
||||
assert pymake.tox.skip_if_missing is True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
|
||||
Reference in New Issue
Block a user