Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ path = "/home/you/arkham"
name = "dunwich"
path = "/srv/work/dunwich"
environment_command = "nix develop -c"
prefix = "dun"

[[projects]]
name = "kadath"
Expand Down Expand Up @@ -127,6 +128,15 @@ says why.
It runs inside the project's environment, and its output is captured rather
than passed on a command line, so the password never shows in `ps`.

**`prefix`** is the prefix the project's tracker gives its beads, written as
`bd init --prefix` takes it: `prefix = "dun"` for beads named `dun-7`. `bdi`
learns a prefix from the beads a tracker answers with, so this only matters
for a project it has not read. With it, a blocker
carrying the prefix is drawn as this project's bead, which was not read, and a
blocker carrying another prefix is never put down to this project. A project
stating none may hold any blocker whose prefix no answer carries, so the line
lists it among the projects not read.

**`poll = false`** stops polling this project and relies on something
[telling `bdi` when it changed](#telling-bdi-a-project-changed). Nothing then
covers for a producer that dies, so the project's mark turns to `?` once
Expand Down
17 changes: 11 additions & 6 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -951,12 +951,15 @@ that project's trees.
tracker's beads carry its prefix, the id up to its first `-` as bd reads one,
so the prefix says whose the bead would be. The line names the projects whose
answers carry the prefix and hold no bead by that id, or the projects that
each hold one. Where no answer carries the prefix, it names the configured
each hold one. Where no answer carries the prefix, it falls to the configured
projects that gave no answer, whether refused, unreachable or left out of the
run, because nothing can learn the prefix of a tracker that did not answer.
Where every configured project answered, the bead is in a project `bdi` is
not configured to read. A parent no answer holds gets no such line, because
it would have been drawn above the bead rather than beneath it. The tree's
Only a project's config can state it. Where one of them states the prefix,
the line says the bead is in that project, which was not read. Otherwise it
names the ones that may hold it: those stating the prefix, or failing any,
those stating none. Where no configured project may hold it, the bead is in a
project `bdi` is not configured to read. A parent no answer holds gets no such
line, because it would have been drawn above the bead rather than beneath it. The tree's
note still counts every bead waiting on something missing, because a fold
can hide the line.

Expand Down Expand Up @@ -2045,8 +2048,10 @@ refusing conflict as `refused`, and one it did not omits the field.
`orphaned_dependencies` is every blocker the bead waits on that no tracker
holds, `[]` where there is none, each an `id` and a `reason`: `not-held` with
the `projects` whose beads carry its prefix, `held-by-several` with the
`projects` that each hold a bead by it, `not-read` with the configured
`projects` that gave no answer, or `unconfigured` with none. `agents`
`projects` that each hold a bead by it, `held-by-unread` with the one
configured `project` that gave no answer and whose config states its prefix,
`not-read` with the configured `projects` that gave no answer and may hold it,
or `unconfigured` with none. `agents`
says which agent provider was asked and how that went, so a consumer knows
which tier it is reading and which program answered for it: `state` is
`answering`, `not-answering` where the provider is there and did not — which
Expand Down
11 changes: 6 additions & 5 deletions src/app/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,11 @@ impl Collection {
now: DateTime<Utc>,
) -> Snapshot {
let answered: Vec<(&str, &ProjectWork)> = self.that_answered(cfg).collect();
let not_read: Vec<&str> = cfg
let not_read: Vec<(&str, Option<&str>)> = cfg
.projects
.iter()
.map(|project| project.name.as_str())
.filter(|project| !answered.iter().any(|(answering, _)| answering == project))
.map(|project| (project.name.as_str(), project.prefix.as_deref()))
.filter(|(project, _)| !answered.iter().any(|(answering, _)| answering == project))
.collect();
let drawn = reaching_across(&answered, &not_read);

Expand Down Expand Up @@ -481,10 +481,11 @@ type Drawn<'a> = (&'a str, &'a str, Result<Cow<'a, Assembled>, &'a RootUnread>);
/// bead waiting on work that answer does not hold is one each tree already
/// names as an orphaned dependency. So only a tree naming one is assembled again, across
/// every answer, and a run with none reads nothing twice. `not_read` is the
/// configured projects that gave no answer, whichever bead they might hold.
/// configured projects that gave no answer, each with the prefix its config
/// states.
fn reaching_across<'a>(
answered: &[(&'a str, &'a ProjectWork)],
not_read: &[&'a str],
not_read: &[(&'a str, Option<&'a str>)],
) -> Vec<Drawn<'a>> {
let waits_elsewhere = |read: &Result<Assembled, RootUnread>| {
read.as_ref()
Expand Down
1 change: 1 addition & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,7 @@ detached
path: PathBuf::from("/srv/work/dunwich"),
environment_command: None,
credential_command: None,
prefix: None,
poll,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down
1 change: 1 addition & 0 deletions src/collect/bd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,7 @@ mod tests {
path: project_dir(),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down
3 changes: 3 additions & 0 deletions src/collect/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub fn from_the_current_directory(
path: root,
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees,
Expand Down Expand Up @@ -342,6 +343,7 @@ detached
path: PathBuf::from("/srv/work/dunwich"),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: vec![PathBuf::from("/srv/work/dunwich")],
Expand Down Expand Up @@ -1172,6 +1174,7 @@ path = "/tmp/seat-b/wt/crates/dish"
path: PathBuf::from("/srv/loose"),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down
4 changes: 4 additions & 0 deletions src/collect/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ mod tests {
path: project_dir(),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down Expand Up @@ -528,6 +529,7 @@ mod tests {
path: project_dir(),
environment_command: None,
credential_command: Some("op read the/password".to_string()),
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down Expand Up @@ -629,6 +631,7 @@ mod tests {
path: project_dir(),
environment_command: None,
credential_command: Some("op read the/password".to_string()),
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down Expand Up @@ -688,6 +691,7 @@ mod tests {
path: project_dir(),
environment_command: None,
credential_command: Some(command.to_string()),
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down
19 changes: 19 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ pub struct Project {
/// to `ps`, so it stays rather than folding into one.
#[serde(default)]
pub credential_command: Option<String>,
/// The prefix this project's tracker gives its beads, as `bd init
/// --prefix` takes it. It says which project holds a bead id before that
/// project's tracker has answered, where nothing can learn the prefix
/// from its beads.
#[serde(default)]
pub prefix: Option<String>,
/// Whether this project asks for itself every interval, or leaves saying
/// its work has moved to whatever reports for it on the inbound channel.
///
Expand Down Expand Up @@ -1079,6 +1085,7 @@ credential_command = "secret-tool lookup tracker arkham"
name = "kadath"
path = "/home/user/dev/kadath"
credential_command = "cat /home/user/dev/kadath/.beads-password"
prefix = "kad"

[[projects.badges]]
key = "metadata.delivery_pr"
Expand Down Expand Up @@ -1165,6 +1172,7 @@ path = "/home/user/dev/cinder"
path: PathBuf::from("/home/user/arkham"),
environment_command: None,
credential_command: Some("secret-tool lookup tracker arkham".to_string()),
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand All @@ -1176,6 +1184,7 @@ path = "/home/user/dev/cinder"
credential_command: Some(
"cat /home/user/dev/kadath/.beads-password".to_string()
),
prefix: Some("kad".to_string()),
poll: true,
badges: vec![Badge {
key: "metadata.delivery_pr".to_string(),
Expand Down Expand Up @@ -1458,6 +1467,7 @@ title = ["title", "badge.metadata.jira", "badges"]
path: PathBuf::from("/home/user").join(name),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges,
worktrees: Vec::new(),
Expand Down Expand Up @@ -1731,6 +1741,15 @@ path = "/home/user/dev/kadath"
assert_eq!(cfg.projects[0].environment_command, None);
}

/// A config written before a project could state its prefix still
/// parses, and says nothing about whose a bead is.
#[test]
fn a_project_saying_nothing_about_its_prefix_states_none() {
let cfg = Config::from_toml(ONE_PROJECT).expect("parses");

assert_eq!(cfg.projects[0].prefix, None);
}

const ONE_ENTERED_WITH_DIRENV: &str = r#"
[[projects]]
name = "kadath"
Expand Down
1 change: 1 addition & 0 deletions src/model/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ mod tests {
path: path.into(),
environment_command: None,
credential_command: None,
prefix: None,
poll: true,
badges: Vec::new(),
worktrees: Vec::new(),
Expand Down
Loading