Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hive-forge/src/verbs/reaction.rs
atlas f0e3ed04d3 hive-forge, hivectl, swarmctl: fix clap help passive voice, regen docs
Rewrites every write-good.Passive hit in the hive-forge clap help text
into terse, imperative, active voice (meaning unchanged) and drops
clap-markdown's own fixed footer ('This document was generated
automatically by...') via MarkdownOptions::show_footer(false), since
that string isn't ours to reword and vale flagged it too.

docs/tools/{hivectl,swarmctl,forge}-cli.md are generated from each
crate's clap tree (see hive-forge/src/main.rs's MarkdownDocs verb) —
regenerated here from the fixed source, not hand-edited.

Refs #4549
2026-09-20 13:49:39 +02:00

113 lines
4.3 KiB
Rust

//! `reaction <number> [--comment <id>] [list|add|remove] [content]` —
//! list, add, or remove emoji reactions on an issue/PR or one of its
//! comments.
//!
//! Forgejo's reaction endpoints work on the shared issue/PR index (PRs
//! are issues internally, same as `dependency`) when no `--comment` is
//! given; `--comment <id>` redirects to the separate comment-reaction
//! endpoint pair, keyed on the comment's own id (not the parent
//! issue/PR number — `number` still has to be passed so this verb slots
//! into `issue <n> reaction` / `pr <n> reaction` like every other
//! generic verb, but it's otherwise unused on that path).
//!
//! `content` is Forgejo's reaction shortcode vocabulary (`+1`, `-1`,
//! `laugh`, `confused`, `heart`, `hooray`, `rocket`, `eyes`, …), not a
//! raw emoji character — same set the forge web UI's reaction picker
//! offers. `--list-allowed` prints the *actual* instance-configured
//! list (`GET /settings/ui`'s `allowed_reactions`) instead of leaving a
//! caller to guess it or learn it from a 403 — this is instance-global,
//! not issue/PR-scoped, so `number`/`--comment` are ignored when it's
//! set (the number is still required positionally, same as every other
//! generic verb, but unused on this path).
use anyhow::Result;
use clap::{Args as ClapArgs, Subcommand};
use forgejo_api::structs::EditReactionOption;
use crate::client::{Client, index};
use crate::verbs::{comment_reactions, issue_reactions, print_json};
#[derive(ClapArgs)]
pub struct Args {
/// Issue or PR number. Ignored (but still required) when you pass
/// `--list-allowed`.
pub(crate) number: u64,
/// Target a specific comment's reactions instead of the issue/PR
/// itself — the comment's own id (from `comments`/`comment-show`),
/// not its position in the thread.
#[arg(long)]
comment: Option<u64>,
/// Print the instance's actual configured reaction shortcodes
/// (`GET /settings/ui`) instead of listing/adding/removing —
/// instance-global, ignores `number`/`--comment`.
#[arg(long)]
pub(crate) list_allowed: bool,
#[command(subcommand)]
action: Option<Action>,
}
#[derive(Subcommand)]
enum Action {
/// List reactions (default when you give no action).
List,
/// Add a reaction — a Forgejo shortcode, for example `+1`, `heart`, `rocket`.
Add { content: String },
/// Remove your own reaction with this content.
Remove { content: String },
}
pub fn run(client: &Client, args: Args) -> Result<()> {
if args.list_allowed {
let settings = client.api().get_general_ui_settings().send()?;
return print_json(&serde_json::json!(
settings.allowed_reactions.unwrap_or_default()
));
}
let (owner, name) = client.owner_repo()?;
match args.action.unwrap_or(Action::List) {
Action::List => {}
Action::Add { content } => {
let body = EditReactionOption {
content: Some(content),
};
match args.comment {
Some(id) => {
client
.api()
.issue_post_comment_reaction(owner, name, index(id)?, body)
.send()?;
}
None => {
client
.api()
.issue_post_issue_reaction(owner, name, index(args.number)?, body)
.send()?;
}
}
}
Action::Remove { content } => {
let body = EditReactionOption {
content: Some(content),
};
match args.comment {
Some(id) => {
client
.api()
.issue_delete_comment_reaction(owner, name, index(id)?, body)
.send()?;
}
None => {
client
.api()
.issue_delete_issue_reaction(owner, name, index(args.number)?, body)
.send()?;
}
}
}
}
let reactions = match args.comment {
Some(id) => comment_reactions(client, owner, name, id)?,
None => issue_reactions(client, owner, name, args.number)?,
};
print_json(&serde_json::json!(reactions))
}