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
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Phabfive currently supports the following Phabricator/Phorge applications:
- **Diffusion** - List repositories, get branches, clone URIs, add repositories, manage URIs
- **Paste** - List, get, and add code pastes
- **User** - Get information about the logged-in user
- **Maniphest** - Add comments, show task details, create tasks from templates, and search with advanced transition filtering
- **Maniphest** - Add comments, show task details, create tasks from templates, and search with advanced project filtering and transition filtering

## Getting Started

Expand Down
196 changes: 194 additions & 2 deletions docs/maniphest-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ phabfive maniphest create tasks.yaml --dry-run

## Task Search

Search for tasks within projects with various filtering options.
Search for tasks within projects with various filtering options, including advanced project pattern matching with AND/OR logic.

### Basic Search

Expand All @@ -83,8 +83,17 @@ phabfive maniphest search "My Project"

# Search all projects
phabfive maniphest search "*"

# Search multiple projects (OR logic)
phabfive maniphest search "ProjectA,ProjectB"

# Search project intersection (AND logic)
phabfive maniphest search "Team Alpha+Sprint 42"
```

!!! tip
For advanced project filtering with AND/OR logic and complex patterns, see the [Advanced Project Filtering](#advanced-project-filtering) section below.

### Wildcard Project Matching

The project name supports wildcard patterns:
Expand All @@ -103,6 +112,189 @@ phabfive maniphest search "*API*"
!!! note
Project matching is case-insensitive. If no exact match is found, phabfive will suggest similar project names.

### Advanced Project Filtering

Search for tasks that belong to multiple projects using AND/OR logic. This powerful feature allows you to find tasks at the intersection of different project scopes or combine results from multiple project queries.

#### Pattern Syntax

Project patterns use a query language with AND/OR logic:

- **Comma (`,`)** = OR logic - match tasks in ANY of the projects
- **Plus (`+`)** = AND logic - match tasks in ALL specified projects
- **Wildcards (`*`)** can be combined with AND/OR operators

#### OR Logic Examples

Find tasks that belong to ANY of the specified projects:

```bash
# Tasks in EITHER ProjectA OR ProjectB
phabfive maniphest search "ProjectA,ProjectB"

# Tasks in any Backend project OR any Frontend project
phabfive maniphest search "Backend*,Frontend*"

# Tasks in ProjectA OR ProjectB OR ProjectC
phabfive maniphest search "ProjectA,ProjectB,ProjectC"
```

**Use case**: Finding all tasks across multiple related projects or teams.

#### AND Logic Examples

Find tasks that belong to ALL specified projects simultaneously:

```bash
# Tasks that are in BOTH ProjectA AND ProjectB
phabfive maniphest search "ProjectA+ProjectB"

# Tasks tagged with both a team and a sprint
phabfive maniphest search "Backend Team+Sprint 42"

# Tasks in multiple categories
phabfive maniphest search "Security+High Priority+Q1 2024"
```

**Use case**: Finding tasks at the intersection of multiple categorizations (e.g., tasks that belong to both a team project and a sprint milestone).

#### Complex Combinations

Combine OR and AND logic for sophisticated queries:

```bash
# Tasks that are in (ProjectA AND ProjectB) OR (ProjectC)
phabfive maniphest search "ProjectA+ProjectB,ProjectC"

# Tasks in (Backend Team AND Sprint 42) OR (Frontend Team AND Sprint 42)
phabfive maniphest search "Backend Team+Sprint 42,Frontend Team+Sprint 42"

# Tasks in any Q1 project AND tagged as urgent, OR any Q2 project
phabfive maniphest search "Q1*+Urgent,Q2*"
```

**How it works**: Comma-separated groups are evaluated independently (OR), and within each group, plus-separated projects must all match (AND).

#### Wildcards with AND/OR Logic

Combine wildcard patterns with logical operators:

```bash
# Tasks in any Backend project OR any API project
phabfive maniphest search "Backend*,API*"

# Tasks in both a Backend project AND marked as Security
phabfive maniphest search "Backend*+Security"

# Tasks in (any 2024 project AND High Priority) OR (any Archive project)
phabfive maniphest search "*2024+High Priority,Archive*"
```

#### Projects with Spaces

Project names containing spaces are fully supported:

```bash
# Single project with spaces
phabfive maniphest search "My Project"

# OR logic with spaces
phabfive maniphest search "Project A,Project B"

# AND logic with spaces
phabfive maniphest search "Backend Team+Sprint 42"

# Complex pattern with spaces
phabfive maniphest search "Q1 2024+Backend Team,Q1 2024+Frontend Team"
```

#### Real-World Examples

**Sprint Planning**: Find all tasks for a specific sprint across multiple teams:
```bash
phabfive maniphest search "Backend+Sprint 15,Frontend+Sprint 15,QA+Sprint 15"
```

**Cross-Team Features**: Find tasks that involve multiple teams:
```bash
phabfive maniphest search "Backend Team+Mobile Team"
```

**Security Audits**: Find security tasks across all product areas:
```bash
phabfive maniphest search "Product*+Security"
```

**Quarterly Planning**: Find all high-priority tasks for Q1 across teams:
```bash
phabfive maniphest search "Q1 2024+High Priority"
```

**Release Tracking**: Find tasks for a specific release across components:
```bash
phabfive maniphest search "Release 2.0+API,Release 2.0+UI,Release 2.0+Database"
```

#### Combining with Other Filters

Project patterns work seamlessly with other search filters:

```bash
# Recent tasks in multiple projects
phabfive maniphest search "ProjectA,ProjectB" --updated-after=7

