Watch
0
0
Fork
You've already forked hyperhive
0

hive-forge: drop subscription --ignore entirely — Forgejo only has watch/unwatch

This commit is contained in:
damocles 2026-10-09 12:44:46 +02:00 • committed by mara
commit d11c9537b6
2 changed files with 13 additions and 75 deletions

View file

@ -1,7 +1,12 @@
//! `subscription [--watch|--ignore|--unwatch|--list] [repo]` — get or
//! set the current user's watch subscription for a repo, or list every
//! repo the user watches (`--list`, for auditing the notification
//! firehose).
//! `subscription [--watch|--unwatch|--list] [repo]` — get or set the
//! current user's watch subscription for a repo, or list every repo the
//! user watches (`--list`, for auditing the notification firehose).
//!
//! There is deliberately no `--ignore`: Forgejo's subscription endpoint
//! has no way to mark a repo ignored without also watching it (its PUT
//! takes no body), so a mute flag here can only ever be subscribe or
//! unsubscribe under the hood. Rather than keep a flag that refuses with
//! an error, this verb just exposes the two states Forgejo actually has.
use anyhow::Result;
use clap::Args as ClapArgs;
@ -11,21 +16,11 @@ use crate::client::{Client, is_not_found};
use crate::verbs::print_json;
#[derive(ClapArgs)]
#[allow(
clippy::struct_excessive_bools,
reason = "mutually-exclusive clap action flags (group = \"action\"); an \
enum would drop the --watch/--ignore/--unwatch/--list flag \
ergonomics agents already use"
)]
pub struct Args {
/// Subscribe (watch the repo).
#[arg(long, group = "action")]
watch: bool,
/// Unsupported: Forgejo's subscription endpoint can't mark a repo
/// ignored without also watching it. Always refuses with an error.
#[arg(long, group = "action")]
ignore: bool,
/// Unsubscribe (clear watch + ignore).
/// Unsubscribe (stop watching).
#[arg(long, group = "action")]
unwatch: bool,
/// List every repo the current user watches (ignores `[repo]`).
@ -33,39 +28,14 @@ pub struct Args {
list: bool,
}
/// Refuse `--ignore`. Forgejo's PUT subscription endpoint takes no body —
/// it always subscribes (watch), with no way to mark a repo ignored
/// without also watching it. The old raw client sent a
/// `{subscribed, ignored}` body which the server ignored, so `--ignore`
/// silently behaved like `--watch` (the opposite of what it promises)
/// instead of failing. Refuse instead of lying about what happened. A
/// free function (rather than inlined in `run`) so the refusal itself —
/// not just a string constant — is unit-testable without a real `Client`:
/// it fires before any API call is made.
///
/// # Errors
/// Always errors when `args.ignore` is set; otherwise always `Ok`.
fn reject_ignore(args: &Args) -> Result<()> {
if args.ignore {
anyhow::bail!(
"subscription --ignore is not supported: Forgejo's subscription \
endpoint has no way to mark a repo ignored without also \
watching it. Use --unwatch to stop watching, or --watch if \
muted-but-watched is what you actually want."
);
}
Ok(())
}
/// Run the `subscription` verb: `--list` all watched repos, set the
/// current repo's watch (`--watch` / `--ignore` / `--unwatch`), or get
/// its current state.
/// current repo's watch (`--watch` / `--unwatch`), or get its current
/// state.
///
/// # Errors
/// Propagates transport / non-2xx errors from the Forgejo client calls
/// and from `print_json`.
pub fn run(client: &Client, args: Args) -> Result<()> {
reject_ignore(&args)?;
if args.list {
// List every repo the authed user watches, so an agent can audit
// its notification firehose and decide what to `--unwatch`. Not
@ -123,34 +93,3 @@ pub fn run(client: &Client, args: Args) -> Result<()> {
Err(e) => Err(e.into()),
}
}
#[cfg(test)]
mod tests {
use super::{Args, reject_ignore};
#[test]
fn ignore_is_rejected_pointing_at_unwatch() {
let args = Args {
watch: false,
ignore: true,
unwatch: false,
list: false,
};
let err = reject_ignore(&args).expect_err("--ignore must be refused");
let msg = err.to_string();
assert!(msg.contains("--unwatch"));
assert!(msg.contains("--watch"));
assert!(msg.contains("not supported"));
}
#[test]
fn watch_is_not_rejected() {
let args = Args {
watch: true,
ignore: false,
unwatch: false,
list: false,
};
assert!(reject_ignore(&args).is_ok());
}
}