Skip to content

Commit 89123bc

Browse files
committed
Add status filtering and transaction consolidation
Add comprehensive status filtering support and consolidate transaction fetching: - docs/maniphest-cli.md: Added a new 'Status Filtering' section with pattern syntax, examples, combining with other filters, negation, and metadata notes. Also updated examples to include --status usage and metadata. - phabfive/cli.py: Added --status option help text and examples in CLI usage, imported parse_status_patterns, parse status patterns from args, and wired status_patterns into task_search calls. Also updated --show-history description to include status history and show-metadata to indicate status matching. - phabfive/status_transitions.py: New module implementing StatusPattern parsing and matching, status ordering map, helper functions get_status_order, _parse_single_condition, parse_status_patterns, and StatusPattern class with matching logic for from/to/in/been/never/raised/lowered and negation support. - phabfive/maniphest.py: Reorganized imports, added transaction consolidation method _fetch_all_transactions to fetch columns/priority/status in one call, updated matching functions to accept pre-fetched transactions (_task_matches_priority_patterns, added _task_matches_status_patterns), updated _task_matches_any_pattern and task_search to use consolidated transactions, added status_transitions_map and matching_status_map handling, updated history and metadata builders to include status history and matched status booleans, and refactored history fetching to use consolidated method. - tests/test_status_transitions.py: Added comprehensive unit tests for status parsing and matching including orders, parsing errors, pattern combinations, and matching behavior. - tox.ini: Added py314 to envlist. These changes implement status transition filtering end-to-end: CLI, parsing, matching, history display, tests, and docs. Tests and new module are isolated; transaction fetching consolidation touches maniphest to reduce API calls and integrate status handling. 🔧 feat(status_transitions): Improve status order handling with API response Enhance status transition logic to dynamically build status order from Phabricator's maniphest.querystatuses API. Add fallback to hardcoded order when API response is unavailable. Modify functions to accept optional API response for more flexible status progression tracking. 🔧 Refactor: Update status order and test cases Modify status order to reflect new workflow and update corresponding test cases. Remove 'In Progress' and 'Stalled' statuses, adjust order of 'Blocked', 'Wontfix', 'Invalid', 'Duplicate', and 'Resolved' statuses. Update test assertions to match new status order and workflow.
1 parent 75e0df4 commit 89123bc

File tree

6 files changed

+1272
-43
lines changed

6 files changed

+1272
-43
lines changed

docs/maniphest-cli.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,125 @@ phabfive maniphest search "My Project" --priority="in:Normal+not:lowered"
413413

414414
**Note**: `not:been:PRIORITY` is functionally equivalent to `never:PRIORITY`.
415415

416+
## Status Filtering
417+
418+
Filter tasks based on their status changes over time. This helps identify tasks that progressed through workflows, track status regressions, and analyze how task completion status evolved.
419+
420+
### Why Use Status Filtering?
421+
422+
Common use cases include:
423+
424+
- **Track completions**: Find tasks that changed to "Resolved"
425+
- **Identify regressions**: Tasks that moved backward from Resolved to Open
426+
- **Find blocked work**: Tasks that are currently Blocked
427+
- **Audit status history**: See complete status change history for tasks
428+
- **Monitor workflow progression**: Find tasks that reached specific milestones
429+
430+
### Status Pattern Types
431+
432+
| Pattern | Description | Example |
433+
|---------|-------------|---------|
434+
| `from:STATUS` | Task changed from STATUS | `from:Open` |
435+
| `from:STATUS:raised` | Task progressed from STATUS | `from:Open:raised` |
436+
| `from:STATUS:lowered` | Task regressed from STATUS | `from:Resolved:lowered` |
437+
| `to:STATUS` | Task changed to STATUS | `to:Resolved` |
438+
| `in:STATUS` | Task is currently at STATUS | `in:Resolved` |
439+
| `been:STATUS` | Task was at STATUS at any point | `been:Resolved` |
440+
| `never:STATUS` | Task was never at STATUS | `never:Blocked` |
441+
| `raised` | Task had any status progression | `raised` |
442+
| `lowered` | Task had any status regression | `lowered` |
443+
| `not:PATTERN` | Negates any pattern above | `not:in:Open`, `not:raised` |
444+
445+
**Negation Prefix `not:`**: Any pattern can be prefixed with `not:` to negate its meaning. This is a general negation operator that works with all pattern types. For example:
446+
- `not:in:Open` - Tasks NOT currently Open
447+
- `not:raised` - Tasks whose status hasn't progressed
448+
- `not:been:Resolved` - Tasks never been Resolved (equivalent to `never:Resolved`)
449+
450+
### Status Values
451+
452+
Custom status workflow (in progression order):
453+
- Open (0) - Initial state for new tasks
454+
- Blocked (1) - Task is blocked/waiting
455+
- Wontfix (2) - Terminal: Won't be fixed
456+
- Invalid (3) - Terminal: Invalid task
457+
- Duplicate (4) - Terminal: Duplicate of another task
458+
- Resolved (5) - Terminal: Task completed successfully
459+
460+
**Note**: All statuses except Open and Blocked are terminal/closed states.
461+
462+
**Status Progression**: Moving from a lower number to a higher number is considered "raised" (forward progression). Moving from a higher number to a lower number is considered "lowered" (regression/reopening).
463+
464+
### Basic Status Examples
465+
466+
```bash
467+
# Find tasks currently Open
468+
phabfive maniphest search "My Project" --status="in:Open"
469+
470+
# Find tasks that were ever Resolved
471+
phabfive maniphest search "My Project" --status="been:Resolved"
472+
473+
# Find tasks that progressed from Open
474+
phabfive maniphest search "My Project" --status="from:Open:raised"
475+
476+
# Find tasks that had any status progression
477+
phabfive maniphest search "My Project" --status=raised
478+
```
479+
480+
### Combining Column, Priority, and Status Filters
481+
482+
You can combine all three filter types for powerful queries:
483+
484+
```bash
485+
# Tasks moved to Done AND were raised from Open AND are currently Resolved
486+
phabfive maniphest search '*' \
487+
--column='to:Done' \
488+
--priority='from:Normal:raised' \
489+
--status='in:Resolved'
490+
491+
# Tasks in progress that have been blocked
492+
phabfive maniphest search "My Project" \
493+
--column="in:In Progress" \
494+
--status="been:Blocked"
495+
496+
# Recently completed tasks that were never blocked
497+
phabfive maniphest search "My Project" \
498+
--status="to:Resolved" \
499+
--updated-after=7 \
500+
--status="never:Blocked"
501+
```
502+
503+
### Status OR/AND Logic
504+
505+
Same as column and priority patterns, status patterns support OR (comma) and AND (plus):
506+
507+
```bash
508+
# Tasks currently Open OR Blocked
509+
phabfive maniphest search "My Project" --status="in:Open,in:Blocked"
510+
511+
# Tasks raised from Open AND currently Resolved
512+
phabfive maniphest search "My Project" --status="from:Open:raised+in:Resolved"
513+
```
514+
515+
### Status Negation Patterns
516+
517+
Use the `not:` prefix to negate status patterns:
518+
519+
```bash
520+
# Tasks NOT currently Open
521+
phabfive maniphest search "My Project" --status="not:in:Open"
522+
523+
# Tasks whose status has NOT progressed
524+
phabfive maniphest search "My Project" --status="not:raised"
525+
526+
# Tasks NOT Resolved AND have been Blocked at some point
527+
phabfive maniphest search "My Project" --status="not:in:Resolved+been:Blocked"
528+
529+
# Tasks that progressed but did NOT reach Resolved
530+
phabfive maniphest search "My Project" --status="raised+not:in:Resolved"
531+
```
532+
533+
**Note**: `not:been:STATUS` is functionally equivalent to `never:STATUS`.
534+
416535
## Viewing Metadata
417536