# Tasks in both team and sprint, currently in specific column
phabfive maniphest search "Backend+Sprint 42" --column="in:In Progress"

# High-priority tasks across backend services
phabfive maniphest search "Backend*" --priority="in:High"

# Tasks at intersection of team and milestone, recently completed
phabfive maniphest search "API Team+Milestone 3" \
--column="to:Done" \
--updated-after=14

# Security tasks across products that moved backward
phabfive maniphest search "Product*+Security" \
--column=backward \
--show-history
```

#### Tips for Project Filtering

**Pattern Evaluation**:
- OR patterns (comma-separated) are evaluated left to right - tasks matching ANY pattern are included
- AND patterns (plus-separated) require the task to belong to ALL specified projects
- Empty strings (`""`) return no results - use `"*"` to search all projects instead

**Performance Considerations**:
- Specific project names are faster than wildcards
- Wildcards like `"*"` (all projects) may take longer for large instances
- Combine with date filters (`--created-after`, `--updated-after`) to narrow results

**Debugging Patterns**:
If a pattern doesn't return expected results:

1. Test each project name individually first
2. Verify project names match exactly (check for typos, extra spaces)
3. Remember that AND logic requires tasks to be in ALL projects simultaneously
4. Use `phabfive maniphest search "*"` to see all available tasks and their projects

**Common Patterns**:
```bash
# Multiple teams working on same feature
"Team A+Feature X,Team B+Feature X"

# All projects in a category
"Backend*,Frontend*,Mobile*"

# Specific sprint across teams
"Sprint 42+Backend,Sprint 42+Frontend,Sprint 42+QA"

# Cross-functional initiatives
"Security+*"
```

### Date Filtering

Filter tasks by creation or modification date:
Expand Down Expand Up @@ -460,7 +652,7 @@ The tool dynamically fetches status information from your Phabricator/Phorge ins

**Open vs Closed**: Only Open and Blocked are "open" statuses. All others (Wontfix, Invalid, Duplicate, Resolved) are terminal/closed states.

**Status Progression**:
**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)
- For example: Open (0) → Resolved (5) is "raised" (task progressed forward)
Expand Down
51 changes: 30 additions & 21 deletions phabfive/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from pprint import pprint as pp

# 3rd party imports
from docopt import docopt, extras, Option, DocoptExit

from docopt import DocoptExit, Option, docopt, extras

base_args = """
Usage:
Expand Down Expand Up @@ -117,10 +116,11 @@
phabfive maniphest search <project_name> [options]

Search Arguments:
<project_name> Project name or wildcard pattern.
Supports: "*" (all projects), "prefix*" (starts with),
"*suffix" (ends with), "*contains*" (contains text).
Empty string "" returns no results.
<project_name> Project name or filter pattern (supports OR/AND logic and wildcards).
Supports: "*" (all projects), "prefix*" (starts with),
"*suffix" (ends with), "*contains*" (contains text).
Filter syntax: "ProjectA,ProjectB" (OR), "ProjectA+ProjectB" (AND).
Empty string "" returns no results.

Search Options:
--created-after=N Tasks created within the last N days
Expand Down Expand Up @@ -165,13 +165,13 @@
raised - Status progressed forward
lowered - Status moved backward
not:PATTERN - Negates any pattern above
Examples:
been:Open
from:Open:raised
not:in:Resolved+raised
in:Open,been:Resolved
--show-history Display column, priority, and status transition history
--show-metadata Display filter match metadata (which boards/priority/status matched)
Examples:
been:Open
from:Open:raised
not:in:Resolved+raised
in:Open,been:Resolved
--show-history Display column, priority, and status transition history
--show-metadata Display filter match metadata (which boards/priority/status matched)

Options:
--all Show all fields for a ticket
Expand Down Expand Up @@ -263,12 +263,11 @@ def run(cli_args, sub_args):
Execute the CLI
"""
# Local imports required due to logging limitation
from phabfive import passphrase, diffusion, paste, user, repl, maniphest
from phabfive.maniphest_transitions import parse_transition_patterns
from phabfive.priority_transitions import parse_priority_patterns
from phabfive.status_transitions import parse_status_patterns
from phabfive import diffusion, maniphest, passphrase, paste, repl, user
from phabfive.constants import REPO_STATUS_CHOICES
from phabfive.exceptions import PhabfiveException
from phabfive.maniphest_transitions import parse_transition_patterns
from phabfive.priority_transitions import parse_priority_patterns

retcode = 0

Expand Down Expand Up @@ -401,7 +400,10 @@ def run(cli_args, sub_args):
sub_args["--column"]
)
except Exception as e:
print(f"ERROR: Invalid column filter pattern: {e}", file=sys.stderr)
print(
f"ERROR: Invalid column filter pattern: {e}",
file=sys.stderr,
)
retcode = 1
return retcode

Expand All @@ -412,18 +414,25 @@ def run(cli_args, sub_args):
sub_args["--priority"]
)
except Exception as e:
print(f"ERROR: Invalid priority filter pattern: {e}", file=sys.stderr)
print(
f"ERROR: Invalid priority filter pattern: {e}",
file=sys.stderr,
)
retcode = 1
return retcode

status_patterns = None
if sub_args.get("--status"):
try:
status_patterns = parse_status_patterns(
# Parse status patterns with API-fetched status ordering
status_patterns = maniphest_app.parse_status_patterns_with_api(
sub_args["--status"]
)
except Exception as e:
print(f"ERROR: Invalid status filter pattern: {e}", file=sys.stderr)
print(
f"ERROR: Invalid status filter pattern: {e}",
file=sys.stderr,
)
retcode = 1
return retcode

Expand Down
Loading