diff --git a/hive-forge/src/verbs/assign.rs b/hive-forge/src/verbs/assign.rs index f7a63592..00ab4593 100644 --- a/hive-forge/src/verbs/assign.rs +++ b/hive-forge/src/verbs/assign.rs @@ -60,6 +60,32 @@ pub fn run(client: &Client, args: Args) -> Result<()> { .iter() .filter_map(|u| u.login.as_deref()) .collect(); + // Verify the mutation actually landed. Forgejo silently drops an assignee + // change the caller isn't permitted to make (e.g. unassigning another + // user) and echoes back the *unchanged* list with a 200 — so trusting the + // success status reports a no-op as success. Diff the returned list + // against the intent and fail loudly instead. + let still_present = logins.iter().any(|&u| u == args.user); + if args.remove && still_present { + anyhow::bail!( + "assignee '{}' is still assigned to #{} after remove — the forge \ + rejected the change (likely insufficient permission to unassign \ + this user). current assignees: [{}]", + args.user, + args.number, + logins.join(", ") + ); + } + if !args.remove && !still_present { + anyhow::bail!( + "assignee '{}' is not assigned to #{} after add — the forge rejected \ + the change (the user may not exist or lack access to this repo). \ + current assignees: [{}]", + args.user, + args.number, + logins.join(", ") + ); + } print_json(&json!({ "number": resp.number, "assignees": logins,