|
4 | 4 | import hashlib |
5 | 5 | import json |
6 | 6 | from copy import deepcopy |
| 7 | +from collections import defaultdict |
7 | 8 |
|
8 | 9 | from landoapi.phabricator import ( |
9 | 10 | PhabricatorAPIException, |
@@ -96,6 +97,51 @@ def validate_change(change): |
96 | 97 | return True |
97 | 98 |
|
98 | 99 |
|
| 100 | +def get_stack(_phid, phabdouble): |
| 101 | + phids = set() |
| 102 | + new_phids = {_phid} |
| 103 | + edges = [] |
| 104 | + |
| 105 | + # Repeatedly request all related edges, adding connected revisions |
| 106 | + # each time until no new revisions are found. |
| 107 | + # NOTE: this was adapted from previous implementation of build_stack_graph. |
| 108 | + while new_phids: |
| 109 | + phids.update(new_phids) |
| 110 | + edges = [ |
| 111 | + e |
| 112 | + for e in phabdouble._edges |
| 113 | + if e["sourcePHID"] in phids |
| 114 | + and e["edgeType"] in ("revision.parent", "revision.child") |
| 115 | + ] |
| 116 | + new_phids = set() |
| 117 | + for edge in edges: |
| 118 | + new_phids.add(edge["sourcePHID"]) |
| 119 | + new_phids.add(edge["destinationPHID"]) |
| 120 | + |
| 121 | + new_phids = new_phids - phids |
| 122 | + |
| 123 | + # Treat the stack like a commit DAG, we only care about edges going |
| 124 | + # from child to parent. This is enough to represent the graph. |
| 125 | + edges = { |
| 126 | + (edge["sourcePHID"], edge["destinationPHID"]) |
| 127 | + for edge in edges |
| 128 | + if edge["edgeType"] == "revision.parent" |
| 129 | + } |
| 130 | + |
| 131 | + stack_graph = defaultdict(list) |
| 132 | + sources = [edge[0] for edge in edges] |
| 133 | + for source, dest in edges: |
| 134 | + # Check that destination phid has a corresponding source phid. |
| 135 | + if dest not in sources: |
| 136 | + # We are at a root node. |
| 137 | + stack_graph[dest] = [] |
| 138 | + stack_graph[source].append(dest) |
| 139 | + if not stack_graph: |
| 140 | + # There is only one node, the root node. |
| 141 | + stack_graph[_phid] = [] |
| 142 | + return dict(stack_graph) |
| 143 | + |
| 144 | + |
99 | 145 | class PhabricatorDouble: |
100 | 146 | """Phabricator test double. |
101 | 147 |
|
@@ -898,6 +944,7 @@ def to_response(i): |
898 | 944 | "fields": { |
899 | 945 | "title": i["title"], |
900 | 946 | "authorPHID": i["authorPHID"], |
| 947 | + "stackGraph": i["stack_graph"], |
901 | 948 | "status": { |
902 | 949 | "value": i["status"].value, |
903 | 950 | "name": i["status"].output_name, |
@@ -948,7 +995,10 @@ def to_response(i): |
948 | 995 |
|
949 | 996 | return deepcopy(resp) |
950 | 997 |
|
951 | | - items = [r for r in self._revisions] |
| 998 | + items = [] |
| 999 | + for r in self._revisions: |
| 1000 | + r["stack_graph"] = get_stack(r["phid"], self) |
| 1001 | + items.append(r) |
952 | 1002 |
|
953 | 1003 | if constraints and "ids" in constraints: |
954 | 1004 | items = [i for i in items if i["id"] in constraints["ids"]] |
|
0 commit comments