feat: add all services (dotfiles, packages, bootstrap, remote, containers, projects)

- DotfilesService: package discovery, module sync, link/unlink/status
- PackageService: install/remove/list with PM and binary support
- BootstrapService: profile-based system setup orchestration
- RemoteService: SSH target resolution and connection
- ContainerService: docker container lifecycle management
- ProjectService: git repo status checking

26 service tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 05:02:31 +02:00
parent 5f1ee18cb4
commit f79154d86f
12 changed files with 1312 additions and 3187 deletions

View File

@@ -0,0 +1,67 @@
"""Tests for BootstrapService."""
from pathlib import Path
import pytest
from flow.core.config import AppConfig, FlowContext
from flow.core.console import Console
from flow.core.errors import FlowError
from flow.core.platform import PlatformInfo
from flow.core.runtime import SystemRuntime
from flow.services.bootstrap import BootstrapService
def _make_ctx(manifest=None):
return FlowContext(
config=AppConfig(),
manifest=manifest or {},
platform=PlatformInfo(),
console=Console(color=False),
runtime=SystemRuntime(),
)
class TestBootstrapService:
def test_show_profile(self, capsys):
manifest = {
"profiles": {
"work": {
"os": "linux",
"hostname": "dev",
"packages": ["fd"],
},
},
"packages": [{"name": "fd", "type": "pkg"}],
}
ctx = _make_ctx(manifest)
svc = BootstrapService(ctx)
svc.show("work")
output = capsys.readouterr().out
assert "work" in output
def test_unknown_profile_raises(self):
ctx = _make_ctx({"profiles": {}})
svc = BootstrapService(ctx)
with pytest.raises(FlowError, match="Unknown profile"):
svc.run("missing")
def test_list_profiles(self, capsys):
manifest = {
"profiles": {
"work": {"os": "linux", "hostname": "dev"},
"personal": {"os": "linux"},
},
}
ctx = _make_ctx(manifest)
svc = BootstrapService(ctx)
svc.list_profiles()
output = capsys.readouterr().out
assert "work" in output
assert "personal" in output
def test_list_profiles_empty(self, capsys):
ctx = _make_ctx({})
svc = BootstrapService(ctx)
svc.list_profiles()
assert "No profiles" in capsys.readouterr().out