mirror of
https://github.com/rookiestar28/ComfyUI-OpenClaw.git
synced 2026-08-14 00:48:07 +00:00
fix(ci): install coverage toml support
This commit is contained in:
@@ -94,8 +94,10 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
# Keep aligned with local pre-push/full-test scripts.
|
||||
# aiohttp is required by multiple unit-test import paths.
|
||||
# CRITICAL: Python 3.10 coverage reads pyproject.toml only when the
|
||||
# TOML extra is present; do not downgrade this back to plain coverage.
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install numpy pillow aiohttp coverage
|
||||
python -m pip install numpy pillow aiohttp "coverage[toml]"
|
||||
- name: R120 preflight
|
||||
run: |
|
||||
python scripts/preflight_check.py --strict
|
||||
|
||||
@@ -218,9 +218,11 @@ if ! "$VENV_PY" -c "import defusedxml" >/dev/null 2>&1; then
|
||||
echo "[pre-push] INFO: installing defusedxml into project venv ($VENV_DIR) ..." >&2
|
||||
pip_install_or_fail "required for S85 fail-closed XML parsing paths/tests" defusedxml
|
||||
fi
|
||||
if ! "$VENV_PY" -c "import coverage" >/dev/null 2>&1; then
|
||||
echo "[pre-push] INFO: installing coverage into project venv ($VENV_DIR) ..." >&2
|
||||
pip_install_or_fail "required for backend coverage gate" coverage
|
||||
if ! "$VENV_PY" -c "import sys, importlib.util; has_coverage = importlib.util.find_spec('coverage') is not None; has_toml = sys.version_info >= (3, 11) or importlib.util.find_spec('tomli') is not None; sys.exit(0 if has_coverage and has_toml else 1)" >/dev/null 2>&1; then
|
||||
# CRITICAL: Python 3.10 coverage cannot read pyproject.toml without TOML
|
||||
# support; plain coverage here causes local pass/CI fail drift.
|
||||
echo "[pre-push] INFO: installing coverage[toml] into project venv ($VENV_DIR) ..." >&2
|
||||
pip_install_or_fail "required for backend coverage gate" "coverage[toml]"
|
||||
fi
|
||||
|
||||
require_cmd npm
|
||||
|
||||
@@ -89,7 +89,12 @@ def decide_should_publish(
|
||||
|
||||
|
||||
def _write_outputs(
|
||||
*, output_path: Path | None, should_publish: bool, reason: str, current_version: str, previous_version: str | None
|
||||
*,
|
||||
output_path: Path | None,
|
||||
should_publish: bool,
|
||||
reason: str,
|
||||
current_version: str,
|
||||
previous_version: str | None,
|
||||
) -> None:
|
||||
lines = [
|
||||
f"should_publish={'true' if should_publish else 'false'}",
|
||||
|
||||
@@ -7,6 +7,7 @@ coverage-governance reporting.
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -17,6 +18,14 @@ def _run_command(command: list[str]) -> int:
|
||||
return int(completed.returncode)
|
||||
|
||||
|
||||
def _coverage_has_pyproject_toml_support() -> bool:
|
||||
# IMPORTANT: keep this probe in sync with the CI/local bootstrap checks so
|
||||
# Python 3.10 fails fast with a clear remediation instead of a coverage crash.
|
||||
if sys.version_info >= (3, 11):
|
||||
return True
|
||||
return importlib.util.find_spec("tomli") is not None
|
||||
|
||||
|
||||
def _build_unittest_args(args: argparse.Namespace) -> list[str]:
|
||||
command = [
|
||||
sys.executable,
|
||||
@@ -65,6 +74,15 @@ def run_backend_coverage(argv: list[str] | None = None) -> int:
|
||||
coverage_json = Path(args.coverage_json)
|
||||
coverage_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if not _coverage_has_pyproject_toml_support():
|
||||
# CRITICAL: coverage reads repo config from pyproject.toml; Python 3.10
|
||||
# needs the TOML extra or CI/local coverage gates fail before tests run.
|
||||
print(
|
||||
"Coverage pyproject support is unavailable on this interpreter. "
|
||||
"Install with `coverage[toml]` before running the backend coverage gate."
|
||||
)
|
||||
return 2
|
||||
|
||||
erase_cmd = [sys.executable, "-m", "coverage", "erase"]
|
||||
if (code := _run_command(erase_cmd)) != 0:
|
||||
return code
|
||||
|
||||
@@ -183,14 +183,16 @@ if (-not $hasDefusedXml) {
|
||||
Invoke-Checked "pip install defusedxml" { & $venvPython -m pip install defusedxml }
|
||||
}
|
||||
|
||||
$hasCoverage = $true
|
||||
& $venvPython -c "import coverage" | Out-Null
|
||||
$hasCoverageTomlSupport = $true
|
||||
# CRITICAL: keep this aligned with CI/pre-push bootstrap so Python 3.10 lanes
|
||||
# install coverage[toml] before the shared backend coverage gate runs.
|
||||
& $venvPython -c "import sys, importlib.util; has_coverage = importlib.util.find_spec('coverage') is not None; has_toml = sys.version_info >= (3, 11) or importlib.util.find_spec('tomli') is not None; sys.exit(0 if has_coverage and has_toml else 1)" | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$hasCoverage = $false
|
||||
$hasCoverageTomlSupport = $false
|
||||
}
|
||||
if (-not $hasCoverage) {
|
||||
Write-Host "[tests] Installing coverage into project venv (R184 backend coverage gate) ..."
|
||||
Invoke-Checked "pip install coverage" { & $venvPython -m pip install coverage }
|
||||
if (-not $hasCoverageTomlSupport) {
|
||||
Write-Host "[tests] Installing coverage[toml] into project venv (R184 backend coverage gate) ..."
|
||||
Invoke-Checked "pip install coverage[toml]" { & $venvPython -m pip install "coverage[toml]" }
|
||||
}
|
||||
|
||||
# Ensure Node >= 18
|
||||
|
||||
@@ -4,18 +4,13 @@ import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = ROOT / "scripts" / "registry_publish_guard.py"
|
||||
PUBLISH_WORKFLOW = ROOT / ".github" / "workflows" / "publish.yml"
|
||||
|
||||
|
||||
def _pyproject_text(version: str) -> str:
|
||||
return (
|
||||
"[project]\n"
|
||||
'name = "comfyui-openclaw"\n'
|
||||
f'version = "{version}"\n'
|
||||
)
|
||||
return "[project]\n" 'name = "comfyui-openclaw"\n' f'version = "{version}"\n'
|
||||
|
||||
|
||||
class RegistryPublishVersionGuardTests(unittest.TestCase):
|
||||
@@ -23,7 +18,9 @@ class RegistryPublishVersionGuardTests(unittest.TestCase):
|
||||
workflow = PUBLISH_WORKFLOW.read_text(encoding="utf-8")
|
||||
self.assertIn("fetch-depth: 2", workflow)
|
||||
self.assertIn("scripts/registry_publish_guard.py", workflow)
|
||||
self.assertIn("if: steps.publish_guard.outputs.should_publish == 'true'", workflow)
|
||||
self.assertIn(
|
||||
"if: steps.publish_guard.outputs.should_publish == 'true'", workflow
|
||||
)
|
||||
|
||||
def test_same_version_sets_should_publish_false(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class CoverageTomlParityContractTests(unittest.TestCase):
|
||||
def test_ci_unit_test_lane_installs_coverage_with_toml_support(self):
|
||||
ci_workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn(
|
||||
'python -m pip install numpy pillow aiohttp "coverage[toml]"', ci_workflow
|
||||
)
|
||||
self.assertNotIn(
|
||||
"python -m pip install numpy pillow aiohttp coverage\n", ci_workflow
|
||||
)
|
||||
|
||||
def test_local_bootstrap_scripts_install_coverage_with_toml_support(self):
|
||||
pre_push = (ROOT / "scripts" / "pre_push_checks.sh").read_text(encoding="utf-8")
|
||||
windows_full = (ROOT / "scripts" / "run_full_tests_windows.ps1").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'pip_install_or_fail "required for backend coverage gate" "coverage[toml]"',
|
||||
pre_push,
|
||||
)
|
||||
self.assertIn('Invoke-Checked "pip install coverage[toml]"', windows_full)
|
||||
self.assertNotIn(
|
||||
'pip_install_or_fail "required for backend coverage gate" coverage',
|
||||
pre_push,
|
||||
)
|
||||
self.assertNotIn(
|
||||
'Invoke-Checked "pip install coverage" { & $venvPython -m pip install coverage }',
|
||||
windows_full,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,6 +1,7 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -68,6 +69,29 @@ class TestR184BackendCoverageGate(unittest.TestCase):
|
||||
self.assertEqual(result, 1)
|
||||
self.assertEqual(mock_run.call_count, 2)
|
||||
|
||||
@patch("scripts.run_backend_coverage._coverage_has_pyproject_toml_support")
|
||||
@patch("scripts.run_backend_coverage.subprocess.run")
|
||||
def test_missing_toml_support_fails_closed_before_running_coverage(
|
||||
self, mock_run, mock_support
|
||||
):
|
||||
from scripts.run_backend_coverage import run_backend_coverage
|
||||
|
||||
mock_support.return_value = False
|
||||
stdout = StringIO()
|
||||
with patch("sys.stdout", stdout):
|
||||
result = run_backend_coverage(
|
||||
[
|
||||
"--module",
|
||||
"tests.test_r156_quality_governance",
|
||||
"--coverage-json",
|
||||
str(ROOT / ".tmp" / "coverage" / "missing_toml.json"),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(result, 2)
|
||||
self.assertEqual(mock_run.call_count, 0)
|
||||
self.assertIn("coverage[toml]", stdout.getvalue())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user