Skip to content

Commit 10af1aa

Browse files
committed
refactor(chat_interface): improve command parsing and execution logic
This commit refactors the chat interface to enhance command parsing and execution. It simplifies the argument parsing process, adds support for the 'user' parameter, and improves error handling. The changes also ensure consistent behavior between the CLI and chat interface for date handling and default values.
1 parent e8cd9a3 commit 10af1aa

File tree

4 files changed

+135
-98
lines changed

4 files changed

+135
-98
lines changed

src/wellcode_cli/commands/chat_interface.py

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def chat_interface():
6868
console.print(f"[dim]Interpreting as: {interpreted_command}[/dim]")
6969

7070
if interpreted_command:
71-
execute_command(command)
71+
execute_command(interpreted_command)
7272
else:
7373
console.print("[yellow]I couldn't understand that request. Try rephrasing or type 'help' for suggestions.[/]")
7474

@@ -89,48 +89,45 @@ def execute_command(command_str: str) -> bool:
8989
ctx = click.get_current_context()
9090

9191
if command_type == CommandType.REVIEW:
92-
# Clean up the command string and split properly
93-
args = command_str.strip('"\'').split()
92+
93+
parts = command_str.split()
94+
9495
date_args = {}
9596

96-
# Parse args list properly
97-
i = 0
98-
while i < len(args):
99-
if args[i].startswith('--'):
100-
key = args[i].strip('--')
101-
if i + 1 < len(args):
102-
value = args[i + 1]
103-
date_args[key] = value
104-
i += 2
105-
else:
106-
i += 1
107-
else:
108-
i += 1
109-
97+
# Parse the command parts directly
98+
for i in range(len(parts)):
99+
if parts[i] == '--start-date' and i + 1 < len(parts):
100+
date_args['start-date'] = parts[i + 1]
101+
elif parts[i] == '--end-date' and i + 1 < len(parts):
102+
date_args['end-date'] = parts[i + 1]
103+
elif parts[i] == '--team' and i + 1 < len(parts):
104+
date_args['team'] = parts[i + 1]
105+
elif parts[i] == '--user' and i + 1 < len(parts):
106+
date_args['user'] = parts[i + 1]
107+
108+
110109
# Initialize dates
111110
now = datetime.now()
112111

113-
try:
114-
if 'start-date' in date_args and 'end-date' in date_args:
115-
start_date = datetime.strptime(date_args['start-date'], '%Y-%m-%d')
116-
end_date = datetime.strptime(date_args['end-date'], '%Y-%m-%d')
117-
else:
118-
# Default to last 7 days
119-
end_date = now
120-
start_date = end_date - timedelta(days=7)
112+
if 'start-date' in date_args and 'end-date' in date_args:
113+
start_date = datetime.strptime(date_args['start-date'], '%Y-%m-%d')
114+
end_date = datetime.strptime(date_args['end-date'], '%Y-%m-%d')
115+
else:
116+
# Default to last 7 days
117+
end_date = now
118+
start_date = end_date - timedelta(days=7)
121119

122-
# Ensure proper time boundaries
123-
end_date = end_date.replace(hour=23, minute=59, second=59)
124-
start_date = start_date.replace(hour=0, minute=0, second=0)
120+
# Ensure proper time boundaries
121+
end_date = end_date.replace(hour=23, minute=59, second=59)
122+
start_date = start_date.replace(hour=0, minute=0, second=0)
125123

126-
# Get team from args
127-
team = date_args.get('team')
128-
129-
ctx.invoke(review, start_date=start_date, end_date=end_date, team=team)
130-
131-
except Exception as e:
132-
console.print(f"[red]Error processing dates: {e}[/]")
133-
return False
124+
# Get team from args
125+
team = date_args.get('team')
126+
127+
# get user from args
128+
user = date_args.get('user')
129+
130+
ctx.invoke(review, start_date=start_date, end_date=end_date, team=team, user=user)
134131
elif command_type == CommandType.CONFIG:
135132
ctx.invoke(config)
136133
elif command_type == CommandType.HELP:

