gitee_cli_rs/api/
webhooks.rs1use super::client::Client;
2use crate::error::{GiteeError, Result};
3use crate::models::Webhook;
4use crate::repo::Repo;
5
6pub const EVENT_FLAGS: &[&str] = &[
7 "push_events",
8 "tag_push_events",
9 "issues_events",
10 "merge_requests_events",
11 "pull_requests_events", "note_events",
13];
14
15pub struct Webhooks<'a> {
16 client: &'a Client,
17 repo: &'a Repo,
18}
19
20pub struct CreateWebhook<'a> {
21 pub url: &'a str,
22 pub password: Option<&'a str>,
23 pub push_events: bool,
24 pub tag_push_events: bool,
25 pub issues_events: bool,
26 pub merge_requests_events: bool,
27 pub note_events: bool,
28}
29
30pub fn parse_events(raw: &[String]) -> Result<Vec<String>> {
33 let joined = join_flags(raw).unwrap_or_default();
34 if joined.is_empty() {
35 return Ok(vec!["push_events".into()]);
36 }
37 let mut out = Vec::new();
38 for ev in joined.split(',') {
39 let ev = ev.trim();
40 if !EVENT_FLAGS.contains(&ev) {
41 return Err(GiteeError::Usage(format!(
42 "unknown webhook event '{ev}'; expected one of {}",
43 EVENT_FLAGS.join(", ")
44 )));
45 }
46 if !out.iter().any(|e| e == ev) {
47 out.push(ev.to_string());
48 }
49 }
50 Ok(out)
51}
52
53pub fn event_bools(events: &[String]) -> (bool, bool, bool, bool, bool) {
55 (
56 events.iter().any(|e| e == "push_events"),
57 events.iter().any(|e| e == "tag_push_events"),
58 events.iter().any(|e| e == "issues_events"),
59 events.iter().any(|e| {
60 e == "merge_requests_events" || e == "pull_requests_events"
61 }),
62 events.iter().any(|e| e == "note_events"),
63 )
64}
65
66fn join_flags(values: &[String]) -> Option<String> {
67 if values.is_empty() {
68 return None;
69 }
70 Some(
71 values
72 .iter()
73 .flat_map(|v| v.split(','))
74 .map(str::trim)
75 .filter(|s| !s.is_empty())
76 .collect::<Vec<_>>()
77 .join(","),
78 )
79}
80
81impl Webhooks<'_> {
82 pub(crate) fn new<'a>(client: &'a Client, repo: &'a Repo) -> Webhooks<'a> {
83 Webhooks { client, repo }
84 }
85
86 pub fn list(&self, limit: usize) -> Result<Vec<Webhook>> {
87 let (o, r) = (&self.repo.owner, &self.repo.name);
88 self.client
89 .get_paged(&format!("/repos/{o}/{r}/hooks"), &[], limit)
90 }
91
92 pub fn create(&self, req: &CreateWebhook<'_>) -> Result<Webhook> {
93 let (o, r) = (&self.repo.owner, &self.repo.name);
94 let mut form: Vec<(&str, &str)> = vec![
95 ("url", req.url),
96 ("push_events", Client::bool_str(req.push_events)),
97 ("tag_push_events", Client::bool_str(req.tag_push_events)),
98 ("issues_events", Client::bool_str(req.issues_events)),
99 (
100 "merge_requests_events",
101 Client::bool_str(req.merge_requests_events),
102 ),
103 ("note_events", Client::bool_str(req.note_events)),
104 ];
105 if let Some(password) = req.password {
106 form.push(("password", password));
107 }
108 self.client
109 .post(&format!("/repos/{o}/{r}/hooks"), &form)
110 }
111
112 pub fn delete(&self, id: i64) -> Result<()> {
113 let (o, r) = (&self.repo.owner, &self.repo.name);
114 self.client
115 .delete_ok(&format!("/repos/{o}/{r}/hooks/{id}"))
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn parse_events_defaults_to_push() {
125 assert_eq!(parse_events(&[]).unwrap(), vec!["push_events"]);
126 }
127
128 #[test]
129 fn parse_events_accepts_pull_requests_alias() {
130 let events = parse_events(&["pull_requests_events".into()]).unwrap();
131 assert_eq!(events, vec!["pull_requests_events"]);
132 let (push, tag, issues, merge, note) = event_bools(&events);
133 assert!(!push);
134 assert!(!tag);
135 assert!(!issues);
136 assert!(merge);
137 assert!(!note);
138 }
139
140 #[test]
141 fn parse_events_rejects_unknown() {
142 assert!(parse_events(&["bogus".into()]).is_err());
143 }
144}