Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
feat: filter on originating node for an event
Merged liw opened 1 year ago

Add the Node(nid) event filter.

Add the from_node field to the BranchDeleted event so that it too can be filtered based on node.

Adjust debug logging for event filtering so that it reports the filtering decision.

Signed-off-by: Lars Wirzenius liw@liw.fi

4 files changed +86 -20 caf839b5 d537fd39
modified doc/userguide.md
@@ -76,11 +76,12 @@ A branch has been updated.

A branch has been deleted.

-
| Event           | fields              | field types |
-
|:----------------|:--------------------|:------------|
-
| `BranchDeleted` | `repo`              | `RepoId`    |
-
|                 | `branch`            | `RefString` |
-
|                 | `tip`               | ` Oid`      |
+
| Event           | fields      | field types |
+
|:----------------|:------------|:------------|
+
| `BranchDeleted` | `from_node` | `NodeId`    |
+
|                 | `repo`      | `RepoId`    |
+
|                 | `branch`    | `RefString` |
+
|                 | `tip`       | ` Oid`      |

## `PatchCreated`

@@ -114,6 +115,7 @@ Otherwise it is discarded and does not trigger a CI run.

| Condition       | Meaning                                                   |
|:----------------|:----------------------------------------------------------|
+
| `Node`          | Event originated from a specific node, identified by ID   |
| `Repository`    | Event refers to a specific repository, identified by ID   |
| `Branch`        | Event refers to a specific Git branch                     |
| `BranchCreated` | Branch was created                                        |
modified src/ci_event.rs
@@ -37,6 +37,7 @@ pub enum CiEventV1 {
        old_tip: Oid,
    },
    BranchDeleted {
+
        from_node: NodeId,
        repo: RepoId,
        branch: RefString,
        tip: Oid,
@@ -157,6 +158,7 @@ impl CiEvent {
                            }
                        }
                        RefUpdate::Deleted { name, oid } => CiEventV1::BranchDeleted {
+
                            from_node: *remote,
                            repo: *rid,
                            branch: branch(name, update)?,
                            tip: *oid,
@@ -402,8 +404,9 @@ mod test {
            Ok(events) if !events.is_empty() => {
                for e in events {
                    match e {
-
                        CiEvent::V1(CiEventV1::BranchDeleted { repo, branch, tip })
-
                            if repo == rid && branch == main && tip == oid => {}
+
                        CiEvent::V1(CiEventV1::BranchDeleted {
+
                            repo, branch, tip, ..
+
                        }) if repo == rid && branch == main && tip == oid => {}
                        _ => panic!("should not succeed that way"),
                    }
                }
modified src/filter.rs
@@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

-
use radicle::{cob::patch::PatchId, git::RefString, prelude::RepoId};
+
use radicle::{cob::patch::PatchId, git::RefString, node::NodeId, prelude::RepoId};
use radicle_git_ext::Oid;

use crate::{
@@ -38,6 +38,9 @@ pub enum EventFilter {
    /// Patch was updated,
    PatchUpdated,

+
    /// Change originated from specific node.
+
    Node(NodeId),
+

    /// Allow any event.
    Allow,

@@ -56,7 +59,6 @@ pub enum EventFilter {

impl EventFilter {
    pub fn allows(&self, event: &CiEvent) -> bool {
-
        logger::debug2(format!("EventFilter::allows: event={event:?}"));
        match self {
            Self::Allow => return true,
            Self::Deny => return false,
@@ -66,39 +68,75 @@ impl EventFilter {
            _ => (),
        }

-
        match event {
+
        let decision = match event {
            CiEvent::V1(CiEventV1::Shutdown) => true,
-
            CiEvent::V1(CiEventV1::BranchCreated { repo, branch, .. }) => match self {
+
            CiEvent::V1(CiEventV1::BranchCreated {
+
                from_node,
+
                repo,
+
                branch,
+
                ..
+
            }) => match self {
+
                Self::Node(wantedc) => from_node == wantedc,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
                Self::BranchCreated => true,
                _ => false,
            },
-
            CiEvent::V1(CiEventV1::BranchUpdated { repo, branch, .. }) => match self {
+
            CiEvent::V1(CiEventV1::BranchUpdated {
+
                from_node,
+
                repo,
+
                branch,
+
                ..
+
            }) => match self {
+
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
                Self::BranchUpdated => true,
                _ => false,
            },
-
            CiEvent::V1(CiEventV1::BranchDeleted { repo, branch, .. }) => match self {
+
            CiEvent::V1(CiEventV1::BranchDeleted {
+
                from_node,
+
                repo,
+
                branch,
+
                ..
+
            }) => match self {
+
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
                Self::BranchDeleted => true,
                _ => false,
            },
-
            CiEvent::V1(CiEventV1::PatchCreated { repo, patch, .. }) => match self {
+
            CiEvent::V1(CiEventV1::PatchCreated {
+
                from_node,
+
                repo,
+
                patch,
+
                ..
+
            }) => match self {
+
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Patch(wanted) => *patch == PatchId::from(wanted),
                Self::PatchCreated => true,
                _ => false,
            },
-
            CiEvent::V1(CiEventV1::PatchUpdated { repo, patch, .. }) => match self {
+
            CiEvent::V1(CiEventV1::PatchUpdated {
+
                from_node,
+
                repo,
+
                patch,
+
                ..
+
            }) => match self {
+
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Patch(wanted) => *patch == PatchId::from(wanted),
                Self::PatchUpdated => true,
                _ => false,
            },
-
        }
+
        };
+

+
        logger::debug2(format!(
+
            "EventFilter::allows: decision={decision} event={event:?}"
+
        ));
+

+
        decision
    }

    pub fn from_file(filename: &Path) -> Result<Vec<Self>, FilterError> {
@@ -132,6 +170,10 @@ mod test {
        Did::decode("did:key:z6MkgEMYod7Hxfy9qCvDv5hYHkZ4ciWmLFgfvm3Wn1b2w2FV").unwrap()
    }

+
    fn other_did() -> Did {
+
        Did::decode("did:key:z6MkfXa53s1ZSFy8rktvyXt5ADCojnxvjAoQpzajaXyLqG5n").unwrap()
+
    }
+

    fn rid() -> RepoId {
        const RID: &str = "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5";
        RepoId::from_urn(RID).unwrap()
@@ -194,7 +236,12 @@ mod test {
                tip,
                old_tip,
            }),
-
            CiEvent::V1(CiEventV1::BranchDeleted { repo, branch, tip }),
+
            CiEvent::V1(CiEventV1::BranchDeleted {
+
                from_node: did.into(),
+
                repo,
+
                branch,
+
                tip,
+
            }),
            CiEvent::V1(CiEventV1::PatchCreated {
                from_node: did.into(),
                repo,
@@ -461,6 +508,20 @@ mod test {
    }

    #[test]
+
    fn allows_all_for_right_node() {
+
        let filter = EventFilter::Node(*did());
+
        let events = all_events(did(), rid(), refstring("main"), patch_id(), oid(), oid());
+
        assert!(events.iter().all(|e| filter.allows(e)));
+
    }
+

+
    #[test]
+
    fn allows_none_for_wrong_node() {
+
        let filter = EventFilter::Node(*other_did());
+
        let events = all_events(did(), rid(), refstring("main"), patch_id(), oid(), oid());
+
        assert!(!events.iter().any(|e| filter.allows(e)));
+
    }
+

+
    #[test]
    fn allows_any_event() {
        let filter = EventFilter::Allow;

modified src/pages.rs
@@ -196,9 +196,9 @@ impl PageData {
                    tip,
                    old_tip: _,
                }) => render_event(repo, branch, tip),
-
                CiEvent::V1(CiEventV1::BranchDeleted { repo, branch, tip }) => {
-
                    render_event(repo, branch, tip)
-
                }
+
                CiEvent::V1(CiEventV1::BranchDeleted {
+
                    repo, branch, tip, ..
+
                }) => render_event(repo, branch, tip),
                CiEvent::V1(CiEventV1::PatchCreated {
                    from_node: _,
                    repo,