Skip to content

Commit c25f024

Browse files
sachiniyerclaude
andauthored
refactor: consolidate duplicated CLI enums with api types (#17)
Add Clone and clap::ValueEnum to BugReviewState and BugDismissalReason in api/types.rs so they work directly as CLI arguments. Delete the duplicated ReviewState, DismissalReason, and BugStatus enums from commands/bugs.rs (~60 lines removed). Update list_bugs to accept Option<&BugReviewState> instead of Option<&str>. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 48f0260 commit c25f024

3 files changed

Lines changed: 22 additions & 88 deletions

File tree

‎src/api/client.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl ApiClient {
136136
pub async fn list_bugs(
137137
&self,
138138
repo_id: &RepoId,
139-
status: Option<&str>,
139+
status: Option<&BugReviewState>,
140140
limit: u32,
141141
offset: u32,
142142
) -> Result<BugsResponse> {
@@ -147,7 +147,10 @@ impl ApiClient {
147147
query.append_pair("limit", &limit.to_string());
148148
query.append_pair("offset", &offset.to_string());
149149
if let Some(s) = status {
150-
query.append_pair("status", s);
150+
let value = serde_json::to_value(s)?;
151+
if let Some(status_str) = value.as_str() {
152+
query.append_pair("status", status_str);
153+
}
151154
}
152155
}
153156
let path_and_query = format!("{}?{}", url.path(), url.query().unwrap_or(""));

‎src/api/types.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub struct BugReview {
114114
pub notes: Option<String>,
115115
}
116116

117-
#[derive(Debug, Deserialize, Serialize)]
117+
#[derive(Debug, Clone, Deserialize, Serialize, clap::ValueEnum)]
118118
#[serde(rename_all = "lowercase")]
119119
pub enum BugReviewState {
120120
Pending,
@@ -132,7 +132,7 @@ impl std::fmt::Display for BugReviewState {
132132
}
133133
}
134134

135-
#[derive(Debug, Deserialize, Serialize)]
135+
#[derive(Debug, Clone, Deserialize, Serialize, clap::ValueEnum)]
136136
#[serde(rename_all = "snake_case")]
137137
pub enum BugDismissalReason {
138138
NotABug,

‎src/commands/bugs.rs‎

Lines changed: 15 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,8 @@
11
use anyhow::{bail, Context, Result};
2-
use clap::{Subcommand, ValueEnum};
2+
use clap::Subcommand;
33
use colored::*;
44

5-
#[derive(Clone, ValueEnum)]
6-
pub enum ReviewState {
7-
/// Mark as pending (reopen)
8-
Pending,
9-
/// Mark as resolved
10-
Resolved,
11-
/// Mark as dismissed
12-
Dismissed,
13-
}
14-
15-
impl ReviewState {
16-
fn as_str(&self) -> &str {
17-
match self {
18-
ReviewState::Pending => "pending",
19-
ReviewState::Resolved => "resolved",
20-
ReviewState::Dismissed => "dismissed",
21-
}
22-
}
23-
}
24-
25-
#[derive(Clone, ValueEnum)]
26-
pub enum DismissalReason {
27-
/// Not a bug
28-
NotABug,
29-
/// Won't fix
30-
WontFix,
31-
/// Duplicate issue
32-
Duplicate,
33-
/// Other reason
34-
Other,
35-
}
36-
37-
impl DismissalReason {
38-
#[allow(dead_code)]
39-
fn as_str(&self) -> &str {
40-
match self {
41-
DismissalReason::NotABug => "not_a_bug",
42-
DismissalReason::WontFix => "wont_fix",
43-
DismissalReason::Duplicate => "duplicate",
44-
DismissalReason::Other => "other",
45-
}
46-
}
47-
}
48-
49-
#[derive(Clone, ValueEnum)]
50-
pub enum BugStatus {
51-
Pending,
52-
Resolved,
53-
Dismissed,
54-
}
55-
56-
impl BugStatus {
57-
fn as_str(&self) -> &str {
58-
match self {
59-
BugStatus::Pending => "pending",
60-
BugStatus::Resolved => "resolved",
61-
BugStatus::Dismissed => "dismissed",
62-
}
63-
}
64-
}
5+
use crate::api::types::{BugDismissalReason, BugReviewState};
656

667
#[derive(Subcommand)]
678
pub enum BugCommands {
@@ -72,7 +13,7 @@ pub enum BugCommands {
7213

7314
/// Status filter
7415
#[arg(long, value_enum, default_value = "pending")]
75-
status: BugStatus,
16+
status: BugReviewState,
7617

7718
/// Maximum number of results per page
7819
#[arg(long, default_value = "50")]
@@ -100,11 +41,11 @@ pub enum BugCommands {
10041

10142
/// Review state
10243
#[arg(long, value_enum)]
103-
state: ReviewState,
44+
state: BugReviewState,
10445

10546
/// Dismissal reason (required if state is dismissed)
10647
#[arg(long, value_enum)]
107-
dismissal_reason: Option<DismissalReason>,
48+
dismissal_reason: Option<BugDismissalReason>,
10849

10950
/// Additional notes
11051
#[arg(long)]
@@ -221,7 +162,7 @@ pub async fn handle(command: &BugCommands, cli: &crate::Cli) -> Result<()> {
221162
let offset = crate::utils::page_to_offset(*page, *limit);
222163

223164
let bugs = client
224-
.list_bugs(&resolved_repo_id, Some(status.as_str()), *limit, offset)
165+
.list_bugs(&resolved_repo_id, Some(status), *limit, offset)
225166
.await
226167
.context("Failed to fetch bugs from repository")?;
227168

@@ -277,36 +218,26 @@ pub async fn handle(command: &BugCommands, cli: &crate::Cli) -> Result<()> {
277218
dismissal_reason,
278219
notes,
279220
} => {
280-
use crate::api::types::{BugDismissalReason, BugId, BugReviewState};
221+
use crate::api::types::BugId;
281222

282223
// Validate that dismissal_reason is provided when state is dismissed
283-
if matches!(state, ReviewState::Dismissed) && dismissal_reason.is_none() {
224+
if matches!(state, BugReviewState::Dismissed) && dismissal_reason.is_none() {
284225
bail!("--dismissal-reason is required when state is 'dismissed'");
285226
}
286227

287228
let bug_id = BugId::new(bug_id).map_err(|e| anyhow::anyhow!(e))?;
288229

289-
let api_state = match state {
290-
ReviewState::Pending => BugReviewState::Pending,
291-
ReviewState::Resolved => BugReviewState::Resolved,
292-
ReviewState::Dismissed => BugReviewState::Dismissed,
293-
};
294-
let api_reason = dismissal_reason.as_ref().map(|r| match r {
295-
DismissalReason::NotABug => BugDismissalReason::NotABug,
296-
DismissalReason::WontFix => BugDismissalReason::WontFix,
297-
DismissalReason::Duplicate => BugDismissalReason::Duplicate,
298-
DismissalReason::Other => BugDismissalReason::Other,
299-
});
300-
301230
client
302-
.update_bug_review(&bug_id, api_state, api_reason, notes.as_deref())
231+
.update_bug_review(
232+
&bug_id,
233+
state.clone(),
234+
dismissal_reason.clone(),
235+
notes.as_deref(),
236+
)
303237
.await
304238
.context("Failed to update bug review")?;
305239

306-
println!(
307-
"{}",
308-
format!("✓ Updated bug review to: {}", state.as_str()).green()
309-
);
240+
println!("{}", format!("✓ Updated bug review to: {}", state).green());
310241
Ok(())
311242
}
312243
}

0 commit comments

Comments
 (0)