5.0 KiB
+++ title = "Wire --filter flag into list, ready, and migrate commands" priority = 8 status = "done" ticket_type = "feature" dependencies = ["c2a024"] +++
Summary
Add --filter KEY=VALUE (repeatable) to the list, ready, and migrate CLI commands.
Parse filter arguments into a TicketFilter and apply it in each command handler.
Depends on: TicketFilter module (ticket c2a024).
CLI changes (src/main.rs)
Add to Commands::List, Commands::Ready, and Commands::Migrate variants:
/// Filter tickets: key=value pairs (repeatable).
/// Keys: priority, type, status, title.
/// Different keys are ANDed; same key with multiple values is ORed.
/// Values support glob wildcards: status=* matches all statuses.
#[arg(long = "filter", value_name = "KEY=VALUE")]
filter: Vec<String>,
Update the dispatch function to pass filter args through to each handler.
Handler changes
cmd_list(filter_args, json)
let filter = filter::parse_filters(&filter_args)?;
let tickets: Vec<Ticket> = list_tickets(&root).await?
.into_iter()
.filter(|t| filter.matches(t))
.collect();
Note: the default done-exclusion behaviour (ticket for that is separate) will also live here, layered on top of this filter application.
cmd_ready(filter_args, json)
Apply the user filter AFTER the ready check. The ready check (not done + all deps done) is always applied first; the user's filter narrows further within ready tickets.
let filter = filter::parse_filters(&filter_args)?;
// ... build done_ids as before ...
let ready: Vec<Ticket> = all
.into_iter()
.filter(|t| {
t.status \!= Status::Done
&& t.dependencies.iter().all(|dep| done_ids.contains(dep.as_str()))
&& filter.matches(t)
})
.collect();
cmd_migrate(filter_args, dry_run, json)
For migrate, the filter selects which tickets are candidates for migration. Tickets not matching the filter are skipped (counted separately, not treated as errors).
Add a skipped field to MigrateReport in store.rs:
pub struct MigrateReport {
pub updated: usize,
pub already_current: usize,
pub skipped: usize, // NEW: tickets excluded by filter
pub errors: Vec<(String, String)>,
}
Update migrate_tickets signature in store.rs:
pub async fn migrate_tickets(
root: &Path,
dry_run: bool,
filter: &TicketFilter,
) -> Result<MigrateReport>
Inside the per-file loop, after deserialising the ticket, check filter.matches(&ticket).
If false: increment report.skipped and continue to next file.
Update cmd_migrate to parse the filter and pass it to migrate_tickets.
display.rs changes
Update format_migrate_report and format_migrate_report_json to include the
skipped count:
Human format:
Migrated 3 tickets.
Current 5 tickets (already up to date).
Skipped 2 tickets (did not match filter).
Errors 1 ticket could not be migrated:
bad_ticket.json: trailing comma at line 4
Only print the "Skipped" line when skipped > 0.
JSON format: add "skipped": N key to the existing object.
files touched
src/main.rs—filterfields on List/Ready/Migrate variants, updated dispatch, updated cmd_list/cmd_ready/cmd_migrate handlerssrc/store.rs—MigrateReport::skipped,migrate_ticketsgainsfilterparamsrc/display.rs— updatedformat_migrate_reportandformat_migrate_report_jsonsrc/tests.rs— unit tests for updated migrate report formattingtests/integration.rs— integration tests
Integration tests to add (tests/integration.rs)
list filtering:
- Create tickets: 1 bug/todo, 1 task/in_progress, 1 bug/done.
nbd list --filter type=bugshows only the bug tickets (done-exclusion is separate, but this test can use non-done bugs). nbd list --filter status=in_progressshows only in_progress tickets.nbd list --filter status=todo --filter status=in_progressshows both todo and in_progress (OR within same key).nbd list --filter type=bug --filter status=todoshows only bug+todo tickets (AND across keys).nbd list --filter title=*login*shows only tickets whose title contains "login".nbd list --filter status=*matches all statuses (wildcard).nbd list --filter type=unknownexits non-zero with an error (unknown key passes through as a value, but "unknown" does not match any type → empty results, or error? Error on unknown key is preferable).nbd list --filter badformat(no=) exits non-zero with an error.
ready filtering:
nbd ready --filter type=bugreturns only ready bug tickets.nbd ready --filter priority=8returns only ready tickets with priority 8.
migrate filtering:
- Create two tickets. Run
nbd migrate --filter status=todo --dry-run. Verifyskippedcount in JSON output matches tickets not matching the filter. nbd migrate --filter status=todo --jsonincludesskippedkey.
error cases:
--filterwith unknown key exits non-zero.--filterwith no=exits non-zero.