Watch
0
0
Fork
You've already forked hyperhive
0

docs: notification flows, their API and the notifications page

This commit is contained in:
atlas 2026-10-24 04:05:05 +02:00 • committed by mara
commit 7795da44f8
9 changed files with 140 additions and 59 deletions

View file

@ -42,7 +42,12 @@ pub const MAX_TEXT: usize = 500;
/// The forge event types a source node can start from: the ones
/// swarm-controller's hooks deliver to the events stream.
pub const SOURCE_EVENTS: &[&str] = &["issues", "issue_assign", "pull_request", "pull_request_assign"];
pub const SOURCE_EVENTS: &[&str] = &[
"issues",
"issue_assign",
"pull_request",
"pull_request_assign",
];
/// The fields of an event a condition or a recipient can name.
pub const FIELDS: &[&str] = &[
@ -204,8 +209,8 @@ impl Document {
/// Not the expected shape, or a [`Document::version`] this build does not
/// know. The reader keeps what it had.
pub fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
let value: serde_json::Value =
serde_json::from_slice(bytes).map_err(|e| DecodeError::Malformed(format!("not JSON: {e}")))?;
let value: serde_json::Value = serde_json::from_slice(bytes)
.map_err(|e| DecodeError::Malformed(format!("not JSON: {e}")))?;
if let Some(found) = value.get("version")
&& found != VERSION
{
@ -225,15 +230,14 @@ impl Document {
return Err(format!("version {} is not {VERSION}", self.version));
}
if self.flows.len() > MAX_FLOWS {
return Err(format!(
"{} flows, more than {MAX_FLOWS}",
self.flows.len()
));
return Err(format!("{} flows, more than {MAX_FLOWS}", self.flows.len()));
}
let builtin = builtins();
for id in &self.disabled_builtins {
if !builtin.iter().any(|b| b.id == *id) {
return Err(format!("disabled_builtins names {id}, which is no built-in flow"));
return Err(format!(
"disabled_builtins names {id}, which is no built-in flow"
));
}
}
let mut ids: BTreeSet<&str> = builtin.iter().map(|b| b.id.as_str()).collect();
@ -244,7 +248,8 @@ impl Document {
flow.id
));
}
flow.validate().map_err(|why| format!("flow {}: {why}", flow.id))?;
flow.validate()
.map_err(|why| format!("flow {}: {why}", flow.id))?;
}
Ok(())
}
@ -401,7 +406,10 @@ impl NodeKind {
}
Self::Match { when } => {
if let Some(bad) = when.iter().find(|c| !is_field(&c.field)) {
return Err(format!("condition on {:?}, which is no event field", bad.field));
return Err(format!(
"condition on {:?}, which is no event field",
bad.field
));
}
}
Self::Todo(sink) => sink.validate()?,
@ -534,7 +542,10 @@ mod tests {
}
fn builtin(id: &str) -> Flow {
builtins().into_iter().find(|f| f.id == id).expect("a built-in")
builtins()
.into_iter()
.find(|f| f.id == id)
.expect("a built-in")
}
/// A custom flow: opened issue or PR → a todo for `triage`.
@ -704,7 +715,12 @@ mod tests {
);
let mut bad = custom("bad");
bad.edges.pop();
assert!(doc(&[], vec![bad]).check().unwrap_err().starts_with("flow bad:"));
assert!(
doc(&[], vec![bad])
.check()
.unwrap_err()
.starts_with("flow bad:")
);
let many = (0..=MAX_FLOWS).map(|i| custom(&format!("f{i}"))).collect();
assert!(doc(&[], many).check().is_err(), "flow count");
let mut old = doc(&[], vec![]);