feat: release Dever 0.1.4 with enforceable project guidance
This commit is contained in:
1 parent
201bdee372
commit
89629c2197
86 files changed
+2798
-338
No files matched your search
@@ -5,6 +5,7 @@ import contextlib
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
@@ -177,6 +178,81 @@ class GateTests(unittest.TestCase):
|
||||
(root / "Cargo.lock").write_text("changed immutable input")
|
||||
self.assertNotEqual(author_before, gate.input_fingerprint({}, config, "author"))
|
||||
|
||||
def test_skill_sources_invalidate_evidence_but_generated_caches_do_not(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
for name in ("Cargo.toml", "Cargo.lock"):
|
||||
(root / name).write_text(name)
|
||||
sources = ("skills/assets/template/AGENTS.md", "skills/references/development.md",
|
||||
"skills/assets/examples/jobs/module/report/archive/app.dever")
|
||||
for name in sources:
|
||||
path = root / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text("original")
|
||||
original = gate.source_fingerprint(root)
|
||||
for name in sources:
|
||||
path = root / name
|
||||
with self.subTest(source=name):
|
||||
path.write_text("changed")
|
||||
self.assertNotEqual(original, gate.source_fingerprint(root))
|
||||
path.unlink()
|
||||
self.assertNotEqual(original, gate.source_fingerprint(root))
|
||||
path.write_text("original")
|
||||
self.assertEqual(original, gate.source_fingerprint(root))
|
||||
for cache in ("__pycache__", "target", ".git"):
|
||||
path = root / "skills/assets/examples/jobs" / cache / "generated"
|
||||
path.parent.mkdir()
|
||||
path.write_text("generated bytes")
|
||||
self.assertEqual(original, gate.source_fingerprint(root))
|
||||
path.write_text("changed generated bytes")
|
||||
self.assertEqual(original, gate.source_fingerprint(root))
|
||||
path.unlink()
|
||||
self.assertEqual(original, gate.source_fingerprint(root))
|
||||
|
||||
def test_python_plan_runs_real_skill_checks_and_rejects_each_failure(self):
|
||||
config = {"tools": {"cargo": sys.executable, "python": sys.executable}}
|
||||
commands = gate.command_plan("python", config)
|
||||
skill_commands = [command for command in commands if "test/skill_examples.py" in command]
|
||||
self.assertEqual(len(skill_commands), 1)
|
||||
command = skill_commands[0]
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
(root / "test").mkdir()
|
||||
shutil.copyfile(gate.ROOT / "test/skill_examples.py", root / "test/skill_examples.py")
|
||||
for name in ("skills", "library"):
|
||||
shutil.copytree(gate.ROOT / name, root / name)
|
||||
logs = root / "logs"
|
||||
logs.mkdir()
|
||||
with patch.object(gate, "ROOT", root):
|
||||
record, content = gate.run_command(command, logs, 0, 10)
|
||||
gate.check_output("python", record, content)
|
||||
test_count = record["python_tests"]
|
||||
self.assertGreater(test_count, 0)
|
||||
for number, (relative, broken, case) in enumerate((
|
||||
("skills/SKILL.md", "[broken](missing.md)",
|
||||
"test_relocated_skill_links_and_release_file_limits"),
|
||||
("skills/references/signatures.md", "```signatures\ndever.io.missing() ()\n```\n",
|
||||
"test_signature_index_matches_public_library_declarations"),
|
||||
("skills/references/language.md",
|
||||
(root / "skills/references/language.md").read_text().replace(
|
||||
'"Hello, "', '"Incorrect tutorial, "', 1
|
||||
),
|
||||
"test_tutorial_code_matches_relocated_checked_sources"),
|
||||
), 1):
|
||||
path = root / relative
|
||||
original = path.read_bytes()
|
||||
path.write_text(broken)
|
||||
with self.subTest(check=case), self.assertRaisesRegex(RuntimeError, "command exited 1"):
|
||||
gate.run_command(command, logs, number, 10)
|
||||
result = json.loads((logs / f"{number:03d}.command.json").read_text())
|
||||
self.assertEqual(result["exit_code"], 1)
|
||||
self.assertEqual(result["python_tests"], test_count)
|
||||
log = (logs / f"{number:03d}.log").read_text()
|
||||
self.assertTrue(
|
||||
f"FAIL: {case}" in log or f"ERROR: {case}" in log, log
|
||||
)
|
||||
path.write_bytes(original)
|
||||
|
||||
def test_cleanup_cannot_delete_author_binary(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
|
||||
Reference in new issue
Block a user