Radish alpha
r
Radicle CI broker
Radicle
Git (anonymous pull)
Log in to clone via SSH
feat: add an easier way to trigger a CI run.
Lars Wirzenius committed 1 year ago
commit a059a0fb087ddf9fbebfd3f51ad6b4c26c068638
parent 128622370b5feaecb8811093895241af69f1d61c
2 files changed +139 -0
modified ci-broker.md
@@ -829,6 +829,31 @@ when I run cibtool --db x.db event shutdown --id-file id.txt
when I run cibtool --db x.db event show --id-file id.txt
then stdout contains "Shutdown"
~~~
+
## Can trigger a CI run
+

+
_Want:_ The node operator can easily trigger a CI run without
+
changing the repository.
+

+
_Why:_ This allows running CI on a schedule, for example. It's also
+
useful for CI broker development.
+

+
_Who:_ Lars.
+

+

+
~~~scenario
+
given file radenv.sh
+
given file setup-node.sh
+
when I run bash radenv.sh bash setup-node.sh
+

+
given an installed cibtool
+
when I run bash radenv.sh cibtool --db x.db trigger --repo testy --ref main --commit HEAD --id-file id.txt
+

+
when I run cibtool --db x.db event show --id-file id.txt
+
then stdout contains "rad:"
+
then stdout contains "main"
+
~~~
+

+

## Add CI run information to database

_Want:_ `cibtool` can add information about a CI run, possibly
modified src/bin/cibtool.rs
@@ -83,6 +83,7 @@ impl Args {
            Cmd::Event(x) => x.run(self)?,
            Cmd::Run(x) => x.run(self)?,
            Cmd::Report(x) => x.run(self)?,
+
            Cmd::Trigger(x) => x.run(self)?,
        }
        Ok(())
    }
@@ -109,6 +110,9 @@ enum Cmd {

    /// Produce HTML reports based on database contents.
    Report(ReportCmd),
+

+
    /// Trigger a Ci run.
+
    Trigger(TriggerCmd),
}

#[derive(Parser)]
@@ -714,6 +718,116 @@ impl ReportCmd {
    }
}

+
#[derive(Parser)]
+
struct TriggerCmd {
+
    /// Set the repository the event refers to. Can be a RID, or the
+
    /// repository name.
+
    #[clap(long)]
+
    repo: String,
+

+
    /// Set the name of the ref the event refers to.
+
    #[clap(long, alias = "ref")]
+
    name: String,
+

+
    /// 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)]
+
    commit: String,
+

+
    /// Write the event ID to this file, after adding the event to the
+
    /// queue.
+
    #[clap(long)]
+
    id_file: Option<PathBuf>,
+
}
+

+
impl TriggerCmd {
+
    #[allow(clippy::result_large_err)]
+
    fn run(&self, args: &Args) -> Result<(), CibToolError> {
+
        let rid = if let Ok(rid) = RepoId::from_urn(&self.repo) {
+
            rid
+
        } else {
+
            self.lookup_rid(&self.repo)?
+
        };
+

+
        let oid = if let Ok(rid) = Oid::from_str(&self.commit) {
+
            rid
+
        } else {
+
            self.lookup_commit(rid, &self.commit)?
+
        };
+

+
        let name = format!(
+
            "refs/namespaces/{}/refs/heads/{}",
+
            self.lookup_nid()?,
+
            self.name.as_str()
+
        );
+
        let name = RefString::try_from(name).expect("RefString");
+

+
        let event = BrokerEvent::new(&rid, &name, &oid, None);
+

+
        let db = args.open_db()?;
+
        let id = db.push_queued_event(event)?;
+
        println!("{id}");
+

+
        if let Some(filename) = &self.id_file {
+
            write(filename, id.to_string().as_bytes()).expect("write id file");
+
        }
+

+
        Ok(())
+
    }
+

+
    #[allow(clippy::result_large_err)]
+
    fn lookup_nid(&self) -> Result<NodeId, CibToolError> {
+
        let profile = Profile::load().map_err(CibToolError::Profile)?;
+
        Ok(*profile.id())
+
    }
+

+
    #[allow(clippy::result_large_err)]
+
    fn lookup_rid(&self, wanted: &str) -> Result<RepoId, CibToolError> {
+
        let profile = Profile::load().map_err(CibToolError::Profile)?;
+
        let storage =
+
            Storage::open(profile.storage(), profile.info()).map_err(CibToolError::Storage)?;
+

+
        let mut rid = None;
+
        let repo_infos = storage.repositories().map_err(CibToolError::Repositories)?;
+
        for ri in repo_infos {
+
            let project = ri
+
                .doc
+
                .project()
+
                .map_err(|e| CibToolError::Project(ri.rid, e))?;
+

+
            if project.name() == wanted {
+
                if rid.is_some() {
+
                    return Err(CibToolError::DuplicateRepositories(wanted.into()));
+
                }
+
                rid = Some(ri.rid);
+
            }
+
        }
+

+
        if let Some(rid) = rid {
+
            Ok(rid)
+
        } else {
+
            Err(CibToolError::NotFound(wanted.into()))
+
        }
+
    }
+

+
    #[allow(clippy::result_large_err)]
+
    fn lookup_commit(&self, rid: RepoId, gitref: &str) -> Result<Oid, CibToolError> {
+
        let profile = Profile::load().map_err(CibToolError::Profile)?;
+
        let storage =
+
            Storage::open(profile.storage(), profile.info()).map_err(CibToolError::Storage)?;
+
        let repo = storage
+
            .repository(rid)
+
            .map_err(|e| CibToolError::RepoOpen(rid, e))?;
+
        let object = repo
+
            .backend
+
            .revparse_single(gitref)
+
            .map_err(|e| CibToolError::RevParse(gitref.into(), e))?;
+

+
        Ok(object.id().into())
+
    }
+
}
+

#[derive(Debug, thiserror::Error)]
#[allow(clippy::large_enum_variant)]
enum CibToolError {