Skip to content

Commit 0d4a231

Browse files
feat: add first-run welcome, setup instructions, and clear API key guidance
1 parent a71534f commit 0d4a231

5 files changed

Lines changed: 163 additions & 15 deletions

File tree

4.24 KB
Binary file not shown.
2.84 KB
Binary file not shown.

codereview/cli.py

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55
import logging
66
from typing import Optional, Tuple
77

8+
from rich.console import Console
9+
from rich.panel import Panel
10+
811
from . import __version__
912
from .config import (
1013
load_config,
1114
init_config,
1215
validate_api_key,
16+
is_first_run,
1317
ConfigError,
1418
PROVIDER_DEFAULTS,
19+
GROQ_SETUP_INSTRUCTIONS,
1520
)
1621
from .reviewer import review_code, ReviewResult
1722
from .formatter import print_review, print_error, print_info, console
@@ -26,6 +31,46 @@
2631
logger = logging.getLogger(__name__)
2732

2833

34+
# ─── Welcome Message ───
35+
36+
WELCOME_MESSAGE: str = """
37+
[bold bright_blue]🔍 Welcome to codereview![/bold bright_blue]
38+
39+
AI-powered code review in your terminal.
40+
41+
[bold]Quick setup (free, 60 seconds):[/bold]
42+
43+
[dim]1.[/dim] Go to [cyan]https://console.groq.com[/cyan]
44+
[dim]2.[/dim] Sign up with Google or GitHub
45+
[dim]3.[/dim] Click [bold]API Keys[/bold] → [bold]Create API Key[/bold]
46+
[dim]4.[/dim] Run these two commands:
47+
48+
[green]export GROQ_API_KEY="gsk_your_key_here"[/green]
49+
[green]codereview --init groq[/green]
50+
51+
[dim]5.[/dim] Review any file:
52+
53+
[green]codereview app.py[/green]
54+
55+
[dim]To make the key permanent so you don't set it every session:[/dim]
56+
57+
[green]echo 'export GROQ_API_KEY="gsk_your_key_here"' >> ~/.zshrc[/green]
58+
[green]source ~/.zshrc[/green]
59+
60+
[dim]Other providers: --init openai | --init anthropic | --init ollama[/dim]
61+
"""
62+
63+
64+
def show_welcome() -> None:
65+
"""Display welcome message for first-time users."""
66+
console.print(Panel(
67+
WELCOME_MESSAGE,
68+
title="[bold]First Time Setup[/bold]",
69+
border_style="bright_blue",
70+
padding=(1, 2),
71+
))
72+
73+
2974
# ─── Argument Parsing ───
3075

