rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwood9767b485c2aad1e23097d2b5165287ba84cfa452
{
"request": "trigger",
"version": 1,
"event_type": "push",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"pusher": {
"id": "did:key:z6MkkpTPzcq1ybmjQyQpyre15JUeMvZY6toxoZVpLZ8YarsB",
"alias": "mzampetakis"
},
"before": "9767b485c2aad1e23097d2b5165287ba84cfa452",
"after": "9767b485c2aad1e23097d2b5165287ba84cfa452",
"branch": "master",
"commits": [
"9767b485c2aad1e23097d2b5165287ba84cfa452"
]
}
{
"response": "triggered",
"run_id": {
"id": "f5c19aac-44c3-4d30-9c04-b0dec50f59df"
},
"info_url": "https://cci.rad.levitte.org//f5c19aac-44c3-4d30-9c04-b0dec50f59df.html"
}
Started at: 2025-10-21 19:08:16.703185+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW added
✓ Remote-tracking branch cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW/master created for z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz added
✓ Remote-tracking branch erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz/master created for z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/f5c19aac-44c3-4d30-9c04-b0dec50f59df/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 125 issues · 15 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout 9767b485c2aad1e23097d2b5165287ba84cfa452
HEAD is now at 9767b485 cli: Improve `rad inbox` output
Exit code: 0
$ git show 9767b485c2aad1e23097d2b5165287ba84cfa452
commit 9767b485c2aad1e23097d2b5165287ba84cfa452
Author: cloudhead <cloudhead@radicle.xyz>
Date: Mon Feb 12 13:28:49 2024 +0100
cli: Improve `rad inbox` output
* Add change authors
* Add object status
* Add colors
diff --git a/radicle-cli/examples/rad-inbox.md b/radicle-cli/examples/rad-inbox.md
index 17c74bf2..fb75d4f3 100644
--- a/radicle-cli/examples/rad-inbox.md
+++ b/radicle-cli/examples/rad-inbox.md
@@ -18,27 +18,27 @@ $ git push rad -o patch.message="Copyright fixes" HEAD:refs/patches
``` ~alice
$ rad inbox --sort-by id
-╭──────────────────────────────────────────────────────────────╮
-│ heartwood │
-├──────────────────────────────────────────────────────────────┤
-│ 1 ● issue No license file [ .. ] opened now │
-│ 2 ● branch Change copyright bob/copy created now │
-╰──────────────────────────────────────────────────────────────╯
+╭──────────────────────────────────────────────────────────────────────╮
+│ heartwood │
+├──────────────────────────────────────────────────────────────────────┤
+│ 001 ● 58fff44 No license file issue open bob now │
+│ 002 ● bob/copy Change copyright branch created bob now │
+╰──────────────────────────────────────────────────────────────────────╯
```
``` ~alice
$ rad inbox --all --sort-by id
-╭──────────────────────────────────────────────────────────╮
-│ radicle-git │
-├──────────────────────────────────────────────────────────┤
-│ 3 ● patch Copyright fixes [ ... ] opened now │
-╰──────────────────────────────────────────────────────────╯
-╭──────────────────────────────────────────────────────────────╮
-│ heartwood │
-├──────────────────────────────────────────────────────────────┤
-│ 1 ● issue No license file [ .. ] opened now │
-│ 2 ● branch Change copyright bob/copy created now │
-╰──────────────────────────────────────────────────────────────╯
+╭────────────────────────────────────────────────────────────────╮
+│ radicle-git │
+├────────────────────────────────────────────────────────────────┤
+│ 003 ● 4dd5843 Copyright fixes patch open bob now │
+╰────────────────────────────────────────────────────────────────╯
+╭──────────────────────────────────────────────────────────────────────╮
+│ heartwood │
+├──────────────────────────────────────────────────────────────────────┤
+│ 001 ● 58fff44 No license file issue open bob now │
+│ 002 ● bob/copy Change copyright branch created bob now │
+╰──────────────────────────────────────────────────────────────────────╯
```
``` ~alice
@@ -64,12 +64,12 @@ Date: Mon Jan 1 14:39:16 2018 +0000
``` ~alice
$ rad inbox list --sort-by id
-╭──────────────────────────────────────────────────────────────╮
-│ heartwood │
-├──────────────────────────────────────────────────────────────┤
-│ 1 ● issue No license file [ ... ] opened now │
-│ 2 branch Change copyright bob/copy created now │
-╰──────────────────────────────────────────────────────────────╯
+╭──────────────────────────────────────────────────────────────────────╮
+│ heartwood │
+├──────────────────────────────────────────────────────────────────────┤
+│ 001 ● 58fff44 No license file issue open bob now │
+│ 002 bob/copy Change copyright branch created bob now │
+╰──────────────────────────────────────────────────────────────────────╯
```
``` ~alice
@@ -90,11 +90,11 @@ $ rad inbox clear
$ rad inbox
Your inbox is empty.
$ rad inbox --all
-╭──────────────────────────────────────────────────────────╮
-│ radicle-git │
-├──────────────────────────────────────────────────────────┤
-│ 3 ● patch Copyright fixes [ ... ] opened now │
-╰──────────────────────────────────────────────────────────╯
+╭────────────────────────────────────────────────────────────────╮
+│ radicle-git │
+├────────────────────────────────────────────────────────────────┤
+│ 003 ● 4dd5843 Copyright fixes patch open bob now │
+╰────────────────────────────────────────────────────────────────╯
```
``` ~alice
diff --git a/radicle-cli/examples/workflow/5-patching-maintainer.md b/radicle-cli/examples/workflow/5-patching-maintainer.md
index 45b52bdc..120c50c6 100644
--- a/radicle-cli/examples/workflow/5-patching-maintainer.md
+++ b/radicle-cli/examples/workflow/5-patching-maintainer.md
@@ -17,12 +17,12 @@ The contributor's changes are now visible to us.
```
$ rad inbox --sort-by id
-╭──────────────────────────────────────────────────────────────────────╮
-│ heartwood │
-├──────────────────────────────────────────────────────────────────────┤
-│ 1 ● issue flux capacitor underpowered d060989 opened now │
-│ 2 ● patch Define power requirements a99d55e opened now │
-╰──────────────────────────────────────────────────────────────────────╯
+╭────────────────────────────────────────────────────────────────────────────╮
+│ heartwood │
+├────────────────────────────────────────────────────────────────────────────┤
+│ 001 ● d060989 flux capacitor underpowered issue open bob now │
+│ 002 ● a99d55e Define power requirements patch open bob now │
+╰────────────────────────────────────────────────────────────────────────────╯
$ git branch -r
bob/patches/a99d55e5958a8c52ff7efbc8ff000d9bbdac79c7
rad/master
diff --git a/radicle-cli/src/commands/inbox.rs b/radicle-cli/src/commands/inbox.rs
index e1a2fc6a..702676c5 100644
--- a/radicle-cli/src/commands/inbox.rs
+++ b/radicle-cli/src/commands/inbox.rs
@@ -9,7 +9,6 @@ use radicle::node::notifications;
use radicle::node::notifications::*;
use radicle::patch::Patches;
use radicle::prelude::{Profile, RepoId};
-use radicle::storage::RefUpdate;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::{cob, Storage};
@@ -157,7 +156,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let Options { op, mode, sort_by } = options;
match op {
- Operation::List => list(mode, sort_by, ¬ifs.read_only(), storage),
+ Operation::List => list(mode, sort_by, ¬ifs.read_only(), storage, &profile),
Operation::Clear => clear(mode, &mut notifs),
Operation::Show => show(mode, &mut notifs, storage, &profile),
}
@@ -168,21 +167,22 @@ fn list(
sort_by: SortBy,
notifs: ¬ifications::StoreReader,
storage: &Storage,
+ profile: &Profile,
) -> anyhow::Result<()> {
let repos: Vec<term::VStack<'_>> = match mode {
Mode::Contextual => {
if let Ok((_, rid)) = radicle::rad::cwd() {
- list_repo(rid, sort_by, notifs, storage)?
+ list_repo(rid, sort_by, notifs, storage, profile)?
.into_iter()
.collect()
} else {
- list_all(sort_by, notifs, storage)?
+ list_all(sort_by, notifs, storage, profile)?
}
}
- Mode::ByRepo(rid) => list_repo(rid, sort_by, notifs, storage)?
+ Mode::ByRepo(rid) => list_repo(rid, sort_by, notifs, storage, profile)?
.into_iter()
.collect(),
- Mode::All => list_all(sort_by, notifs, storage)?,
+ Mode::All => list_all(sort_by, notifs, storage, profile)?,
Mode::ById(_) => anyhow::bail!("the `list` command does not take IDs"),
};
@@ -200,13 +200,14 @@ fn list_all<'a>(
sort_by: SortBy,
notifs: ¬ifications::StoreReader,
storage: &Storage,
+ profile: &Profile,
) -> anyhow::Result<Vec<term::VStack<'a>>> {
let mut repos = storage.repositories()?;
repos.sort_by_key(|r| r.rid);
let mut vstacks = Vec::new();
for repo in repos {
- let vstack = list_repo(repo.rid, sort_by, notifs, storage)?;
+ let vstack = list_repo(repo.rid, sort_by, notifs, storage, profile)?;
vstacks.extend(vstack.into_iter());
}
Ok(vstacks)
@@ -217,6 +218,7 @@ fn list_repo<'a, R: ReadStorage>(
sort_by: SortBy,
notifs: ¬ifications::StoreReader,
storage: &R,
+ profile: &Profile,
) -> anyhow::Result<Option<term::VStack<'a>>>
where
<R as ReadStorage>::Repository: cob::Store,
@@ -226,6 +228,7 @@ where
..term::TableOptions::default()
});
let repo = storage.repository(rid)?;
+ let (_, head) = repo.head()?;
let doc = repo.identity_doc()?;
let proj = doc.project()?;
let issues = Issues::open(&repo)?;
@@ -245,48 +248,82 @@ where
} else {
term::format::tertiary(String::from("●")).into()
};
- let (category, summary, status, name) = match n.kind {
+ let (category, summary, state, name) = match n.kind {
NotificationKind::Branch { name } => {
let commit = if let Some(head) = n.update.new() {
repo.commit(head)?.summary().unwrap_or_default().to_owned()
} else {
String::new()
};
- let status = match n.update {
- RefUpdate::Updated { .. } => "updated",
- RefUpdate::Created { .. } => "created",
- RefUpdate::Deleted { .. } => "deleted",
- RefUpdate::Skipped { .. } => "skipped",
- };
- ("branch".to_string(), commit, status, name.to_string())
+
+ let state = match n
+ .update
+ .new()
+ .map(|oid| repo.is_ancestor_of(oid, head))
+ .transpose()
+ {
+ Ok(Some(true)) => {
+ term::Paint::<String>::from(term::format::secondary("merged"))
+ }
+ Ok(Some(false)) | Ok(None) => term::format::ref_update(n.update).into(),
+ Err(e) => return Err(e.into()),
+ }
+ .to_owned();
+
+ (
+ "branch".to_string(),
+ commit,
+ state,
+ term::format::default(name.to_string()),
+ )
}
NotificationKind::Cob { type_name, id } => {
- let (category, summary) = if type_name == *cob::issue::TYPENAME {
- let issue = issues.get(&id)?.ok_or(anyhow!("missing"))?;
- (String::from("issue"), issue.title().to_owned())
+ let (category, summary, state) = if type_name == *cob::issue::TYPENAME {
+ let Some(issue) = issues.get(&id)? else {
+ // Issue could have been deleted after notification was created.
+ continue;
+ };
+ (
+ String::from("issue"),
+ issue.title().to_owned(),
+ term::format::issue::state(issue.state()),
+ )
} else if type_name == *cob::patch::TYPENAME {
- let patch = patches.get(&id)?.ok_or(anyhow!("missing"))?;
- (String::from("patch"), patch.title().to_owned())
+ let Some(patch) = patches.get(&id)? else {
+ // Patch could have been deleted after notification was created.
+ continue;
+ };
+ (
+ String::from("patch"),
+ patch.title().to_owned(),
+ term::format::patch::state(patch.state()),
+ )
} else {
- (type_name.to_string(), "".to_owned())
- };
- let status = match n.update {
- RefUpdate::Updated { .. } => "updated",
- RefUpdate::Created { .. } => "opened",
- RefUpdate::Deleted { .. } => "deleted",
- RefUpdate::Skipped { .. } => "skipped",
+ (
+ type_name.to_string(),
+ "".to_owned(),
+ term::format::default(String::new()),
+ )
};
- (category, summary, status, term::format::cob(&id))
+ (category, summary, state, term::format::cob(&id))
}
};
+ let author = n
+ .remote
+ .map(|r| {
+ let (alias, _) = term::format::Author::new(&r, profile).labels();
+ alias
+ })
+ .unwrap_or_default();
table.push([
- n.id.to_string().into(),
+ term::format::dim(format!("{:-03}", n.id)).into(),
seen,
- category.into(),
+ term::format::tertiary(name).into(),
summary.into(),
- name.into(),
- status.into(),
- term::format::timestamp(n.timestamp).into(),
+ term::format::dim(category).into(),
+ state.into(),
+ author,
+ term::format::italic(term::format::timestamp(n.timestamp)).into(),
]);
}
@@ -296,7 +333,7 @@ where
Ok(Some(
term::VStack::default()
.border(Some(term::colors::FAINT))
- .child(term::label(proj.name()))
+ .child(term::label(term::format::bold(proj.name())))
.divider()
.child(table),
))
diff --git a/radicle-cli/src/commands/patch/checkout.rs b/radicle-cli/src/commands/patch/checkout.rs
index 4b35fcd0..1546840e 100644
--- a/radicle-cli/src/commands/patch/checkout.rs
+++ b/radicle-cli/src/commands/patch/checkout.rs
@@ -22,9 +22,8 @@ impl Options {
Some(refname) => Ok(Qualified::from_refstr(refname)
.map_or_else(|| refname.clone(), |q| q.to_ref_string())),
// SAFETY: Patch IDs are valid refstrings.
- None => Ok(
- git::refname!("patch").join(RefString::try_from(term::format::cob(id)).unwrap())
- ),
+ None => Ok(git::refname!("patch")
+ .join(RefString::try_from(term::format::cob(id).item).unwrap())),
}
}
}
diff --git a/radicle-cli/src/terminal/format.rs b/radicle-cli/src/terminal/format.rs
index bf80bbac..dcd1191a 100644
--- a/radicle-cli/src/terminal/format.rs
+++ b/radicle-cli/src/terminal/format.rs
@@ -10,6 +10,7 @@ use radicle::identity::Visibility;
use radicle::node::{Alias, AliasStore, NodeId};
use radicle::prelude::Did;
use radicle::profile::Profile;
+use radicle::storage::RefUpdate;
use radicle_term::element::Line;
use crate::terminal as term;
@@ -44,8 +45,8 @@ pub fn command<D: fmt::Display>(cmd: D) -> Paint<String> {
}
/// Format a COB id.
-pub fn cob(id: &ObjectId) -> String {
- format!("{:.7}", id.to_string())
+pub fn cob(id: &ObjectId) -> Paint<String> {
+ Paint::new(format!("{:.7}", id.to_string()))
}
/// Format a DID.
@@ -72,6 +73,16 @@ pub fn timestamp(time: impl Into<LocalTime>) -> Paint<String> {
Paint::new(fmt.convert(duration.into()))
}
+/// Format a ref update.
+pub fn ref_update(update: RefUpdate) -> Paint<&'static str> {
+ match update {
+ RefUpdate::Updated { .. } => term::format::tertiary("updated"),
+ RefUpdate::Created { .. } => term::format::positive("created"),
+ RefUpdate::Deleted { .. } => term::format::negative("deleted"),
+ RefUpdate::Skipped { .. } => term::format::dim("skipped"),
+ }
+}
+
/// Identity formatter that takes a profile and displays it as
/// `<node-id> (<username>)` depending on the configuration.
pub struct Identity<'a> {
@@ -222,6 +233,41 @@ pub mod html {
}
}
+/// Issue formatting
+pub mod issue {
+ use super::*;
+ use radicle::issue::{CloseReason, State};
+
+ /// Format issue state.
+ pub fn state(s: &State) -> term::Paint<String> {
+ match s {
+ State::Open => term::format::positive(s.to_string()),
+ State::Closed {
+ reason: CloseReason::Other,
+ } => term::format::negative(s.to_string()),
+ State::Closed {
+ reason: CloseReason::Solved,
+ } => term::format::secondary(s.to_string()),
+ }
+ }
+}
+
+/// Patch formatting
+pub mod patch {
+ use super::*;
+ use radicle::patch::State;
+
+ /// Format patch state.
+ pub fn state(s: &State) -> term::Paint<String> {
+ match s {
+ State::Draft { .. } => term::format::dim(s.to_string()),
+ State::Open { .. } => term::format::positive(s.to_string()),
+ State::Archived => term::format::yellow(s.to_string()),
+ State::Merged { .. } => term::format::secondary(s.to_string()),
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
Exit code: 0
shell: 'cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny clippy::all cargo build --all-targets --workspace cargo doc --workspace cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name f5c19aac-44c3-4d30-9c04-b0dec50f59df -v /opt/radcis/ci.rad.levitte.org/cci/state/f5c19aac-44c3-4d30-9c04-b0dec50f59df/s:/f5c19aac-44c3-4d30-9c04-b0dec50f59df/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/f5c19aac-44c3-4d30-9c04-b0dec50f59df/w:/f5c19aac-44c3-4d30-9c04-b0dec50f59df/w -w /f5c19aac-44c3-4d30-9c04-b0dec50f59df/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:bookworm bash /f5c19aac-44c3-4d30-9c04-b0dec50f59df/s/script.sh
+ cargo --version
info: syncing channel updates for '1.74-x86_64-unknown-linux-gnu'
info: latest update on 2023-12-07, rust version 1.74.1 (a28077b28 2023-12-04)
info: downloading component 'cargo'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: installing component 'cargo'
info: installing component 'rust-std'
info: installing component 'rustc'
cargo 1.74.1 (ecb9851af 2023-10-18)
+ rustc --version
rustc 1.74.1 (a28077b28 2023-12-04)
+ cargo fmt --check
error: 'cargo-fmt' is not installed for the toolchain '1.74-x86_64-unknown-linux-gnu'.
To install, run `rustup component add --toolchain 1.74-x86_64-unknown-linux-gnu rustfmt`
Exit code: 1
{
"response": "finished",
"result": "failure"
}