Skip to content

Commit 185c7b3

Browse files
committed
🔧 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.
1 parent f08025d commit 185c7b3

File tree

1 file changed

+76
-14
lines changed

1 file changed

+76
-14
lines changed

‎phabfive/status_transitions.py‎

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
log = logging.getLogger(__name__)
1010

11-
# Status ordering for comparison and workflow progression
11+
# Fallback status ordering for comparison and workflow progression
1212
# Lower number = earlier in the workflow
1313
# Used to determine if status was "raised" (progressed forward) or "lowered" (moved backward)
14-
# Statuses like "Wontfix", "Invalid", "Duplicate" are considered terminal/closed states
15-
STATUS_ORDER = {
14+
# This is only used if the API call to maniphest.querystatuses fails
15+
FALLBACK_STATUS_ORDER = {
1616
"open": 0,
1717
"blocked": 1,
1818
"wontfix": 2,
@@ -22,14 +22,64 @@
2222
}
2323

2424

25-
def get_status_order(status_name):
25+
def _build_status_order_from_api(api_response):
26+
"""
27+
Build status order mapping from API response.
28+
29+
The maniphest.querystatuses API returns:
30+
- openStatuses: list of open status keys
31+
- closedStatuses: dict of closed status values
32+
- statusMap: dict mapping status keys to display names
33+
34+
Parameters
35+
----------
36+
api_response : dict
37+
Response from maniphest.querystatuses API
38+
39+
Returns
40+
-------
41+
dict
42+
Mapping of status name (lowercase) to order number
43+
"""
44+
if not api_response:
45+
return FALLBACK_STATUS_ORDER
46+
47+
order_map = {}
48+
49+
# Extract status information from API response
50+
open_status_keys = api_response.get("openStatuses", [])
51+
closed_status_values = api_response.get("closedStatuses", {})
52+
status_map = api_response.get("statusMap", {})
53+
54+
# Build order: open statuses first (lower numbers), then closed statuses
55+
current_order = 0
56+
57+
# Add open statuses
58+
for status_key in open_status_keys:
59+
status_name = status_map.get(status_key, status_key)
60+
order_map[status_name.lower()] = current_order
61+
current_order += 1
62+
63+
# Add closed statuses
64+
for status_key in closed_status_values.values():
65+
status_name = status_map.get(status_key, status_key)
66+
order_map[status_name.lower()] = current_order
67+
current_order += 1
68+
69+
return order_map
70+
71+
72+
def get_status_order(status_name, api_response=None):
2673
"""
2774
Get the numeric order of a status for comparison.
2875
2976
Parameters
3077
----------
3178
status_name : str
3279
Status name (case-insensitive)
80+
api_response : dict, optional
81+
Full response from maniphest.querystatuses API.
82+
If not provided, uses fallback ordering.
3383
3484
Returns
3585
-------
@@ -38,7 +88,14 @@ def get_status_order(status_name):
3888
"""
3989
if not status_name:
4090
return None
41-
return STATUS_ORDER.get(status_name.lower())
91+
92+
# Build order map from API response if provided
93+
if api_response:
94+
order_map = _build_status_order_from_api(api_response)
95+
else:
96+
order_map = FALLBACK_STATUS_ORDER
97+
98+
return order_map.get(status_name.lower())
4299

43100

44101
class StatusPattern:
@@ -49,15 +106,18 @@ class StatusPattern:
49106
Multiple patterns can be combined with OR logic.
50107
"""
51108

52-
def __init__(self, conditions):
109+
def __init__(self, conditions, api_response=None):
53110
"""
54111
Parameters
55112
----------
56113
conditions : list
57114
List of condition dicts, each with keys like:
58115
{"type": "from", "status": "Open", "direction": "raised"}
116+
api_response : dict, optional
117+
Full response from maniphest.querystatuses API for ordering
59118
"""
60119
self.conditions = conditions
120+
self.api_response = api_response
61121

62122
def matches(self, status_transactions, current_status):
63123
"""
@@ -131,8 +191,8 @@ def _matches_from(self, condition, status_transactions):
131191
return True
132192

133193
# Check direction
134-
old_order = get_status_order(old_value)
135-
new_order = get_status_order(new_value)
194+
old_order = get_status_order(old_value, self.api_response)
195+
new_order = get_status_order(new_value, self.api_response)
136196

137197
if old_order is not None and new_order is not None:
138198
if direction == "raised" and new_order > old_order:
@@ -203,8 +263,8 @@ def _matches_raised(self, status_transactions):
203263
if old_value is None or new_value is None:
204264
continue
205265

206-
old_order = get_status_order(old_value)
207-
new_order = get_status_order(new_value)
266+
old_order = get_status_order(old_value, self.api_response)
267+
new_order = get_status_order(new_value, self.api_response)
208268

209269
if old_order is not None and new_order is not None:
210270
if new_order > old_order: # Higher number = further along
@@ -221,8 +281,8 @@ def _matches_lowered(self, status_transactions):
221281
if old_value is None or new_value is None:
222282
continue
223283

224-
old_order = get_status_order(old_value)
225-
new_order = get_status_order(new_value)
284+
old_order = get_status_order(old_value, self.api_response)
285+
new_order = get_status_order(new_value, self.api_response)
226286

227287
if old_order is not None and new_order is not None:
228288
if new_order < old_order: # Lower number = earlier stage
@@ -314,7 +374,7 @@ def _parse_single_condition(condition_str):
314374
return result
315375

316376

317-
def parse_status_patterns(patterns_str):
377+
def parse_status_patterns(patterns_str, api_response=None):
318378
"""
319379
Parse status pattern string into list of StatusPattern objects.
320380
@@ -326,6 +386,8 @@ def parse_status_patterns(patterns_str):
326386
----------
327387
patterns_str : str
328388
Pattern string like "from:Open:raised+in:Resolved,to:Closed"
389+
api_response : dict, optional
390+
Full response from maniphest.querystatuses API for ordering
329391
330392
Returns
331393
-------
@@ -372,7 +434,7 @@ def parse_status_patterns(patterns_str):
372434
conditions.append(condition)
373435

374436
if conditions:
375-
patterns.append(StatusPattern(conditions))
437+
patterns.append(StatusPattern(conditions, api_response))
376438

377439
if not patterns:
378440
raise PhabfiveException("No valid status patterns found")

0 commit comments

Comments
 (0)