src/wellcode_cli/commands/review.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ def review(start_date, end_date, user, team):
3030
if end_date is None:
3131
end_date = datetime.now()
3232

33-
# Handle start date
33+
# Handle start date - use the passed start_date instead of defaulting to 1 day
3434
if start_date is None:
35-
start_date = end_date - timedelta(days=1)
35+
start_date = end_date - timedelta(days=7) # Changed from 1 to 7 days default
3636

37-
# Ensure we're working with whole days
37+
# Ensure we're working with whole days and use the passed dates
3838
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
3939
end_date = end_date.replace(hour=23, minute=59, second=59, microsecond=999999)
4040

src/wellcode_cli/github/github_metrics.py

Lines changed: 96 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,17 @@ def process_repository_batch(repo, org_metrics, start_date, end_date, user_filte
149149
repo_metrics = org_metrics.get_or_create_repository(repo.name)
150150
repo_metrics.default_branch = repo.default_branch
151151

152-
# Track PR counts
152+
# Track PR counts for both repo and org
153153
repo_metrics.prs_created += len(relevant_pulls)
154+
org_metrics.prs_created += len(relevant_pulls)
155+
154156
merged_prs = [pr for pr in relevant_pulls if pr.merged]
155157
repo_metrics.prs_merged += len(merged_prs)
156-
repo_metrics.prs_merged_to_main += sum(1 for pr in merged_prs if pr.base.ref == repo_metrics.default_branch)
158+
org_metrics.prs_merged += len(merged_prs)
159+
160+
merged_to_main = sum(1 for pr in merged_prs if pr.base.ref == repo_metrics.default_branch)
161+
repo_metrics.prs_merged_to_main += merged_to_main
162+
org_metrics.prs_merged_to_main += merged_to_main
157163

158164
# Add contributor tracking
159165
for pr in relevant_pulls:
@@ -200,7 +206,6 @@ def process_pr(pr, repo_metrics, org_metrics, start_date, end_date):
200206
repo_metrics, org_metrics)
201207
]
202208

203-
# Wait for all updates to complete
204209
for future in as_completed(futures):
205210
future.result()
206211

@@ -279,28 +284,56 @@ def update_review_metrics(pr, pr_data, repo_metrics, org_metrics):
279284

280285
def update_time_metrics(pr, commits, repo_metrics, org_metrics, start_date, end_date):
281286
"""Update time metrics for a PR"""
282-
if pr.merged_at:
283-
merge_time = ensure_datetime(pr.merged_at)
284-
285-
# Update merge distribution
286-
if merge_time.weekday() >= 5: # Weekend
287-
repo_metrics.time_metrics.merge_distribution['weekends'] += 1
288-
org_metrics.time_metrics.merge_distribution['weekends'] += 1
289-
elif 9 <= merge_time.hour < 17: # Business hours (simplified)
290-
repo_metrics.time_metrics.merge_distribution['business_hours'] += 1
291-
org_metrics.time_metrics.merge_distribution['business_hours'] += 1
292-
else: # After hours
293-
repo_metrics.time_metrics.merge_distribution['after_hours'] += 1
294-
org_metrics.time_metrics.merge_distribution['after_hours'] += 1
287+
try:
288+
if pr.merged_at:
289+
# Convert all times to datetime with timezone
290+
merge_time = ensure_datetime(pr.merged_at)
291+
created_time = ensure_datetime(pr.created_at)
295292

