Skip to main content

ephemeris_forge_github/plan/
webhooks.rs

1use ephemeris_forge::{Collection, FieldDiff, Limitation, NameSet, Report};
2
3use crate::Webhooks;
4use crate::api::model;
5use crate::operation::webhooks::Operation;
6
7const WEB: &str = "web";
8
9pub(super) fn plan(
10    config: Option<&Webhooks>,
11    live: &[model::Webhook],
12    report: &mut Report,
13) -> Vec<Operation> {
14    let Some(config) = config else {
15        return Vec::new();
16    };
17    for hook in live.iter().filter(|hook| hook.name != WEB) {
18        report.limitations.push(Limitation::WebhookKindLeftAlone {
19            id: hook.id,
20            kind: hook.name.clone(),
21        });
22    }
23    let managed: Vec<&model::Webhook> = live.iter().filter(|hook| hook.name == WEB).collect();
24    Collection {
25        noun: "webhook",
26        mode: config.mode,
27    }
28    .plan(
29        &config.webhooks,
30        &managed,
31        report,
32        |hook, url| hook.config.url.as_deref() == Some(url),
33        |url, desired, actual, report| {
34            let mut diff = FieldDiff::default();
35            let mut config_changed = diff.check(
36                "content_type",
37                actual.is_some_and(|actual| {
38                    actual.config.content_type.as_deref() == Some(desired.content_type.as_str())
39                }),
40                &actual.and_then(|actual| actual.config.content_type.as_deref()),
41                &desired.content_type,
42            );
43            config_changed |= diff.check(
44                "insecure_ssl",
45                actual.is_some_and(|actual| actual.config.insecure() == desired.insecure_ssl),
46                &actual.map(|actual| actual.config.insecure()),
47                &desired.insecure_ssl,
48            );
49            if config_changed && actual.is_some_and(|actual| actual.config.secret.is_some()) {
50                report.limitations.push(Limitation::WebhookSecretKept {
51                    url: url.to_owned(),
52                });
53                config_changed = false;
54            }
55            let mut changed = config_changed;
56            let events = actual.map(|actual| NameSet::new(actual.events.clone()));
57            changed |= diff
58                .want_set(
59                    "events",
60                    &NameSet::new(desired.events.clone()),
61                    events.as_ref(),
62                )
63                .is_some();
64            changed |= diff.compare(
65                "active",
66                actual.map(|actual| &actual.active),
67                &desired.active,
68            );
69            let url = url.to_owned();
70            let webhook = desired.clone();
71            let operation = match actual {
72                _ if !changed => None,
73                Some(actual) => Some(Operation::Update {
74                    url,
75                    id: actual.id,
76                    webhook,
77                    config_changed,
78                }),
79                None => Some(Operation::Create { url, webhook }),
80            };
81            (diff, operation.into_iter().collect())
82        },
83        |hook, _| {
84            let url = hook
85                .config
86                .url
87                .clone()
88                .unwrap_or_else(|| format!("#{}", hook.id));
89            Some((url.clone(), Operation::Delete { url, id: hook.id }))
90        },
91    )
92}