Coverage for src/workstack/cli/commands/config.py: 89%
132 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-19 09:31 -0400
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-19 09:31 -0400
1from pathlib import Path
3import click
5from workstack.cli.config import LoadedConfig, load_config
6from workstack.cli.core import discover_repo_context, ensure_workstacks_dir
7from workstack.core.context import WorkstackContext
10def _get_env_value(cfg: LoadedConfig, parts: list[str], key: str) -> None:
11 """Handle env.* configuration keys.
13 Prints the value or exits with error if key not found.
14 """
15 if len(parts) != 2:
16 click.echo(f"Invalid key: {key}", err=True)
17 raise SystemExit(1)
19 if parts[1] not in cfg.env:
20 click.echo(f"Key not found: {key}", err=True)
21 raise SystemExit(1)
23 click.echo(cfg.env[parts[1]])
26def _get_post_create_value(cfg: LoadedConfig, parts: list[str], key: str) -> None:
27 """Handle post_create.* configuration keys.
29 Prints the value or exits with error if key not found.
30 """
31 if len(parts) != 2:
32 click.echo(f"Invalid key: {key}", err=True)
33 raise SystemExit(1)
35 # Handle shell subkey
36 if parts[1] == "shell":
37 if not cfg.post_create_shell:
38 click.echo(f"Key not found: {key}", err=True)
39 raise SystemExit(1)
40 click.echo(cfg.post_create_shell)
41 return
43 # Handle commands subkey
44 if parts[1] == "commands":
45 for cmd in cfg.post_create_commands:
46 click.echo(cmd)
47 return
49 # Unknown subkey
50 click.echo(f"Key not found: {key}", err=True)
51 raise SystemExit(1)
54@click.group("config")
55def config_group() -> None:
56 """Manage workstack configuration."""
59@config_group.command("list")
60@click.pass_obj
61def config_list(ctx: WorkstackContext) -> None:
62 """Print a list of configuration keys and values."""
63 # Try to load global config
64 try:
65 workstacks_root = ctx.global_config_ops.get_workstacks_root()
66 use_graphite = ctx.global_config_ops.get_use_graphite()
67 show_pr_info = ctx.global_config_ops.get_show_pr_info()
68 show_pr_checks = ctx.global_config_ops.get_show_pr_checks()
69 click.echo(click.style("Global configuration:", bold=True))
70 click.echo(f" workstacks_root={workstacks_root}")
71 click.echo(f" use_graphite={str(use_graphite).lower()}")
72 click.echo(f" show_pr_info={str(show_pr_info).lower()}")
73 click.echo(f" show_pr_checks={str(show_pr_checks).lower()}")
74 except FileNotFoundError:
75 click.echo(click.style("Global configuration:", bold=True))
76 click.echo(" (not configured - run 'workstack init' to create)")
78 # Try to load repo config
79 try:
80 repo = discover_repo_context(ctx, Path.cwd())
81 workstacks_dir = ensure_workstacks_dir(repo)
82 cfg = load_config(workstacks_dir)
84 click.echo(click.style("\nRepository configuration:", bold=True))
85 if cfg.env:
86 for key, value in cfg.env.items():
87 click.echo(f" env.{key}={value}")
88 if cfg.post_create_shell:
89 click.echo(f" post_create.shell={cfg.post_create_shell}")
90 if cfg.post_create_commands:
91 click.echo(f" post_create.commands={cfg.post_create_commands}")
93 if not cfg.env and not cfg.post_create_shell and not cfg.post_create_commands:
94 click.echo(" (no configuration - run 'workstack init --repo' to create)")
95 except Exception:
96 click.echo(click.style("\nRepository configuration:", bold=True))
97 click.echo(" (not in a git repository)")
100@config_group.command("get")
101@click.argument("key", metavar="KEY")
102@click.pass_obj
103def config_get(ctx: WorkstackContext, key: str) -> None:
104 """Print the value of a given configuration key."""
105 parts = key.split(".")
107 # Handle global config keys
108 if parts[0] in ("workstacks_root", "use_graphite", "show_pr_info", "show_pr_checks"):
109 try:
110 if parts[0] == "workstacks_root":
111 click.echo(str(ctx.global_config_ops.get_workstacks_root()))
112 elif parts[0] == "use_graphite":
113 click.echo(str(ctx.global_config_ops.get_use_graphite()).lower())
114 elif parts[0] == "show_pr_info":
115 click.echo(str(ctx.global_config_ops.get_show_pr_info()).lower())
116 elif parts[0] == "show_pr_checks":
117 click.echo(str(ctx.global_config_ops.get_show_pr_checks()).lower())
118 except FileNotFoundError as e:
119 click.echo(f"Global config not found at {ctx.global_config_ops.get_path()}", err=True)
120 raise SystemExit(1) from e
121 return
123 # Handle repo config keys
124 try:
125 repo = discover_repo_context(ctx, Path.cwd())
126 workstacks_dir = ensure_workstacks_dir(repo)
127 cfg = load_config(workstacks_dir)
129 if parts[0] == "env":
130 _get_env_value(cfg, parts, key)
131 return
133 if parts[0] == "post_create":
134 _get_post_create_value(cfg, parts, key)
135 return
137 click.echo(f"Invalid key: {key}", err=True)
138 raise SystemExit(1)
140 except Exception as e:
141 if "not in a git repository" in str(e).lower() or "not a git repository" in str(e).lower():
142 click.echo("Not in a git repository", err=True)
143 else:
144 click.echo(f"Error: {e}", err=True)
145 raise SystemExit(1) from e
148@config_group.command("set")
149@click.argument("key", metavar="KEY")
150@click.argument("value", metavar="VALUE")
151@click.pass_obj
152def config_set(ctx: WorkstackContext, key: str, value: str) -> None:
153 """Update configuration with a value for the given key."""
154 # Parse key into parts
155 parts = key.split(".")
157 # Handle global config keys
158 if parts[0] in ("workstacks_root", "use_graphite", "show_pr_info", "show_pr_checks"):
159 if not ctx.global_config_ops.exists():
160 click.echo(f"Global config not found at {ctx.global_config_ops.get_path()}", err=True)
161 click.echo("Run 'workstack init' to create it.", err=True)
162 raise SystemExit(1)
164 # Update value using set()
165 if parts[0] == "workstacks_root":
166 ctx.global_config_ops.set(workstacks_root=Path(value).expanduser().resolve())
167 elif parts[0] == "use_graphite":
168 if value.lower() not in ("true", "false"):
169 click.echo(f"Invalid boolean value: {value}", err=True)
170 raise SystemExit(1)
171 ctx.global_config_ops.set(use_graphite=value.lower() == "true")
172 elif parts[0] == "show_pr_info":
173 if value.lower() not in ("true", "false"):
174 click.echo(f"Invalid boolean value: {value}", err=True)
175 raise SystemExit(1)
176 ctx.global_config_ops.set(show_pr_info=value.lower() == "true")
177 elif parts[0] == "show_pr_checks":
178 if value.lower() not in ("true", "false"):
179 click.echo(f"Invalid boolean value: {value}", err=True)
180 raise SystemExit(1)
181 ctx.global_config_ops.set(show_pr_checks=value.lower() == "true")
183 click.echo(f"Set {key}={value}")
184 return
186 # Handle repo config keys - not implemented yet
187 click.echo("Setting repo config keys not yet implemented", err=True)
188 raise SystemExit(1)