//! `assign [--remove]` — add or remove a user from an //! issue/PR's assignee list. Forgejo has no dedicated POST endpoint — //! we read the current list, mutate, and PATCH the issue back (closes //! #353's "no such endpoint" trap; matches the bash helper's logic). use anyhow::Result; use clap::Args as ClapArgs; use serde_json::{Value, json}; use crate::client::Client; use crate::verbs::print_json; #[derive(ClapArgs)] pub struct Args { /// Issue or PR number. number: u64, /// User login to assign (or unassign with `--remove`). user: String, /// Remove the user instead of adding. #[arg(long)] remove: bool, } pub fn run(client: &Client, args: Args) -> Result<()> { let repo = client.repo(); let current = client.get_json(&format!("/repos/{repo}/issues/{}", args.number))?; let mut assignees: Vec = current .get("assignees") .and_then(Value::as_array) .map(|a| { a.iter() .filter_map(|u| u.get("login").and_then(Value::as_str).map(str::to_owned)) .collect() }) .unwrap_or_default(); if args.remove { assignees.retain(|u| u != &args.user); } else if !assignees.contains(&args.user) { assignees.push(args.user.clone()); } let resp = client.patch_json( &format!("/repos/{repo}/issues/{}", args.number), &json!({ "assignees": assignees }), )?; let logins: Vec<&str> = resp .get("assignees") .and_then(Value::as_array) .map(|a| { a.iter() .filter_map(|u| u.get("login").and_then(Value::as_str)) .collect() }) .unwrap_or_default(); print_json(&json!({ "number": resp.get("number"), "assignees": logins, })) }