Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
feat: add predicate DefaultBranch
Merged liw opened 1 year ago

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

refactor(src/filter.rs): rename local variable to avoid typo

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

2 files changed +83 -2 14ad23cc 74097d60
modified ci-broker.md
@@ -1194,6 +1194,42 @@ triggers:
~~~


+
## Filter predicate `DefaultBranch`
+

+
_Want:_ We can allow an event if the event refers to the default
+
branch.
+

+
_Why:_ This is so that the user doesn't need to spell out the name
+
explicitly.
+

+
~~~scenario
+
given a Radicle node, with CI configured with broker.yaml and adapter dummy.sh
+
given a Git repository xyzzy in the Radicle node
+

+
given file config.yaml from filter-defaultbranch.yaml
+

+
when I run cibtool --db ci-broker.db event add --repo xyzzy --ref main --commit HEAD --kind branch-created
+
when I run cibtool --db ci-broker.db event add --repo xyzzy --ref oksa --commit HEAD --kind branch-created
+

+
when I run ./env.sh cib --config config.yaml queued
+

+
when I run cibtool --db ci-broker.db run list --json
+
then stdout contains "main"
+
then stdout doesn't contain "oksa"
+
~~~
+

+
~~~{#filter-defaultbranch.yaml .file .json}
+
db: ci-broker.db
+
adapters:
+
  default:
+
    command: ./adapter.sh
+
triggers:
+
  - adapter: default
+
    filters:
+
      - !DefaultBranch
+
~~~
+

+

# Acceptance criteria for test tooling

The event synthesizer is a helper to feed the CI broker node events in
modified src/filter.rs
@@ -2,7 +2,13 @@ use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

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

use crate::{
@@ -49,6 +55,9 @@ pub enum EventFilter {
    /// Event is for a specific branch.
    Branch(RefString),

+
    /// Event if for the default branch for the repository.
+
    DefaultBranch,
+

    /// Branch was created.
    BranchCreated,

@@ -110,9 +119,10 @@ impl EventFilter {
                branch,
                ..
            }) => match self {
-
                Self::Node(wantedc) => from_node == wantedc,
+
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
+
                Self::DefaultBranch => is_default_branch(repo, branch),
                Self::BranchCreated => true,
                _ => false,
            },
@@ -125,6 +135,7 @@ impl EventFilter {
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
+
                Self::DefaultBranch => is_default_branch(repo, branch),
                Self::BranchUpdated => true,
                _ => false,
            },
@@ -137,6 +148,7 @@ impl EventFilter {
                Self::Node(wanted) => from_node == wanted,
                Self::Repository(wanted) => repo == wanted,
                Self::Branch(wanted) => branch == wanted,
+
                Self::DefaultBranch => is_default_branch(repo, branch),
                Self::BranchDeleted => true,
                _ => false,
            },
@@ -176,6 +188,39 @@ impl EventFilter {
    }
}

+
fn is_default_branch(repo_id: &RepoId, wanted: &str) -> bool {
+
    let res = get_default_branch(repo_id);
+
    logger::debug2(format!("is_default_branch: res={res:?}"));
+
    if let Ok(actual) = res {
+
        logger::debug2(format!(
+
            "is_default_branch: actual={actual} wanted={wanted}"
+
        ));
+
        actual == wanted
+
    } else {
+
        logger::debug("is_default_branch: could not get actual");
+
        false
+
    }
+
}
+

+
fn get_default_branch(repo_id: &RepoId) -> Result<String, Box<dyn std::error::Error>> {
+
    let profile = Profile::load()?;
+
    logger::debug("loaded profile");
+
    let path = profile.storage.path().join(repo_id.canonical());
+
    logger::debug2(format!("path={}", path.display()));
+
    let repo = Repository::open(path, *repo_id)?;
+
    logger::debug("loaded repo");
+
    let proj = repo.project()?;
+
    logger::debug("loaded project");
+

+
    let def = format!(
+
        "{}/refs/heads/{}",
+
        profile.id().to_namespace(),
+
        proj.default_branch()
+
    );
+

+
    Ok(def)
+
}
+

#[derive(Deserialize)]
struct Filters {
    filters: Vec<EventFilter>,