From df44cee9ef009fbbb4a7d6ab741a8563c34ab139 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 2 Nov 2023 11:32:16 +0200 Subject: [PATCH] cob: Add an experimental "job" COB This is meant to record in Radicle that automated "jobs" have been run on a repository. The job might be, for example, a CI run that builds the software and runs its tests. The recording is done in a "job COB", which can be in three states: * fresh -- when the job has been triggered, but has not yet started running * running -- when it's running * finished -- when it's finished running The finished state also records whether the job was successful or if it failed. A job COB records the git commit that it runs on, and the "run ID" of the job. The run ID represents an external identifier, such as one assigned by a remote CI system. The COB can optionally store a URL related to the job, such as to the build log from CI. Add the "rad job" subcommand to create and manage job COBs. For production use, the COBs should be created and updated using `heartwood` as a library instead of running "rad job", if at all possible. However, "rad job list" lists the jobs that have been run on the repository. The COB type name is xyz.radicle.beta.job, until we've gained experience with the COB and its implementation and are ready to declare it stable. Signed-off-by: Lars Wirzenius --- radicle-cli/examples/rad-job.md | 87 ++++++ radicle-cli/src/commands.rs | 2 + radicle-cli/src/commands/help.rs | 1 + radicle-cli/src/commands/job.rs | 362 +++++++++++++++++++++++ radicle-cli/src/main.rs | 7 + radicle-cli/src/terminal.rs | 1 + radicle-cli/src/terminal/format.rs | 5 + radicle-cli/src/terminal/job.rs | 51 ++++ radicle-cli/tests/commands.rs | 14 + radicle/src/cob.rs | 1 + radicle/src/cob/job.rs | 441 +++++++++++++++++++++++++++++ 11 files changed, 972 insertions(+) create mode 100644 radicle-cli/examples/rad-job.md create mode 100644 radicle-cli/src/commands/job.rs create mode 100644 radicle-cli/src/terminal/job.rs create mode 100644 radicle/src/cob/job.rs diff --git a/radicle-cli/examples/rad-job.md b/radicle-cli/examples/rad-job.md new file mode 100644 index 00000000..a28668b3 --- /dev/null +++ b/radicle-cli/examples/rad-job.md @@ -0,0 +1,87 @@ +The `rad job` command lets you manage job COBs. Let's first checkout the +`heartwood` repository: + +``` +$ rad checkout rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji +✓ Repository checkout successful under ./heartwood +$ cd heartwood +``` + +Using the `rad job` (or `rad job list`) command we can see that there are +currently no jobs listed: + +``` +$ rad job +Nothing to show. +``` + +Let's create a job to represent a new CI run. We check what the current `HEAD` +of the repository is, and use the `rad job trigger` to start a fresh job for +that commit: + +``` +$ git rev-parse HEAD +f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 +$ rad job trigger f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 +╭──────────────────────────────────────────────────╮ +│ Job fbbda2447c30ebbab9b746498cd41a383ff05225 │ +│ Commit f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │ +│ State fresh │ +╰──────────────────────────────────────────────────╯ +``` + +Let's check the list again, and we should we see our fresh job there: + +``` +$ rad job +╭───────────────────────────────╮ +│ ● ID Commit State │ +├───────────────────────────────┤ +│ ● fbbda24 f2de534 fresh │ +╰───────────────────────────────╯ +``` + +From there we can start a new job, assigning an arbitrary identifier `xyzzy`, +which would usually from the CI system that is running the job: + +``` +$ rad job start fbbda2447c30ebbab9b746498cd41a383ff05225 xyzzy +``` + +Checking the job again, we can now see that the job is `running`: + +``` +$ rad job +╭─────────────────────────────────╮ +│ ● ID Commit State │ +├─────────────────────────────────┤ +│ ● fbbda24 f2de534 running │ +╰─────────────────────────────────╯ +$ rad job show fbbda2447c30ebbab9b746498cd41a383ff05225 +╭──────────────────────────────────────────────────╮ +│ Job fbbda2447c30ebbab9b746498cd41a383ff05225 │ +│ Commit f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │ +│ State running │ +│ Run ID xyzzy │ +╰──────────────────────────────────────────────────╯ +``` + +When a job has finished, we can mark it as done -- either with a `--success` or +`--failed` flag -- using the `rad job finish` command: + +``` +$ rad job finish --success fbbda2447c30ebbab9b746498cd41a383ff05225 +$ rad job +╭───────────────────────────────────╮ +│ ● ID Commit State │ +├───────────────────────────────────┤ +│ ● fbbda24 f2de534 succeeded │ +╰───────────────────────────────────╯ +$ rad job show fbbda2447c30ebbab9b746498cd41a383ff05225 +╭──────────────────────────────────────────────────╮ +│ Job fbbda2447c30ebbab9b746498cd41a383ff05225 │ +│ Commit f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │ +│ State succeeded │ +│ Run ID xyzzy │ +╰──────────────────────────────────────────────────╯ +``` diff --git a/radicle-cli/src/commands.rs b/radicle-cli/src/commands.rs index e4df12c1..60d5eb14 100644 --- a/radicle-cli/src/commands.rs +++ b/radicle-cli/src/commands.rs @@ -32,6 +32,8 @@ pub mod rad_init; pub mod rad_inspect; #[path = "commands/issue.rs"] pub mod rad_issue; +#[path = "commands/job.rs"] +pub mod rad_job; #[path = "commands/ls.rs"] pub mod rad_ls; #[path = "commands/node.rs"] diff --git a/radicle-cli/src/commands/help.rs b/radicle-cli/src/commands/help.rs index 79ba11bf..93f3d3be 100644 --- a/radicle-cli/src/commands/help.rs +++ b/radicle-cli/src/commands/help.rs @@ -25,6 +25,7 @@ const COMMANDS: &[Help] = &[ rad_inbox::HELP, rad_inspect::HELP, rad_issue::HELP, + rad_job::HELP, rad_ls::HELP, rad_node::HELP, rad_patch::HELP, diff --git a/radicle-cli/src/commands/job.rs b/radicle-cli/src/commands/job.rs new file mode 100644 index 00000000..ab1bfdc5 --- /dev/null +++ b/radicle-cli/src/commands/job.rs @@ -0,0 +1,362 @@ +#![allow(clippy::or_fun_call)] +use std::ffi::OsString; + +use anyhow::{anyhow, Context as _}; + +use radicle::cob::job::{JobStore, Reason, State}; +use radicle::crypto::Signer; +use radicle::node::Handle; +use radicle::storage::{WriteRepository, WriteStorage}; +use radicle::{cob, Node}; + +use crate::git::Rev; +use crate::terminal as term; +use crate::terminal::args::{Args, Error, Help}; +use crate::terminal::Element; + +pub const HELP: Help = Help { + name: "job", + description: "Manage automated jobs on a repository", + version: env!("CARGO_PKG_VERSION"), + usage: r#" +Usage + + rad job [