@@ -32,6 +32,31 @@
#[arg(long)]
repo: Option<String>,
},
/// Edit a label definition (rename / recolor / redescribe)
Edit {
/// Current label name
name: String,
/// New name
#[arg(long)]
new_name: Option<String>,
/// New color (hex, e.g. "#00ff00")
#[arg(long)]
color: Option<String>,
/// New description
#[arg(long)]
description: Option<String>,
/// Repository (org/repo)
#[arg(long)]
repo: Option<String>,
},
/// Delete a label definition (removes it from all issues)
Delete {
/// Label name
name: String,
/// Repository (org/repo)
#[arg(long)]
repo: Option<String>,
},
/// Add a label to an issue
Add {
/// Issue number
@@ -74,6 +99,23 @@
description,
repo,
} => create(repo.as_deref(), &name, &color, description.as_deref()).await,
LabelCommand::Edit {
name,
new_name,
color,
description,
repo,
} => {
edit(
repo.as_deref(),
&name,
new_name.as_deref(),
color.as_deref(),
description.as_deref(),
)
.await
}
LabelCommand::Delete { name, repo } => delete(repo.as_deref(), &name).await,
LabelCommand::Add { issue, name, repo } => add(repo.as_deref(), issue, &name).await,
LabelCommand::Remove { issue, name, repo } => remove(repo.as_deref(), issue, &name).await,
}
@@ -83,6 +125,10 @@
let client = Client::from_config()?;
let (org, name) = config::resolve_repo(repo)?;
let resp: serde_json::Value = client.get(&format!("/{org}/{name}/labels")).await?;
if output::is_json() {
output::print_json(&resp);
return Ok(());
}
let labels: Vec<Label> = resp
.get("labels")
.and_then(|v| serde_json::from_value(v.clone()).ok())
@@ -114,13 +160,61 @@
if let Some(desc) = description {
payload["description"] = serde_json::json!(desc);
}
let _resp: serde_json::Value = client
let resp: serde_json::Value = client
.post(&format!("/{org}/{name}/labels"), &payload)
.await?;
if output::is_json() {
output::json_ok("label", resp);
return Ok(());
}
output::success(&format!("Created label '{label_name}'"));
Ok(())
}
async fn edit(
repo: Option<&str>,
label_name: &str,
new_name: Option<&str>,
color: Option<&str>,
description: Option<&str>,
) -> Result<(), Box<dyn std::error::Error>> {
let client = Client::from_config()?;
let (org, name) = config::resolve_repo(repo)?;
let mut payload = serde_json::json!({});
if let Some(v) = new_name {
payload["new_name"] = serde_json::json!(v);
}
if let Some(v) = color {
payload["color"] = serde_json::json!(v);
}
if let Some(v) = description {
payload["description"] = serde_json::json!(v);
}
let resp: serde_json::Value = client
.patch(&format!("/{org}/{name}/labels/{label_name}"), &payload)
.await?;
if output::is_json() {
output::json_ok("label", resp);
return Ok(());
}
output::success(&format!("Updated label '{label_name}'"));
Ok(())
}
async fn delete(repo: Option<&str>, label_name: &str) -> Result<(), Box<dyn std::error::Error>> {
let client = Client::from_config()?;
let (org, name) = config::resolve_repo(repo)?;
client
.delete_empty(&format!("/{org}/{name}/labels/{label_name}"))
.await?;
if output::is_json() {
output::json_ok("deleted", serde_json::json!(label_name));
return Ok(());
}
output::success(&format!("Deleted label '{label_name}'"));
Ok(())
}
async fn add(
repo: Option<&str>,
issue_number: u32,
@@ -134,6 +228,13 @@
&serde_json::json!({"name": label_name}),
)
.await?;
if output::is_json() {
output::json_ok(
"label_added",
serde_json::json!({"issue": issue_number, "name": label_name}),
);
return Ok(());
}
output::success(&format!(
"Added label '{label_name}' to issue #{issue_number}"
));
@@ -152,6 +253,13 @@
"/{org}/{name}/issues/{issue_number}/labels/{label_name}"
))
.await?;
if output::is_json() {
output::json_ok(
"label_removed",
serde_json::json!({"issue": issue_number, "name": label_name}),
);
return Ok(());
}
output::success(&format!(
"Removed label '{label_name}' from issue #{issue_number}"
));