//! `issue-edit [--title ] [body sources] [--state s] //! [--milestone id] [repo]` — partial update of an issue. Fields not //! provided are left unchanged. use anyhow::Result; use clap::{Args as ClapArgs, ValueEnum}; use forgejo_api::structs::EditIssueOption; use serde_json::json; use crate::body; use crate::client::{Client, index}; use crate::verbs::print_json; #[derive(Copy, Clone, ValueEnum)] pub enum StateArg { Open, Closed, } impl StateArg { fn as_str(self) -> &'static str { match self { Self::Open => "open", Self::Closed => "closed", } } } #[derive(ClapArgs)] pub struct Args { /// Issue number. number: u64, /// New title (omit to leave unchanged). #[arg(long)] title: Option, /// Inline body text (omit to leave unchanged). #[arg(long, conflicts_with = "body_file")] body: Option, /// Read body from a file. `-` means stdin. #[arg(long = "body-file")] body_file: Option, /// New state. #[arg(long, value_enum)] state: Option, /// Milestone id (0 to unset). #[arg(long)] milestone: Option, } /// # Errors /// /// Propagates any I/O error from the body input (`--body-file`, /// stdin), any transport error from the Forgejo REST call (network /// unreachable, 4xx/5xx response, token missing/invalid), and any /// I/O error from writing the response to stdout. pub fn run(client: &Client, args: Args) -> Result<()> { // Body is partial: only update the body field if a source was // actually given. Piped stdin without --body/--body-file leaves // body alone (the partial-update contract). Absent fields ride as // JSON `null`, which Forgejo's partial-update binding treats as // "leave unchanged". let body_explicit = args.body.is_some() || args.body_file.is_some(); let body = if body_explicit { body::resolve(args.body.as_deref(), args.body_file.as_deref())? } else { None }; let payload = EditIssueOption { assignee: None, assignees: None, body, due_date: None, milestone: args.milestone.map(index).transpose()?, r#ref: None, state: args.state.map(|s| s.as_str().to_owned()), title: args.title, unset_due_date: None, updated_at: None, }; let (owner, name) = client.owner_repo()?; let resp = client .api() .issue_edit_issue(owner, name, index(args.number)?, payload) .send()?; print_json(&json!({ "number": resp.number, "title": resp.title, "state": resp.state, "milestone": resp.milestone.as_ref().and_then(|m| m.title.as_deref()), })) }