418537
Use `--show-metadata` to see why tasks matched your filters. This is especially useful when debugging complex filter combinations.
@@ -421,6 +540,7 @@ Use `--show-metadata` to see why tasks matched your filters. This is especially
421540
phabfive maniphest search '*' \
422541
--column='from:Up Next:forward' \
423542
--priority='been:Normal' \
543+
--status='in:Resolved' \
424544
--show-metadata
425545
```
426546

@@ -429,11 +549,13 @@ Output includes:
429549
Metadata:
430550
MatchedBoards: ['Development', 'GUNNAR-Core']
431551
MatchedPriority: true
552+
MatchedStatus: true
432553
```
433554

434555
The metadata section shows:
435556
- **MatchedBoards**: Which boards satisfied the `--column` filter (in alphabetical order)
436557
- **MatchedPriority**: Whether the task matched the `--priority` filter
558+
- **MatchedStatus**: Whether the task matched the `--status` filter
437559

438560
This helps you understand exactly why a task appeared in your search results.
439561

phabfive/cli.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,23 @@
155155
from:Normal:raised
156156
not:in:High+raised
157157
in:High,been:Unbreak Now!
158-
--show-history Display column and priority transition history for each task
159-
--show-metadata Display filter match metadata (which boards/priority matched)
158+
--status=PATTERNS Filter tasks by status transitions (comma=OR, plus=AND).
159+
Automatically displays status history.
160+
from:STATUS[:direction] - Changed from STATUS
161+
to:STATUS - Changed to STATUS
162+
in:STATUS - Currently at STATUS
163+
been:STATUS - Was at STATUS at any point
164+
never:STATUS - Never was at STATUS
165+
raised - Status progressed forward
166+
lowered - Status moved backward
167+
not:PATTERN - Negates any pattern above
168+
Examples:
169+
been:Open
170+
from:Open:raised
171+
not:in:Resolved+raised
172+
in:Open,been:Resolved
173+
--show-history Display column, priority, and status transition history
174+
--show-metadata Display filter match metadata (which boards/priority/status matched)
160175
161176
Options:
162177
--all Show all fields for a ticket
@@ -251,6 +266,7 @@ def run(cli_args, sub_args):
251266
from phabfive import passphrase, diffusion, paste, user, repl, maniphest
252267
from phabfive.maniphest_transitions import parse_transition_patterns
253268
from phabfive.priority_transitions import parse_priority_patterns
269+
from phabfive.status_transitions import parse_status_patterns
254270
from phabfive.constants import REPO_STATUS_CHOICES
255271
from phabfive.exceptions import PhabfiveException
256272

@@ -400,6 +416,17 @@ def run(cli_args, sub_args):
400416
retcode = 1
401417
return retcode
402418

419+
status_patterns = None
420+
if sub_args.get("--status"):
421+
try:
422+
status_patterns = parse_status_patterns(
423+
sub_args["--status"]
424+
)
425+
except Exception as e:
426+
print(f"ERROR: Invalid status filter pattern: {e}", file=sys.stderr)
427+
retcode = 1
428+
return retcode
429+
403430
# Only show history if explicitly requested
404431
show_history = sub_args.get("--show-history", False)
405432

@@ -411,6 +438,7 @@ def run(cli_args, sub_args):
411438
updated_after=sub_args["--updated-after"],
412439
transition_patterns=transition_patterns,
413440
priority_patterns=priority_patterns,
441+
status_patterns=status_patterns,
414442
show_history=show_history,
415443
show_metadata=show_metadata,
416444
)

0 commit comments

Comments
 (0)