3176
def build_parser() -> argparse.ArgumentParser:
@@ -49,9 +94,16 @@ def build_parser() -> argparse.ArgumentParser:
4994
5095
Providers:
5196
codereview --init openai Set up with OpenAI
52-
codereview --init ollama Set up with local Ollama
53-
codereview --init groq Set up with Groq (free tier)
97+
codereview --init ollama Set up with local Ollama (free, offline)
98+
codereview --init groq Set up with Groq (free, no credit card)
5499
codereview --init anthropic Set up with Anthropic
100+
101+
Free setup:
102+
1. Go to https://console.groq.com
103+
2. Sign up (Google or GitHub)
104+
3. Create an API key
105+
4. export GROQ_API_KEY="gsk_your_key_here"
106+
5. codereview --init groq
55107
""",
56108
)
57109

@@ -72,6 +124,11 @@ def build_parser() -> argparse.ArgumentParser:
72124
choices=list(PROVIDER_DEFAULTS.keys()),
73125
help="Initialize config for a provider",
74126
)
127+
parser.add_argument(
128+
"--setup",
129+
action="store_true",
130+
help="Show setup instructions",
131+
)
75132
parser.add_argument(
76133
"--version",
77134
action="version",
@@ -95,15 +152,41 @@ def handle_init(provider: str) -> None:
95152
print_error(str(e))
96153
sys.exit(1)
97154

98-
print_info(f"Config initialized for {provider}")
99-
print_info(f"Model: {config['model']}")
155+
console.print()
156+
console.print(f"[bold green]✅ Config initialized for {provider}[/bold green]")
157+
console.print(f"[dim] Model: {config['model']}[/dim]")
158+
console.print()
100159

101160
if provider == "ollama":
102-
print_info("Make sure Ollama is running: ollama serve")
161+
console.print("[bold]Next steps:[/bold]")
162+
console.print(" 1. Make sure Ollama is running: [green]ollama serve[/green]")
163+
console.print(" 2. Pull a model: [green]ollama pull llama3[/green]")
164+
console.print(" 3. Review code: [green]codereview yourfile.py[/green]")
103165
else:
104166
env_key: str = PROVIDER_DEFAULTS[provider].get("env_key", "")
105-
if env_key:
106-
print_info(f"Set your API key: export {env_key}=your-key-here")
167+
has_key: bool = bool(config.get("api_key"))
168+
169+
if has_key:
170+
console.print("[bold green]✅ API key detected![/bold green]")
171+
console.print()
172+
console.print("[bold]You're ready! Try:[/bold]")
173+
console.print(" [green]codereview yourfile.py[/green]")
174+
else:
175+
console.print(f"[bold yellow]⚠️ No API key detected.[/bold yellow]")
176+
console.print()
177+
if provider == "groq":
178+
console.print("[bold]Get your free key:[/bold]")
179+
console.print(" 1. Go to [cyan]https://console.groq.com[/cyan]")
180+
console.print(" 2. Sign up → API Keys → Create API Key")
181+
console.print(f" 3. Run: [green]export {env_key}=\"gsk_your_key_here\"[/green]")
182+
console.print()
183+
console.print("[dim]To make it permanent:[/dim]")
184+
console.print(f' [green]echo \'export {env_key}="gsk_your_key_here"\' >> ~/.zshrc && source ~/.zshrc[/green]')
185+
else:
186+
console.print(f"[bold]Set your API key:[/bold]")
187+
console.print(f" [green]export {env_key}=\"your-key-here\"[/green]")
188+
189+
console.print()
107190

108191

109192
# ─── Git Requirement ───
@@ -287,26 +370,43 @@ def main() -> None:
287370
parser: argparse.ArgumentParser = build_parser()
288371
args: argparse.Namespace = parser.parse_args()
289372

373+
# Handle --setup
374+
if args.setup:
375+
show_welcome()
376+
return
377+
290378
# Handle --init
291379
if args.init:
292380
handle_init(args.init)
293381
return
294382

383+
# First run detection — show welcome if no config and no args
384+
if is_first_run():
385+
resolved_check: Optional[Tuple[str, str, bool]] = resolve_code(args) if (
386+
args.files or args.staged or args.diff or args.last or args.stdin
387+
) else None
388+
389+
if resolved_check is None:
390+
show_welcome()
391+
return
392+
295393
# Load and validate config
296394
config: dict = load_config()
297395
config = apply_overrides(config, args)
298396

299397
try:
300398
validate_api_key(config.get("api_key"), config.get("provider", "openai"))
301399
except ConfigError as e:
302-
print_error(str(e))
400+
console.print(str(e))
303401
sys.exit(1)
304402

305403
# Resolve code source
306404
resolved: Optional[Tuple[str, str, bool]] = resolve_code(args)
307405

308406
if resolved is None:
309407
parser.print_help()
408+
console.print()
409+
console.print("[dim]Need help? Run: codereview --setup[/dim]")
310410
sys.exit(0)
311411

312412
code, filename, is_diff = resolved

codereview/config.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,46 @@
4343
},
4444
}
4545

46+
GROQ_SETUP_INSTRUCTIONS: str = """
47+
╭──────────────────────────────────────────────────────────────╮
48+
│ │
49+
│ 🔑 API Key Required │
50+
│ │
51+
│ codereview needs an LLM API key to analyze your code. │
52+
│ │
53+
│ ⚡ FREE OPTION — Groq (recommended, no credit card): │
54+
│ │
55+
│ 1. Go to https://console.groq.com │
56+
│ 2. Sign up with Google or GitHub (takes 30 seconds) │
57+
│ 3. Click "API Keys" → "Create API Key" │
58+
│ 4. Copy the key and run: │
59+
│ │
60+
│ export GROQ_API_KEY="gsk_your_key_here" │
61+
│ codereview --init groq │
62+
│ │
63+
│ To make it permanent (so you don't set it every time): │
64+
│ │
65+
│ echo 'export GROQ_API_KEY="gsk_your_key_here"' │
66+
│ >> ~/.zshrc && source ~/.zshrc │
67+
│ │
68+
│ 💰 PAID OPTIONS: │
69+
│ │
70+
│ OpenAI: export OPENAI_API_KEY="sk-..." │
71+
│ codereview --init openai │
72+
│ │
73+
│ Anthropic: export ANTHROPIC_API_KEY="sk-ant-..." │
74+
│ codereview --init anthropic │
75+
│ │
76+
│ 🏠 FULLY OFFLINE — Ollama (free, no API key needed): │
77+
│ │
78+
│ 1. Install Ollama: https://ollama.com │
79+
│ 2. Run: ollama pull llama3 │
80+
│ 3. Run: ollama serve │
81+
│ 4. Run: codereview --init ollama │
82+
│ │
83+
╰──────────────────────────────────────────────────────────────╯
84+
"""
85+
4686

4787
class ConfigError(Exception):
4888
"""Raised when configuration is invalid or missing."""
@@ -91,22 +131,27 @@ def validate_api_key(api_key: Optional[str], provider: str) -> bool:
91131
return True
92132

93133
if not api_key:
94-
env_key: str = PROVIDER_DEFAULTS.get(provider, {}).get("env_key", "API_KEY")
95-
raise ConfigError(
96-
f"No API key found. Set the {env_key} environment variable.\n"
97-
f" export {env_key}=your-key-here\n"
98-
f" Or: export CODEREVIEW_API_KEY=your-key-here"
99-
)
134+
raise ConfigError(GROQ_SETUP_INSTRUCTIONS)
100135

101136
if len(api_key) < 10:
102137
raise ConfigError(
103138
f"API key looks too short ({len(api_key)} chars). "
104-
f"Check your environment variable."
139+
f"Double-check your environment variable.\n"
140+
+ GROQ_SETUP_INSTRUCTIONS
105141
)
106142

107143
return True
108144

109145

146+
def is_first_run() -> bool:
147+
"""Check if this is the first time running codereview.
148+
149+
Returns:
150+
True if no config file exists yet.
151+
"""
152+
return not CONFIG_PATH.exists()
153+
154+
110155
def _load_config_file() -> Dict[str, Any]:
111156
"""Load config from disk safely.
112157

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ dependencies = [
1616

1717
[project.scripts]
1818
codereview = "codereview.cli:main"
19+
20+
[tool.pytest.ini_options]
21+
testpaths = ["tests"]

0 commit comments

Comments
 (0)