diff options
author | Lars Wirzenius <liw@liw.fi> | 2024-03-05 18:01:57 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2024-03-05 18:01:57 +0200 |
commit | fee8700dc8d1845c7c8c55e0fd2dd99b29d3efe6 (patch) | |
tree | ffae19fdb494dd7093849f23cb5eb5ddf51363c9 | |
parent | 65c2cbfd92534a1de6907feae1b9aaa6072700dc (diff) | |
download | radicle-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.rs | 8 | ||||
-rw-r--r-- | src/bin/ci-broker.rs | 7 | ||||
-rw-r--r-- | src/msg.rs | 148 | ||||
-rw-r--r-- | src/test.rs | 7 |
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)?; } } @@ -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> { |