Skip to content

Commit fec1f1d

Browse files
committed
feat(cli): make brd done work without an ID argument
auto-detect the current "doing" issue when no ID is given, matching the ergonomics of `brd start` and `brd edit`.
1 parent ce85904 commit fec1f1d

3 files changed

Lines changed: 71 additions & 19 deletions

File tree

src/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ pub enum Command {
143143

144144
/// mark an issue as done
145145
Done {
146-
/// issue ID
147-
id: String,
146+
/// issue ID (defaults to current "doing" issue if omitted)
147+
id: Option<String>,
148148

149149
/// force completion even if not claimed by you, or close design issue without results
150150
#[arg(long)]

src/commands/done.rs

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::error::{BrdError, Result};
66
use crate::graph::would_create_cycle;
77
use crate::issue::{Issue, IssueType, Status};
88
use crate::lock::LockGuard;
9-
use crate::repo::RepoPaths;
9+
use crate::repo::{self, RepoPaths};
1010

1111
use super::start::{commit_and_push_issues_branch_with_action, commit_and_push_main_with_action};
1212
use super::{issue_to_json, load_all_issues, resolve_issue_id};
@@ -15,7 +15,7 @@ use std::collections::{HashMap, HashSet};
1515
pub fn cmd_done(
1616
cli: &Cli,
1717
paths: &RepoPaths,
18-
id: &str,
18+
id: Option<&str>,
1919
force: bool,
2020
result_ids: &[String],
2121
no_push: bool,
@@ -24,7 +24,35 @@ pub fn cmd_done(
2424
let _lock = LockGuard::acquire(&paths.lock_path())?;
2525

2626
let mut issues = load_all_issues(paths, &config)?;
27-
let full_id = resolve_issue_id(id, &issues)?;
27+
let full_id = match id {
28+
Some(partial) => resolve_issue_id(partial, &issues)?,
29+
None => {
30+
let agent_id = repo::get_agent_id(&paths.worktree_root);
31+
let doing: Vec<_> = issues
32+
.values()
33+
.filter(|i| {
34+
i.status() == Status::Doing && i.frontmatter.owner.as_deref() == Some(&agent_id)
35+
})
36+
.collect();
37+
38+
match doing.len() {
39+
0 => {
40+
return Err(BrdError::Other(
41+
"no issue in progress. specify an issue ID or run `brd start` first"
42+
.to_string(),
43+
));
44+
}
45+
1 => doing[0].id().to_string(),
46+
_ => {
47+
let ids: Vec<_> = doing.iter().map(|i| i.id()).collect();
48+
return Err(BrdError::Other(format!(
49+
"multiple issues in progress: {}. specify which to complete",
50+
ids.join(", ")
51+
)));
52+
}
53+
}
54+
}
55+
};
2856
let mut changed_ids = HashSet::new();
2957

3058
// check if this is a design issue
@@ -127,7 +155,7 @@ pub fn cmd_done(
127155
{
128156
let issue = issues
129157
.get_mut(&full_id)
130-
.ok_or_else(|| BrdError::IssueNotFound(id.to_string()))?;
158+
.ok_or_else(|| BrdError::IssueNotFound(full_id.clone()))?;
131159

132160
issue.frontmatter.status = Status::Done;
133161
issue.frontmatter.owner = None;
@@ -210,7 +238,7 @@ mod tests {
210238
.owner("tester")
211239
.create();
212240

213-
cmd_done(&test_cli(), &repo.paths, "brd-aaaa", false, &[], true).unwrap();
241+
cmd_done(&test_cli(), &repo.paths, Some("brd-aaaa"), false, &[], true).unwrap();
214242

215243
let issues = load_all_issues(&repo.paths, &repo.config).unwrap();
216244
let issue = issues.get("brd-aaaa").unwrap();
@@ -221,7 +249,15 @@ mod tests {
221249
#[test]
222250
fn test_done_issue_not_found() {
223251
let repo = TestRepo::builder().build();
224-
let err = cmd_done(&test_cli(), &repo.paths, "brd-missing", false, &[], true).unwrap_err();
252+
let err = cmd_done(
253+
&test_cli(),
254+
&repo.paths,
255+
Some("brd-missing"),
256+
false,
257+
&[],
258+
true,
259+
)
260+
.unwrap_err();
225261
assert!(matches!(err, BrdError::IssueNotFound(_)));
226262
}
227263

@@ -231,7 +267,7 @@ mod tests {
231267
repo.issue("brd-aaaa").create();
232268
repo.issue("brd-aaab").create();
233269

234-
let err = cmd_done(&test_cli(), &repo.paths, "aaa", false, &[], true).unwrap_err();
270+
let err = cmd_done(&test_cli(), &repo.paths, Some("aaa"), false, &[], true).unwrap_err();
235271
assert!(matches!(err, BrdError::AmbiguousId(_, _)));
236272
}
237273

@@ -242,7 +278,15 @@ mod tests {
242278
.issue_type(IssueType::Design)
243279
.create();
244280

245-
let err = cmd_done(&test_cli(), &repo.paths, "brd-design", false, &[], true).unwrap_err();
281+
let err = cmd_done(
282+
&test_cli(),
283+
&repo.paths,
284+
Some("brd-design"),
285+
false,
286+
&[],
287+
true,
288+
)
289+
.unwrap_err();
246290
assert!(err.to_string().contains("design issues require --result"));
247291
}
248292

@@ -253,7 +297,15 @@ mod tests {
253297
.issue_type(IssueType::Design)
254298
.create();
255299

256-
cmd_done(&test_cli(), &repo.paths, "brd-design", true, &[], true).unwrap();
300+
cmd_done(
301+
&test_cli(),
302+
&repo.paths,
303+
Some("brd-design"),
304+
true,
305+
&[],
306+
true,
307+
)
308+
.unwrap();
257309

258310
let issues = load_all_issues(&repo.paths, &repo.config).unwrap();
259311
assert_eq!(issues.get("brd-design").unwrap().status(), Status::Done);
@@ -270,7 +322,7 @@ mod tests {
270322
cmd_done(
271323
&test_cli(),
272324
&repo.paths,
273-
"brd-design",
325+
Some("brd-design"),
274326
false,
275327
&["brd-impl".to_string()],
276328
true,
@@ -291,7 +343,7 @@ mod tests {
291343
let err = cmd_done(
292344
&test_cli(),
293345
&repo.paths,
294-
"brd-design",
346+
Some("brd-design"),
295347
false,
296348
&["brd-missing".to_string()],
297349
true,
@@ -312,7 +364,7 @@ mod tests {
312364
cmd_done(
313365
&test_cli(),
314366
&repo.paths,
315-
"brd-design",
367+
Some("brd-design"),
316368
false,
317369
&["brd-impl".to_string()],
318370
true,
@@ -339,7 +391,7 @@ mod tests {
339391
cmd_done(
340392
&test_cli(),
341393
&repo.paths,
342-
"brd-design",
394+
Some("brd-design"),
343395
false,
344396
&["brd-impl".to_string()],
345397
true,
@@ -367,7 +419,7 @@ mod tests {
367419
cmd_done(
368420
&test_cli(),
369421
&repo.paths,
370-
"brd-design",
422+
Some("brd-design"),
371423
false,
372424
&["brd-impl1".to_string(), "brd-impl2".to_string()],
373425
true,
@@ -409,7 +461,7 @@ mod tests {
409461
cmd_done(
410462
&test_cli(),
411463
&repo.paths,
412-
"brd-design",
464+
Some("brd-design"),
413465
false,
414466
&["brd-impl1".to_string(), "brd-impl2".to_string()],
415467
true,
@@ -452,7 +504,7 @@ mod tests {
452504
let err = cmd_done(
453505
&test_cli(),
454506
&repo.paths,
455-
"brd-design",
507+
Some("brd-design"),
456508
false,
457509
&["brd-impl".to_string()],
458510
true,

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ fn run(cli: &Cli) -> Result<()> {
119119
force,
120120
result,
121121
no_push,
122-
} => cmd_done(cli, &paths, id, *force, result, *no_push),
122+
} => cmd_done(cli, &paths, id.as_deref(), *force, result, *no_push),
123123
Command::Skip { id } => cmd_skip(cli, &paths, id),
124124
Command::Reopen { id } => cmd_reopen(cli, &paths, id),
125125
Command::Path { id } => cmd_path(cli, &paths, id),

0 commit comments

Comments
 (0)