diff options
| author | godosa <godosa@godosa.eu> | 2026-10-07 07:27:17 +0200 |
|---|---|---|
| committer | godosa <godosa@godosa.eu> | 2026-10-07 07:27:17 +0200 |
| commit | 81d4e80fd5aabe4e80f58e960affa795cf7d34ec (patch) | |
| tree | e98eeac2af6af63aa4287bba1f6d4a3af26b5727 /tests/test_setup.py | |
| download | workflow-81d4e80fd5aabe4e80f58e960affa795cf7d34ec.tar.gz workflow-81d4e80fd5aabe4e80f58e960affa795cf7d34ec.zip | |
workflow: initial public history
Diffstat (limited to 'tests/test_setup.py')
| -rw-r--r-- | tests/test_setup.py | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/tests/test_setup.py b/tests/test_setup.py new file mode 100644 index 0000000..ea44c33 --- /dev/null +++ b/tests/test_setup.py @@ -0,0 +1,164 @@ +import os +import sys +import tempfile +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from wflib import config as C +from test_claims import FOUR, git +from test_cli import TOML, Cli + +SETUP = TOML + 'worktree_setup = ["mkdir -p out && ln -sfn \\"$WF_MAIN/out/data\\" out/data", "echo ran >> log.txt"]\n' + + +class SetupConfigTest(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.root = Path(self.tmp.name).resolve() + + def tearDown(self): + self.tmp.cleanup() + + def load(self, extra): + (self.root / "workflow.toml").write_text('format = 1\ntasks = "T.md"\narchive = "a.md"\n' + extra) + return C.load(self.root) + + def test_default_empty(self): + self.assertEqual(self.load("").worktree_setup, []) + + def test_list_of_commands(self): + self.assertEqual(self.load('worktree_setup = ["a", "b c"]\n').worktree_setup, ["a", "b c"]) + + def test_wrong_type(self): + with self.assertRaisesRegex(C.ConfigError, "'worktree_setup' must be a list of strings"): + self.load('worktree_setup = "a"\n') + + def test_unknown_key_still_errors(self): + with self.assertRaisesRegex(C.ConfigError, "unknown key 'worktree_setp'"): + self.load('worktree_setp = []\n') + + +class GitCli(Cli): + tasks_text = FOUR + toml = SETUP + + def setUp(self): + super().setUp() + git(self.root, "init", "-q", "-b", "master") + (self.root / ".gitignore").write_text(".worktrees/\n.wf/\nout/\n") + git(self.root, "add", "-A") + git(self.root, "commit", "-qm", "init") + + +class WorktreeCli(GitCli): + def setUp(self): + super().setUp() + self.wt = self.root / ".worktrees" / "opus" + git(self.root, "worktree", "add", "-q", str(self.wt), "-b", "opus/t-three") + (self.root / "out" / "data").mkdir(parents=True) + (self.root / "out" / "data" / "x.bin").write_text("main data\n") + + def setup_(self, *args, cwd=None): + return self.wf("setup", *args, project=False, cwd=cwd or self.wt) + + +class SetupCliTest(WorktreeCli): + def test_runs_commands_in_worktree_with_wf_main(self): + code, out, err = self.setup_() + self.assertEqual((code, err), (0, ""), out) + self.assertEqual((self.wt / "out" / "data" / "x.bin").read_text(), "main data\n") + self.assertEqual((self.wt / "log.txt").read_text(), "ran\n") + self.assertFalse((self.root / "log.txt").exists()) + self.assertIn("$ echo ran >> log.txt\n", out) + self.assertTrue(out.endswith("worktree_setup: 2 commands ok in .worktrees/opus\n"), out) + + def test_idempotent_rerun(self): + self.assertEqual(self.setup_()[0], 0) + self.assertEqual(self.setup_()[0], 0) + self.assertEqual((self.wt / "out" / "data" / "x.bin").read_text(), "main data\n") + + def test_from_subfolder_runs_at_worktree_project_root(self): + code, out, err = self.setup_(cwd=self.wt / "docs") + self.assertEqual((code, err), (0, ""), out) + self.assertTrue((self.wt / "log.txt").is_file()) + + def test_nonzero_exit_reported_and_rest_skipped(self): + (self.wt / "workflow.toml").write_text(TOML + 'worktree_setup = ["echo a > a.txt", "exit 3", "echo c > c.txt"]\n') + code, out, err = self.setup_() + self.assertEqual(code, 1, out + err) + self.assertEqual(err, "wf: worktree_setup 'exit 3' failed (exit 3): later commands skipped\n") + self.assertTrue((self.wt / "a.txt").is_file()) + self.assertFalse((self.wt / "c.txt").exists()) + + def test_outside_worktree_fails(self): + code, out, err = self.wf("setup", project=False, cwd=self.root) + self.assertEqual((code, err), (1, "wf: setup runs inside a linked git worktree (lane worktree)\n")) + + def test_none_configured(self): + (self.wt / "workflow.toml").write_text(TOML) + code, out, err = self.setup_() + self.assertEqual((code, out, err), (0, "no worktree_setup in workflow.toml: nothing to do\n", "")) + + +class WorktreeConfigTest(WorktreeCli): + """A lane worktree's own workflow.toml / area file: setup, gate, areas read it; --mark writes it.""" + + def edit_wt_toml(self, extra): + (self.wt / "workflow.toml").write_text(TOML + extra) + + def test_setup_and_gate_read_worktree_toml(self): + self.edit_wt_toml('worktree_setup = ["echo branch > b.txt"]\nquick_gate = ["echo g > g.txt"]\n') + code, out, err = self.setup_() + self.assertEqual((code, err), (0, ""), out) + self.assertEqual((self.wt / "b.txt").read_text(), "branch\n") + self.assertFalse((self.wt / "log.txt").exists()) + code, out, err = self.wf("gate", project=False, cwd=self.wt) + self.assertEqual((code, err), (0, ""), out) + self.assertTrue((self.wt / "g.txt").is_file()) + + def test_books_stay_main_tree(self): + self.edit_wt_toml("") + (self.wt / "TASKS.md").write_text("# other\n") + out = self.ok("show", "t-three", project=False, cwd=self.wt) + self.assertIn("t-three", out) + cfg = C.load_at(self.wt) + self.assertEqual((cfg.root, cfg.local, cfg.tasks), (self.root, self.wt, self.root / "TASKS.md")) + self.assertEqual(cfg.areas_file, self.wt / "CLAUDE.md") + + def test_areas_read_and_mark_worktree_copy(self): + notes = "## Areas\n### Core\n- Code map: `nothing_here`\n" + (self.root / "CLAUDE.md").write_text(notes.replace("Core", "Main")) + (self.wt / "CLAUDE.md").write_text(notes) + self.assertIn("Core: ", self.ok("areas", project=False, cwd=self.wt)) + self.ok("areas", "--mark", "Core", project=False, cwd=self.wt) + self.assertIn("- Checked: ", (self.wt / "CLAUDE.md").read_text()) + self.assertEqual((self.root / "CLAUDE.md").read_text(), notes.replace("Core", "Main")) + self.assertIn("Main: ", self.ok("areas", project=False, cwd=self.root)) + + def test_main_tree_ignores_worktree(self): + self.edit_wt_toml('quick_gate = ["exit 9"]\n') + self.assertIsNone(C.find_local(self.root)) + code, out, err = self.wf("gate", project=False, cwd=self.root) + self.assertEqual((code, out), (0, "no quick_gate in workflow.toml: nothing to do\n")) + + +class SetupHintTest(GitCli): + def env(self, name, pid): + sock = self.root / f"{name}.sock" + sock.write_text("") + return {"CLAUDE_CODE_MESSAGING_SOCKET": str(sock), "CLAUDE_PID": str(pid), "CLAUDE_CODE_SESSION_ID": name} + + def test_multi_session_hint_adds_setup(self): + son, me = self.env("s", os.getppid()), self.env("o", os.getpid()) + self.ok("next", "--lane", "slow", "--as", "sonnet", "--brief", env=son) + out = self.ok("next", "--lane", "fast", "--as", "opus", env=me) + self.assertIn(" git worktree add .worktrees/fast -b fast/<task> master && cd .worktrees/fast && wf setup" + " (wf there writes this TASKS.md)\n", out) + (self.root / ".worktrees" / "fast").mkdir(parents=True) + out = self.ok("next", "--lane", "fast", "--as", "opus", env=me) + self.assertIn(" cd .worktrees/fast && git switch -c fast/<task> master && wf setup" + " (wf there writes this TASKS.md)\n", out) + +if __name__ == "__main__": + unittest.main() |
