//! `issue-create --title [body sources] [--assignee ] //! [--label ]... [repo]` — create an issue. Prints the issue URL. use anyhow::Result; use clap::Args as ClapArgs; use forgejo_api::structs::CreateIssueOption; use crate::body; use crate::client::Client; use crate::verbs::labels; #[derive(ClapArgs)] pub struct Args { /// Issue title (required). #[arg(long)] title: String, /// Inline body text. #[arg(long, conflicts_with = "body_file")] body: Option, /// Read body from a file. `-` means stdin. #[arg(long = "body-file")] body_file: Option, /// Initial assignee login. #[arg(long)] assignee: Option, /// Label name to attach, repeatable (e.g. `--label area/ops --label /// type/bug`). Same spelling `labels add` accepts. An unresolved name /// errors out (before the issue is created) rather than silently /// attaching fewer labels than asked for. #[arg(long = "label")] labels: Vec, } /// # 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, the /// `--label` lookup's own list-labels call), an unresolved `--label` /// name, and any I/O error from writing the issue URL to stdout. pub fn run(client: &Client, args: Args) -> Result<()> { let body = body::resolve(args.body.as_deref(), args.body_file.as_deref())?.unwrap_or_default(); let (owner, name) = client.owner_repo()?; let label_ids = if args.labels.is_empty() { None } else { let all = labels::repo_labels(client)?; Some(labels::resolve_ids(&all, &args.labels)?) }; let payload = CreateIssueOption { assignee: None, assignees: args.assignee.map(|a| vec![a]), body: Some(body), closed: None, due_date: None, labels: label_ids, milestone: None, r#ref: None, title: args.title, }; let issue = client .api() .issue_create_issue(owner, name, payload) .send()?; if let Some(url) = issue.html_url { println!("{url}"); } Ok(()) }