feat: add standard init-db CLI for host install schema ensure
All checks were successful
技能自动化发布 / release (push) Successful in 4s

This commit is contained in:
2026-07-14 17:26:24 +08:00
parent af7a43a702
commit 6b64aad138
11 changed files with 76 additions and 12 deletions

View File

@@ -12,7 +12,7 @@
| 场景 | 放在哪里 | 默认是否运行 | 说明 |
|------|----------|--------------|------|
| CLI / health / version / metadata / runtime 路径 | `tests/test_*.py` | 是 | 默认必跑,保持轻量、无外联 |
| CLI / health / version / init-db / metadata / runtime 路径 | `tests/test_*.py` | 是 | 默认必跑,保持轻量、无外联 |
| 纯函数 / 业务规则 | `tests/test_*.py` | 是 | 不依赖真实外部系统 |
| service 层契约 | 从 `tests/samples/test_service_contract.py.sample` 复制到 `tests/test_service_contract.py` | 是,复制后 | 用 `FakeAdapter` / stub 注入外部依赖 |
| 外源同步契约 | 从 `tests/samples/test_sync_contract.py.sample` 复制 | 是,复制后 | 幂等 / 事务 / 空结果保护 / 不导出文件 |
@@ -35,6 +35,7 @@
- [ ] `python tests/run_tests.py -v` 能通过(含 platform-kit 导入与无 vendored core 守护)。
- [ ] `python scripts/main.py health` 能通过(输出 runtime diagnosticswarning 不导致非零退出)。
- [ ] `python scripts/main.py version` 输出 JSON且 `skill` 与目录名 / `SKILL.md` / `constants.SKILL_SLUG` 一致。
- [ ] `python scripts/main.py init-db` 幂等创建本地库并输出 JSON`ok` / `skill` / `db_path`)。
- [ ] 所有 DB / 文件写入都在 `IsolatedDataRoot`(或等价隔离)下测试,不写真实数据目录。
- [ ] 外部系统默认使用 mock / `FakeAdapter`,不访问真实 API不打开真实 RPA。
- [ ] 至少有 1 个成功路径测试。

View File

@@ -27,6 +27,7 @@ class TestCliSmoke(unittest.TestCase):
out = buf.getvalue()
self.assertIn("通用业务技能模板", out)
self.assertIn("health", out)
self.assertIn("init-db", out)
def test_health_zero(self) -> None:
old_record = os.environ.get("OPENCLAW_RECORD_VIDEO")
@@ -57,6 +58,26 @@ class TestCliSmoke(unittest.TestCase):
self.assertIn("skill", payload)
self.assertEqual(payload["skill"], SKILL_SLUG)
def test_init_db_creates_database_and_is_idempotent(self) -> None:
with IsolatedDataRoot(user_id="_cli_init_db"):
config.reset_cache()
buf = io.StringIO()
with redirect_stdout(buf), redirect_stderr(io.StringIO()):
rc = main(["init-db"])
self.assertEqual(rc, 0)
payload = json.loads(buf.getvalue().strip())
self.assertTrue(payload["ok"])
self.assertEqual(payload["skill"], SKILL_SLUG)
self.assertTrue(os.path.isfile(payload["db_path"]))
buf2 = io.StringIO()
with redirect_stdout(buf2), redirect_stderr(io.StringIO()):
rc2 = main(["init-db"])
self.assertEqual(rc2, 0)
payload2 = json.loads(buf2.getvalue().strip())
self.assertTrue(payload2["ok"])
self.assertEqual(payload2["db_path"], payload["db_path"])
def test_logs_empty_returns_zero(self) -> None:
with IsolatedDataRoot():
buf = io.StringIO()