mirror of
https://seed.radicle.dev/rad:zwTxygwuz5LDGBq255RA2CbNGrz8.git
synced 2026-10-18 19:30:29 +08:00
feat: HasFile event filter predicte
Signed-off-by: Lars Wirzenius <liw@liw.fi>
This commit is contained in:
@@ -236,6 +236,8 @@ The Git repository must exist.
|
||||
~~~scenario
|
||||
then directory reppy exists
|
||||
then directory reppy/.git exists
|
||||
then file reppy/file.dat exists
|
||||
then file reppy/foobar does not exist
|
||||
when I run, in reppy, git show
|
||||
then stdout matches regex ^commit
|
||||
~~~
|
||||
@@ -1230,6 +1232,53 @@ triggers:
|
||||
~~~
|
||||
|
||||
|
||||
## Filter predicate `HasFile`
|
||||
|
||||
_Want:_ We can allow an event if its commit contains a file or
|
||||
directory by this name.
|
||||
|
||||
_Why:_ This is so that the user can choose a suitable adapter.
|
||||
|
||||
~~~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-hasfile-missing.yaml
|
||||
when I run cibtool --db ci-broker.db event add --repo xyzzy --ref main --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 doesn't contain "main"
|
||||
|
||||
given file config.yaml from filter-hasfile.yaml
|
||||
when I run cibtool --db ci-broker.db event add --repo xyzzy --ref main --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"
|
||||
~~~
|
||||
|
||||
~~~{#filter-hasfile.yaml .file .json}
|
||||
db: ci-broker.db
|
||||
adapters:
|
||||
default:
|
||||
command: ./adapter.sh
|
||||
triggers:
|
||||
- adapter: default
|
||||
filters:
|
||||
- !HasFile "file.dat"
|
||||
~~~
|
||||
|
||||
~~~{#filter-hasfile-missing.yaml .file .json}
|
||||
db: ci-broker.db
|
||||
adapters:
|
||||
default:
|
||||
command: ./adapter.sh
|
||||
triggers:
|
||||
- adapter: default
|
||||
filters:
|
||||
- !HasFile "does-not-exist"
|
||||
~~~
|
||||
|
||||
|
||||
# Acceptance criteria for test tooling
|
||||
|
||||
The event synthesizer is a helper to feed the CI broker node events in
|
||||
|
||||
+43
-3
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use radicle::{
|
||||
cob::patch::PatchId,
|
||||
git::RefString,
|
||||
git::{raw::ObjectType, RefString},
|
||||
node::NodeId,
|
||||
prelude::{Profile, RepoId},
|
||||
storage::git::Repository,
|
||||
@@ -79,6 +79,9 @@ pub enum EventFilter {
|
||||
/// Change originated from specific node.
|
||||
Node(NodeId),
|
||||
|
||||
/// Commit in change contains a file or directory with this name.
|
||||
HasFile(PathBuf),
|
||||
|
||||
/// Allow any event.
|
||||
Allow,
|
||||
|
||||
@@ -117,19 +120,21 @@ impl EventFilter {
|
||||
from_node,
|
||||
repo,
|
||||
branch,
|
||||
..
|
||||
tip,
|
||||
}) => match self {
|
||||
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,
|
||||
Self::HasFile(wanted) => has_file(repo, tip, wanted),
|
||||
_ => false,
|
||||
},
|
||||
CiEvent::V1(CiEventV1::BranchUpdated {
|
||||
from_node,
|
||||
repo,
|
||||
branch,
|
||||
tip,
|
||||
..
|
||||
}) => match self {
|
||||
Self::Node(wanted) => from_node == wanted,
|
||||
@@ -137,43 +142,49 @@ impl EventFilter {
|
||||
Self::Branch(wanted) => branch == wanted,
|
||||
Self::DefaultBranch => is_default_branch(repo, branch),
|
||||
Self::BranchUpdated => true,
|
||||
Self::HasFile(wanted) => has_file(repo, tip, wanted),
|
||||
_ => false,
|
||||
},
|
||||
CiEvent::V1(CiEventV1::BranchDeleted {
|
||||
from_node,
|
||||
repo,
|
||||
branch,
|
||||
..
|
||||
tip,
|
||||
}) => match self {
|
||||
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,
|
||||
Self::HasFile(wanted) => has_file(repo, tip, wanted),
|
||||
_ => false,
|
||||
},
|
||||
CiEvent::V1(CiEventV1::PatchCreated {
|
||||
from_node,
|
||||
repo,
|
||||
patch,
|
||||
new_tip,
|
||||
..
|
||||
}) => match self {
|
||||
Self::Node(wanted) => from_node == wanted,
|
||||
Self::Repository(wanted) => repo == wanted,
|
||||
Self::Patch(wanted) => *patch == PatchId::from(wanted),
|
||||
Self::PatchCreated => true,
|
||||
Self::HasFile(wanted) => has_file(repo, new_tip, wanted),
|
||||
_ => false,
|
||||
},
|
||||
CiEvent::V1(CiEventV1::PatchUpdated {
|
||||
from_node,
|
||||
repo,
|
||||
patch,
|
||||
new_tip,
|
||||
..
|
||||
}) => match self {
|
||||
Self::Node(wanted) => from_node == wanted,
|
||||
Self::Repository(wanted) => repo == wanted,
|
||||
Self::Patch(wanted) => *patch == PatchId::from(wanted),
|
||||
Self::PatchUpdated => true,
|
||||
Self::HasFile(wanted) => has_file(repo, new_tip, wanted),
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
@@ -212,6 +223,35 @@ fn get_default_branch(repo_id: &RepoId) -> Result<String, Box<dyn std::error::Er
|
||||
Ok(def)
|
||||
}
|
||||
|
||||
fn has_file(repo_id: &RepoId, oid: &Oid, filename: &Path) -> bool {
|
||||
fn helper(
|
||||
repo_id: &RepoId,
|
||||
oid: Oid,
|
||||
filename: &Path,
|
||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
let profile = Profile::load()?;
|
||||
let repo = Repository::open(profile.storage.path().join(repo_id.canonical()), *repo_id)?;
|
||||
|
||||
let obj = repo.backend.find_object(*oid, Some(ObjectType::Commit))?;
|
||||
let commit = if let Ok(commit) = obj.into_commit() {
|
||||
commit
|
||||
} else {
|
||||
return Ok(false);
|
||||
};
|
||||
let tree = commit.tree()?;
|
||||
let entry = if let Ok(entry) = tree.get_path(filename) {
|
||||
entry
|
||||
} else {
|
||||
return Ok(false);
|
||||
};
|
||||
let obj = entry.to_object(&repo.backend)?;
|
||||
let ok = obj.into_blob().is_ok();
|
||||
Ok(ok)
|
||||
}
|
||||
|
||||
helper(repo_id, *oid, filename).unwrap_or(false)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Filters {
|
||||
filters: Vec<EventFilter>,
|
||||
|
||||
Reference in New Issue
Block a user