296-
# Calculate deployment frequency (merges per day to main branch)
297-
if pr.base.ref == repo_metrics.default_branch:
298-
one_day_seconds = 24 * 60 * 60
299-
days_in_period = (end_date - start_date).total_seconds() / one_day_seconds
300-
repo_metrics.time_metrics.deployment_frequency = repo_metrics.prs_merged_to_main / days_in_period
301-
org_metrics.time_metrics.deployment_frequency = org_metrics.prs_merged_to_main / days_in_period
302-
303-
# ... rest of existing update_time_metrics code ...
293+
# Calculate time to merge in hours
294+
merge_duration = (merge_time - created_time).total_seconds() / 3600
295+
repo_metrics.time_metrics.time_to_merge.append(merge_duration)
296+
org_metrics.time_metrics.time_to_merge.append(merge_duration)
297+
298+
# Calculate lead time if we have commits
299+
if commits and len(commits) > 0:
300+
first_commit = min(commits, key=lambda c: ensure_datetime(c.commit.author.date))
301+
first_commit_date = ensure_datetime(first_commit.commit.author.date)
302+
lead_time = (merge_time - first_commit_date).total_seconds() / 3600
303+
repo_metrics.time_metrics.lead_times.append(lead_time)
304+
org_metrics.time_metrics.lead_times.append(lead_time)
305+
306+
# Calculate cycle time
307+
cycle_time = (merge_time - first_commit_date).total_seconds() / 3600
308+
repo_metrics.time_metrics.cycle_time.append(cycle_time)
309+
org_metrics.time_metrics.cycle_time.append(cycle_time)
310+
311+
# Update merge distribution
312+
if merge_time.weekday() >= 5: # Weekend
313+
repo_metrics.time_metrics.merge_distribution['weekends'] += 1
314+
org_metrics.time_metrics.merge_distribution['weekends'] += 1
315+
elif 9 <= merge_time.hour < 17: # Business hours
316+
repo_metrics.time_metrics.merge_distribution['business_hours'] += 1
317+
org_metrics.time_metrics.merge_distribution['business_hours'] += 1
318+
else: # After hours
319+
repo_metrics.time_metrics.merge_distribution['after_hours'] += 1
320+
org_metrics.time_metrics.merge_distribution['after_hours'] += 1
321+
322+
# Calculate deployment frequency with safety check
323+
if pr.base.ref == repo_metrics.default_branch:
324+
one_day_seconds = 24 * 60 * 60
325+
days_in_period = max((end_date - start_date).total_seconds() / one_day_seconds, 1) # Ensure minimum 1 day
326+
327+
# Add safety checks for division
328+
if days_in_period > 0:
329+
if repo_metrics.prs_merged_to_main > 0:
330+
repo_metrics.time_metrics.deployment_frequency = repo_metrics.prs_merged_to_main / days_in_period
331+
if org_metrics.prs_merged_to_main > 0:
332+
org_metrics.time_metrics.deployment_frequency = org_metrics.prs_merged_to_main / days_in_period
333+
except Exception as e:
334+
print(f"DEBUG: Error in update_time_metrics: {str(e)}")
335+
# Continue processing even if there's an error with one PR
336+
pass
304337

305338
def process_reviews(pr, reviews, repo_metrics, org_metrics):
306339
"""Process reviews for a PR"""
@@ -323,8 +356,8 @@ def process_reviews(pr, reviews, repo_metrics, org_metrics):
323356
repo_metrics.review_metrics.update_from_review(review, pr)
324357
org_metrics.review_metrics.update_from_review(review, pr)
325358

326-
# Update collaboration metrics
327-
update_collaboration_metrics(pr, review, repo_metrics, org_metrics, reviewer_metrics)
359+
# Fix: Remove reviewer_metrics from this call
360+
update_collaboration_metrics(pr, reviews, repo_metrics, org_metrics)
328361

329362
def update_collaboration_metrics(pr, reviews, repo_metrics, org_metrics):
330363
"""Update collaboration metrics including participation rate"""
@@ -334,42 +367,46 @@ def update_collaboration_metrics(pr, reviews, repo_metrics, org_metrics):
334367
org_metrics.collaboration_metrics.self_merges += 1
335368

