summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2024-03-05 18:01:57 +0200
committerLars Wirzenius <liw@liw.fi>2024-03-05 18:01:57 +0200
commitfee8700dc8d1845c7c8c55e0fd2dd99b29d3efe6 (patch)
treeffae19fdb494dd7093849f23cb5eb5ddf51363c9
parent65c2cbfd92534a1de6907feae1b9aaa6072700dc (diff)
downloadradicle-ci-broker-fee8700dc8d1845c7c8c55e0fd2dd99b29d3efe6.tar.gz
feat: add a RequestBuilder to create Request messages
A builder interface is easier to use I find. Signed-off-by: Lars Wirzenius <liw@liw.fi>
-rw-r--r--src/bin/broker-messages.rs8
-rw-r--r--src/bin/ci-broker.rs7
-rw-r--r--src/msg.rs148
-rw-r--r--src/test.rs7
4 files changed, 110 insertions, 60 deletions
diff --git a/src/bin/broker-messages.rs b/src/bin/broker-messages.rs
index 8e47ee1..deb3112 100644
--- a/src/bin/broker-messages.rs
+++ b/src/bin/broker-messages.rs
@@ -2,7 +2,7 @@ use radicle::git::RefString;
use radicle::Profile;
use radicle_ci_broker::{
event::BrokerEvent,
- msg::{Oid, RepoId, Request, Response, RunId, RunResult},
+ msg::{Oid, RepoId, RequestBuilder, Response, RunId, RunResult},
};
fn main() {
@@ -17,7 +17,11 @@ fn main() {
old: None,
};
let profile = Profile::load().expect("create profile");
- let trigger = Request::trigger(&profile, &be).expect("create trigger");
+ let trigger = RequestBuilder::default()
+ .profile(&profile)
+ .broker_event(&be)
+ .build_trigger()
+ .expect("create trigger");
println!("Trigger request:\n{}\n", trigger);
let triggered = Response::triggered(RunId::from("any-string-works-as-run-id"));
diff --git a/src/bin/ci-broker.rs b/src/bin/ci-broker.rs
index 9ea58ff..d8cf766 100644
--- a/src/bin/ci-broker.rs
+++ b/src/bin/ci-broker.rs
@@ -14,7 +14,7 @@ use radicle_ci_broker::{
config::Config,
error::BrokerError,
event::NodeEventSource,
- msg::Request,
+ msg::RequestBuilder,
pages::{PageBuilder, StatusPage},
};
@@ -101,7 +101,10 @@ fn fallible_main() -> Result<(), BrokerError> {
for e in source.event()? {
page.broker_event(&e);
debug!("broker event {e:#?}");
- let req = Request::trigger(&profile, &e)?;
+ let req = RequestBuilder::default()
+ .profile(&profile)
+ .broker_event(&e)
+ .build_trigger()?;
broker.execute_ci(&req, &mut page)?;
}
}
diff --git a/src/msg.rs b/src/msg.rs
index 63fdccf..067faa2 100644
--- a/src/msg.rs
+++ b/src/msg.rs
@@ -95,62 +95,31 @@ impl fmt::Display for RunResult {
}
}
-/// A request message sent by the broker to its adapter child process.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(tag = "request")]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum Request {
- /// Trigger a run.
- Trigger {
- /// Common fields for all message variants.
- #[serde(flatten)]
- common: EventCommonFields,
-
- /// The push event, if any.
- #[serde(flatten)]
- push: Option<PushEvent>,
-
- /// The patch event, if any.
- #[serde(flatten)]
- patch: Option<PatchEvent>,
- },
+/// Build a [`Request`].
+#[derive(Debug, Default)]
+pub struct RequestBuilder<'a> {
+ profile: Option<&'a Profile>,
+ event: Option<&'a BrokerEvent>,
}
-impl Request {
- /// Repository that the event concerns.
- pub fn repo(&self) -> RepoId {
- match self {
- Self::Trigger {
- common,
- push: _,
- patch: _,
- } => common.repository.id,
- }
+impl<'a> RequestBuilder<'a> {
+ /// Set the node profile to use.
+ pub fn profile(mut self, profile: &'a Profile) -> Self {
+ self.profile = Some(profile);
+ self
}
- /// Return the commit the event concerns. In other words, the
- /// commit that CI should run against.
- pub fn commit(&self) -> Oid {
- match self {
- Self::Trigger {
- common: _,
- push,
- patch,
- } => {
- if let Some(push) = push {
- *push.commits.last().unwrap()
- } else if let Some(patch) = patch {
- *patch.patch.commits.last().unwrap()
- } else {
- panic!("neither push not panic: {self:#?}");
- }
- }
- }
+ /// Set the broker event to use.
+ pub fn broker_event(mut self, event: &'a BrokerEvent) -> Self {
+ self.event = Some(event);
+ self
}
- /// Create a request event to trigger a run.
- pub fn trigger(profile: &Profile, event: &BrokerEvent) -> Result<Self, MessageError> {
+ /// Create a [`Request::Trigger`] message.
+ pub fn build_trigger(self) -> Result<Request, MessageError> {
+ let profile = self.profile.ok_or(MessageError::NoProfile)?;
+ let event = self.event.ok_or(MessageError::NoEvent)?;
+
let BrokerEvent::RefChanged {
rid,
name,
@@ -268,12 +237,67 @@ impl Request {
},
};
- Ok(Self::Trigger {
+ Ok(Request::Trigger {
common,
push: push_info,
patch: patch_info,
})
}
+}
+
+/// A request message sent by the broker to its adapter child process.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(tag = "request")]
+#[serde(rename_all = "snake_case")]
+#[non_exhaustive]
+pub enum Request {
+ /// Trigger a run.
+ Trigger {
+ /// Common fields for all message variants.
+ #[serde(flatten)]
+ common: EventCommonFields,
+
+ /// The push event, if any.
+ #[serde(flatten)]
+ push: Option<PushEvent>,
+
+ /// The patch event, if any.
+ #[serde(flatten)]
+ patch: Option<PatchEvent>,
+ },
+}
+
+impl Request {
+ /// Repository that the event concerns.
+ pub fn repo(&self) -> RepoId {
+ match self {
+ Self::Trigger {
+ common,
+ push: _,
+ patch: _,
+ } => common.repository.id,
+ }
+ }
+
+ /// Return the commit the event concerns. In other words, the
+ /// commit that CI should run against.
+ pub fn commit(&self) -> Oid {
+ match self {
+ Self::Trigger {
+ common: _,
+ push,
+ patch,
+ } => {
+ if let Some(push) = push {
+ *push.commits.last().unwrap()
+ } else if let Some(patch) = patch {
+ *patch.patch.commits.last().unwrap()
+ } else {
+ panic!("neither push not panic: {self:#?}");
+ }
+ }
+ }
+ }
/// Serialize the request as a single-line JSON, including the
/// newline. This is meant for the broker to use.
@@ -547,6 +571,14 @@ impl Response {
/// All possible errors from the CI broker messages.
#[derive(Debug, thiserror::Error)]
pub enum MessageError {
+ /// [`RequestBuilder`] does not have profile set.
+ #[error("RequestBuilder must have profile set")]
+ NoProfile,
+
+ /// [`RequestBuilder`] does not have event set.
+ #[error("RequestBuilder must have broker event set")]
+ NoEvent,
+
/// Failed to serialize a request message as JSON. This should
/// never happen and likely indicates a programming failure.
#[error("failed to serialize a request into JSON to a file handle")]
@@ -606,7 +638,7 @@ pub enum MessageError {
#[cfg(test)]
pub mod tests {
use crate::event::BrokerEvent;
- use crate::msg::Request;
+ use crate::msg::{Request, RequestBuilder};
use radicle::git::raw::Oid;
use radicle::git::RefString;
use radicle::patch::{MergeTarget, Patches};
@@ -637,7 +669,11 @@ pub mod tests {
old: Some(repo_head),
};
- let req = Request::trigger(&profile, &be).expect("expect request trigger");
+ let req = RequestBuilder::default()
+ .profile(&profile)
+ .broker_event(&be)
+ .build_trigger()
+ .unwrap();
let Request::Trigger {
common,
push,
@@ -702,7 +738,11 @@ pub mod tests {
old: None,
};
- let req = Request::trigger(&profile, &be)?;
+ let req = RequestBuilder::default()
+ .profile(&profile)
+ .broker_event(&be)
+ .build_trigger()
+ .unwrap();
let Request::Trigger {
common,
push,
diff --git a/src/test.rs b/src/test.rs
index f1e1bdd..7d1f9c1 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -6,7 +6,7 @@ use std::{
use crate::adapter::Adapter;
use crate::event::BrokerEvent;
-use crate::msg::Request;
+use crate::msg::{Request, RequestBuilder};
use radicle::crypto::ssh::Keystore;
use radicle::crypto::test::signer::MockSigner;
use radicle::crypto::Signer;
@@ -77,7 +77,10 @@ pub fn trigger_request() -> TestResult<Request> {
old: Some(repo_head),
};
- Ok(Request::trigger(&profile, &be)?)
+ Ok(RequestBuilder::default()
+ .profile(&profile)
+ .broker_event(&be)
+ .build_trigger()?)
}
pub fn mock_adapter(filename: &Path, script: &str) -> TestResult<Adapter> {