Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
feat: add `cibtool trigger --all` option
Lars Wirzenius committed 8 months ago
commit 7a27e0c01a732ebdc2d553daec49ab0416d7554d
parent 7c3af34
1 file changed +86 -40
modified src/bin/cibtoolcmd/trigger.rs
@@ -8,16 +8,20 @@ use radicle_ci_broker::{
use super::*;

/// Trigger a CI run.
-
#[derive(Parser)]
+
#[derive(Debug, Parser)]
pub struct TriggerCmd {
    /// Set the node where the node originated from.
    #[clap(long)]
    node: Option<NodeId>,

+
    /// Trigger CI to run for all repositories on the local node.
+
    #[clap(long, required_unless_present_any = ["patch","commit"])]
+
    all: bool,
+

    /// Set the repository the event refers to. Can be a RID, or the
    /// repository name.
-
    #[clap(long)]
-
    repo: String,
+
    #[clap(long, required_unless_present = "all")]
+
    repo: Option<String>,

    /// Set the name of the ref the event refers to.
    #[clap(long = "ref", aliases = ["name"], default_value = "main")]
@@ -26,11 +30,11 @@ pub struct TriggerCmd {
    /// Set the commit the event refers to. Can be the SHA1 commit id,
    /// or a symbolic Git revision, as understood by `git rev-parse`.
    /// For example, `HEAD`.
-
    #[clap(long, required_unless_present = "patch")]
+
    #[clap(long, required_unless_present_any = ["patch","all"])]
    commit: Option<String>,

    /// Trigger CI to run on this patch.
-
    #[clap(long, required_unless_present = "commit")]
+
    #[clap(long, required_unless_present_any = ["commit","all"])]
    patch: Option<PatchId>,

    /// Write the event ID to this file, after adding the event to the
@@ -40,52 +44,30 @@ pub struct TriggerCmd {

    /// Output the event to trigger a CI run to the standard output,
    /// instead of adding to the event queue in the database.
-
    #[clap(long)]
+
    #[clap(long, conflicts_with = "all")]
    stdout: bool,

    /// Output the event to trigger a CI run to a named file, instead
    /// of adding to the event queue in the database.
-
    #[clap(long)]
+
    #[clap(long, conflicts_with = "all")]
    output: Option<PathBuf>,
}

impl Leaf for TriggerCmd {
    fn run(&self, args: &Args) -> Result<(), CibToolError> {
        let r = ergo::Radicle::new().map_err(TriggerError::Ergonomic)?;
-

-
        let profile = r.profile();
-
        let nid = self.node.unwrap_or(*profile.id());
-
        let repo = r
-
            .repository_by_name(&self.repo)
-
            .map_err(TriggerError::Ergonomic)?;
-

-
        let oid = self.oid(&r, &repo)?;
-

-
        let base = r
-
            .resolve_commit(&repo.id, &format!("{oid}^"))
-
            .unwrap_or(oid);
-

-
        let branch_name = self.branch(&r, &repo)?;
-

-
        let event = CiEvent::branch_updated(nid, repo.id, &branch_name, oid, base)
-
            .map_err(CibToolError::CiEvent)?;
-

-
        if self.stdout {
-
            let json = event.to_pretty_json().map_err(CibToolError::EventToJson2)?;
-
            println!("{json}");
-
        } else if let Some(filename) = &self.output {
-
            let json = event.to_pretty_json().map_err(CibToolError::EventToJson2)?;
-
            std::fs::write(filename, &json)
-
                .map_err(|err| CibToolError::Write(filename.into(), err))?;
-
        } else {
-
            let db = args.open_db()?;
-
            let id = db.push_queued_ci_event(event)?;
-
            println!("{id}");
-

-
            if let Some(filename) = &self.id_file {
-
                write(filename, id.to_string().as_bytes())
-
                    .map_err(|e| CibToolError::WriteEventId(filename.into(), e))?;
+
        if self.all {
+
            for ri in r.repositories().map_err(TriggerError::Ergonomic)? {
+
                let repo = r.repository(&ri.rid).map_err(TriggerError::Ergonomic)?;
+
                self.trigger(args, &r, &repo)?;
            }
+
        } else if let Some(repo) = &self.repo {
+
            let repo = r
+
                .repository_by_name(repo)
+
                .map_err(TriggerError::Ergonomic)?;
+
            self.trigger(args, &r, &repo)?;
+
        } else {
+
            Err(TriggerError::NoRepo)?
        }

        Ok(())
@@ -112,6 +94,49 @@ impl TriggerCmd {
            Ok(project.default_branch().clone())
        }
    }
+

+
    fn trigger(
+
        &self,
+
        args: &Args,
+
        r: &ergo::Radicle,
+
        repo: &Repository,
+
    ) -> Result<(), TriggerError> {
+
        let profile = r.profile();
+
        let nid = self.node.unwrap_or(*profile.id());
+

+
        let oid = self.oid(r, repo)?;
+

+
        let base = r
+
            .resolve_commit(&repo.id, &format!("{oid}^"))
+
            .unwrap_or(oid);
+

+
        let branch_name = self.branch(r, repo)?;
+

+
        let event = CiEvent::branch_updated(nid, repo.id, &branch_name, oid, base)
+
            .map_err(TriggerError::CiEvent)?;
+

+
        if self.stdout {
+
            let json = event.to_pretty_json().map_err(TriggerError::EventToJson2)?;
+
            println!("{json}");
+
        } else if let Some(filename) = &self.output {
+
            let json = event.to_pretty_json().map_err(TriggerError::EventToJson2)?;
+
            std::fs::write(filename, &json)
+
                .map_err(|err| TriggerError::Write(filename.into(), err))?;
+
        } else {
+
            let db = args
+
                .open_db()
+
                .map_err(|err| TriggerError::OpenDb(Box::new(err)))?;
+
            let id = db.push_queued_ci_event(event)?;
+
            println!("{id}");
+

+
            if let Some(filename) = &self.id_file {
+
                write(filename, id.to_string().as_bytes())
+
                    .map_err(|e| TriggerError::WriteEventId(filename.into(), e))?;
+
            }
+
        }
+

+
        Ok(())
+
    }
}

#[derive(Debug, thiserror::Error)]
@@ -121,4 +146,25 @@ pub enum TriggerError {

    #[error(transparent)]
    RefError(#[from] radicle_ci_broker::refs::RefError),
+

+
    #[error("repository must be given with --repo")]
+
    NoRepo,
+

+
    #[error("failed to construct a CI event")]
+
    CiEvent(#[source] CiEventError),
+

+
    #[error(transparent)]
+
    EventToJson2(#[from] CiEventError),
+

+
    #[error(transparent)]
+
    Db(#[from] DbError),
+

+
    #[error("failed to write file: {0}")]
+
    Write(PathBuf, #[source] std::io::Error),
+

+
    #[error("failed to write event ID to file {0}")]
+
    WriteEventId(PathBuf, #[source] std::io::Error),
+

+
    #[error("failed to get database")]
+
    OpenDb(#[source] Box<CibToolError>),
}