336369
# Update collaboration metrics at all levels
337-
repo_metrics.collaboration_metrics.update_from_reviews(
338-
reviews, pr,
339-
author_team=pr.user.team,
340-
reviewer_team=reviews[0].user.team
341-
)
342-
org_metrics.collaboration_metrics.update_from_reviews(
343-
reviews, pr,
344-
author_team=pr.user.team,
345-
reviewer_team=reviews[0].user.team
346-
)
347-
348-
# Update team reviews
349-
if reviews[0].user.team and pr.user.team:
350-
if reviews[0].user.team == pr.user.team:
351-
repo_metrics.collaboration_metrics.team_reviews += 1
352-
org_metrics.collaboration_metrics.team_reviews += 1
370+
if reviews and len(reviews) > 0 and hasattr(pr.user, 'team') and hasattr(reviews[0].user, 'team'):
371+
repo_metrics.collaboration_metrics.update_from_reviews(
372+
reviews, pr,
373+
author_team=pr.user.team,
374+
reviewer_team=reviews[0].user.team
375+
)
376+
org_metrics.collaboration_metrics.update_from_reviews(
377+
reviews, pr,
378+
author_team=pr.user.team,
379+
reviewer_team=reviews[0].user.team
380+
)
381+
382+
# Update team reviews
383+
if reviews[0].user.team and pr.user.team:
384+
if reviews[0].user.team == pr.user.team:
385+
repo_metrics.collaboration_metrics.team_reviews += 1
386+
org_metrics.collaboration_metrics.team_reviews += 1
387+
else:
388+
repo_metrics.collaboration_metrics.cross_team_reviews += 1
389+
org_metrics.collaboration_metrics.cross_team_reviews += 1
353390
else:
354-
repo_metrics.collaboration_metrics.cross_team_reviews += 1
355-
org_metrics.collaboration_metrics.cross_team_reviews += 1
356-
else:
357-
repo_metrics.collaboration_metrics.external_reviews += 1
358-
org_metrics.collaboration_metrics.external_reviews += 1
391+
repo_metrics.collaboration_metrics.external_reviews += 1
392+
org_metrics.collaboration_metrics.external_reviews += 1
393+
394+
# Calculate review participation rate for repository
395+
repo_total_reviews = (repo_metrics.collaboration_metrics.team_reviews +
396+
repo_metrics.collaboration_metrics.cross_team_reviews +
397+
repo_metrics.collaboration_metrics.external_reviews)
398+
399+
if repo_metrics.prs_created > 0:
400+
repo_metrics.collaboration_metrics.review_participation_rate = repo_total_reviews / repo_metrics.prs_created
359401

360-
# Calculate review participation rate
361-
total_reviews = repo_metrics.collaboration_metrics.team_reviews + \
362-
repo_metrics.collaboration_metrics.cross_team_reviews + \
363-
repo_metrics.collaboration_metrics.external_reviews
364-
total_prs = repo_metrics.prs_merged + repo_metrics.collaboration_metrics.self_merges
402+
# Calculate review participation rate for organization
403+
org_total_reviews = (org_metrics.collaboration_metrics.team_reviews +
404+
org_metrics.collaboration_metrics.cross_team_reviews +
405+
org_metrics.collaboration_metrics.external_reviews)
365406

366-
if total_prs > 0:
367-
repo_metrics.collaboration_metrics.review_participation_rate = total_reviews / total_prs
368-
org_metrics.collaboration_metrics.review_participation_rate = \
369-
(org_metrics.collaboration_metrics.team_reviews + \
370-
org_metrics.collaboration_metrics.cross_team_reviews + \
371-
org_metrics.collaboration_metrics.external_reviews) / \
372-
(org_metrics.prs_merged + org_metrics.collaboration_metrics.self_merges)
407+
# Fix: Use prs_created instead of total_prs
408+
if org_metrics.prs_created > 0: # Changed from total_prs to prs_created
409+
org_metrics.collaboration_metrics.review_participation_rate = org_total_reviews / org_metrics.prs_created
373410

374411
def get_team_members(org, team_filter: str) -> set:
375412
"""Get team members for a specific team"""

src/wellcode_cli/github/models/metrics.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ class OrganizationMetrics(BaseMetrics):
343343
time_metrics: TimeMetrics = field(default_factory=TimeMetrics)
344344
collaboration_metrics: CollaborationMetrics = field(default_factory=CollaborationMetrics)
345345
bottleneck_metrics: BottleneckMetrics = field(default_factory=BottleneckMetrics)
346+
prs_created: int = 0
347+
prs_merged: int = 0
348+
prs_merged_to_main: int = 0
346349

347350
def get_or_create_repository(self, name: str, default_branch: str = "main") -> RepositoryMetrics:
348351
if name not in self.repositories:

0 commit comments

Comments
 (0)