Coverage for src/workstack/cli/commands/down.py: 92%

25 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-19 09:31 -0400

1from pathlib import Path 

2 

3import click 

4 

5from workstack.cli.commands.switch import ( 

6 _activate_root_repo, 

7 _activate_worktree, 

8 _ensure_graphite_enabled, 

9 _resolve_down_navigation, 

10) 

11from workstack.cli.core import discover_repo_context 

12from workstack.cli.graphite import find_worktree_for_branch 

13from workstack.core.context import WorkstackContext 

14 

15 

16@click.command("down") 

17@click.option( 

18 "--script", is_flag=True, help="Print only the activation script without usage instructions." 

19) 

20@click.pass_obj 

21def down_cmd(ctx: WorkstackContext, script: bool) -> None: 

22 """Move to parent branch in Graphite stack. 

23 

24 With shell integration (recommended): 

25 workstack down 

26 

27 The shell wrapper function automatically activates the worktree. 

28 Run 'workstack init --shell' to set up shell integration. 

29 

30 Without shell integration: 

31 source <(workstack down --script) 

32 

33 This will cd to the parent branch's worktree (or root repo if parent is trunk), 

34 create/activate .venv, and load .env variables. 

35 Requires Graphite to be enabled: 'workstack config set use_graphite true' 

36 """ 

37 _ensure_graphite_enabled(ctx) 

38 repo = discover_repo_context(ctx, Path.cwd()) 

39 

40 # Get current branch 

41 current_branch = ctx.git_ops.get_current_branch(Path.cwd()) 

42 if current_branch is None: 

43 click.echo("Error: Not currently on a branch (detached HEAD)", err=True) 

44 raise SystemExit(1) 

45 

46 # Get all worktrees for checking if target has a worktree 

47 worktrees = ctx.git_ops.list_worktrees(repo.root) 

48 

49 # Resolve navigation to get target branch or 'root' 

50 target_name = _resolve_down_navigation(ctx, repo, current_branch, worktrees) 

51 

52 # Check if target_name refers to 'root' which means root repo 

53 if target_name == "root": 

54 _activate_root_repo(repo, script, "down") 

55 

56 # Resolve target branch to actual worktree path 

57 target_wt_path = find_worktree_for_branch(worktrees, target_name) 

58 if target_wt_path is None: 

59 # This should not happen because _resolve_down_navigation already checks 

60 # But include defensive error handling 

61 click.echo( 

62 f"Error: Branch '{target_name}' has no worktree. This should not happen.", 

63 err=True, 

64 ) 

65 raise SystemExit(1) 

66 

67 _activate_worktree(repo, target_wt_path, script, "down")