1
+ from phabricator import Phabricator as PhabricatorOriginal
2
+ from phabricator import parse_interfaces
3
+ import argparse
4
+
5
+
6
+ '''
7
+ get project wide tasks which are not closed but all in the Finished column
8
+
9
+ 1. get all Workboard columns
10
+ - extract workboard phid for the Finished column
11
+ - and the project phid and name
12
+
13
+ 2. get all open taks from projects with Finish column
14
+ 3. get unique taskslists from previous step to get projekts of a task
15
+ 4. get all transactions for each task and check if the task is in the Finished column per project
16
+ 5. autoclose if task is in all Finished column
17
+
18
+ '''
19
+
20
+ '''
21
+ extend of original Phabricator class to add new interface "project.column.search"
22
+ this can be delete if PR https://github.com/disqus/python-phabricator/pull/71 is merged in the pip package
23
+
24
+ '''
25
+ import copy
26
+ import json
27
+ import pkgutil
28
+
29
+ INTERFACES = json .loads (
30
+ pkgutil .get_data ('phabricator' , 'interfaces.json' )
31
+ .decode ('utf-8' ))
32
+
33
+ INTERFACES ['project.column.search' ] = {
34
+ "description" : "Search for Workboard columns." ,
35
+ "params" : {
36
+ "ids" : "optional list<int>" ,
37
+ "phids" : "optional list<phid>" ,
38
+ "projects" : "optional list<phid>"
39
+ },
40
+ "return" : "list"
41
+ }
42
+
43
+ class Phabricator (PhabricatorOriginal ):
44
+ def __init__ (self , ** kwargs ):
45
+ kwargs ['interface' ] = copy .deepcopy (parse_interfaces (INTERFACES ))
46
+ super (Phabricator , self ).__init__ (self , ** kwargs )
47
+
48
+ ''' end of extend the original Phabricator class'''
49
+
50
+ def phab_search (method , constraints = dict (), after = None ):
51
+ results = []
52
+ while True :
53
+ response = method (
54
+ constraints = constraints ,
55
+ after = after
56
+ )
57
+ results .extend (response .response ['data' ])
58
+ after = response .response ['cursor' ]['after' ]
59
+ if after is None :
60
+ break
61
+ return results
62
+
63
+
64
+ def phab_query (method , after = None ):
65
+ results = []
66
+ while True :
67
+ response = method (
68
+ offset = after
69
+ )
70
+ results .extend (response .response ['data' ])
71
+ after = response .response ['cursor' ]['after' ]
72
+ if after is None :
73
+ break
74
+ return results
75
+
76
+
77
+ def close_task (task_id , phab ):
78
+ try :
79
+ response = phab .maniphest .update (
80
+ id = task_id ,
81
+ status = 'resolved'
82
+ )
83
+ if response .response ['isClosed' ]:
84
+ print (f'T{ task_id } closed' )
85
+ except Exception as e :
86
+ print (f'T{ task_id } Error: { e } ' )
87
+
88
+
89
+ parser = argparse .ArgumentParser ()
90
+ parser .add_argument ("-t" , "--token" , type = str , help = "API token" , required = True )
91
+ args = parser .parse_args ()
92
+
93
+ phab = Phabricator (host = 'https://vyos.dev/api/' , token = args .token )
94
+ phab .maniphest .update (id = 6053 , status = 'resolved' )
95
+
96
+ workboards = phab_search (phab .project .column .search )
97
+ project_hirarchy = {}
98
+
99
+ # get sub-project hirarchy from proxyPHID in workboards
100
+ for workboard in workboards :
101
+ if workboard ['fields' ]['proxyPHID' ]:
102
+ proxy_phid = workboard ['fields' ]['proxyPHID' ]
103
+ project_phid = workboard ['fields' ]['project' ]['phid' ]
104
+
105
+ if project_phid not in project_hirarchy .keys ():
106
+ project_hirarchy [project_phid ] = []
107
+ project_hirarchy [project_phid ].append (proxy_phid )
108
+
109
+ finished_boards = []
110
+
111
+
112
+ for workboard in workboards :
113
+ project_id = workboard ['fields' ]['project' ]['phid' ]
114
+ if project_id in project_hirarchy .keys ():
115
+ # skip projects with sub-projects
116
+ continue
117
+ if workboard ['fields' ]['name' ] == 'Finished' :
118
+ project_tasks = phab_search (phab .maniphest .search , constraints = {
119
+ 'projects' : [project_id ],
120
+ 'statuses' : ['open' ],
121
+ })
122
+ finished_boards .append ({
123
+ 'project_id' : project_id ,
124
+ 'project_name' : workboard ['fields' ]['project' ]['name' ],
125
+ 'project_tasks' : project_tasks ,
126
+ 'should_board_id' : workboard ['phid' ],
127
+ })
128
+
129
+ # get unique tasks
130
+ # tasks = {
131
+ # 9999: {
132
+ # 'PHID-PROJ-xxxxx': 'PHID-PCOL-xxxxx',
133
+ # 'PHID-PROJ-yyyyy': 'PHID-PCOL-yyyyy'
134
+ # }
135
+ # }
136
+ tasks = {}
137
+ for project in finished_boards :
138
+ project_id = project ['project_id' ]
139
+ board_id = project ['should_board_id' ]
140
+ for task in project ['project_tasks' ]:
141
+ task_id = task ['id' ]
142
+ if task_id not in tasks .keys ():
143
+ tasks [task_id ] = {}
144
+ if project_id not in tasks [task_id ].keys ():
145
+ tasks [task_id ][project_id ] = board_id
146
+
147
+ tasks = dict (sorted (tasks .items ()))
148
+
149
+ # get transactions for each task and compare if the task is in the Finished column
150
+ for task_id , projects in tasks .items ():
151
+ fisnish_timestamp = 0
152
+ project_ids = list (projects .keys ())
153
+ # don't use own pagination function, because endpoint without pagination
154
+ transactions = phab .maniphest .gettasktransactions (ids = [task_id ])
155
+ transactions = transactions .response [str (task_id )]
156
+ finished = False
157
+ for transaction in transactions :
158
+ if transaction ['transactionType' ] == 'core:columns' :
159
+ # test if projectid is in transaction
160
+ if transaction ['newValue' ][0 ]['boardPHID' ] in project_ids :
161
+ # remove project_id from project_ids to use only last transaction in this
162
+ # project
163
+ project_ids .remove (transaction ['newValue' ][0 ]['boardPHID' ])
164
+ # test if boardid is the "Finished" board
165
+ if fisnish_timestamp < int (transaction ['dateCreated' ]):
166
+ fisnish_timestamp = int (transaction ['dateCreated' ])
167
+ if projects [transaction ['newValue' ][0 ]['boardPHID' ]] == transaction ['newValue' ][0 ]['columnPHID' ]:
168
+ finished = True
169
+ for project in finished_boards :
170
+ if project ['project_id' ] == transaction ['newValue' ][0 ]['boardPHID' ]:
171
+ project_name = project ['project_name' ]
172
+ # print(f'T{task_id} is Finished in {project_name}')
173
+ if len (project_ids ) == 0 :
174
+ print (f'T{ task_id } is Finished in all projects' )
175
+ close_task (task_id , phab )
176
+ break
177
+
178
+ #if len(project_ids) > 0 and finished:
179
+ # collect project names for output
180
+ # project_names = []
181
+ # for project_id in project_ids:
182
+ # for project in finished_boards:
183
+ # if project['project_id'] == project_id:
184
+ # project_names.append(project['project_name'])
185
+ # print(f'T{task_id} is in a different column: {' and '.join(project_names)}')
186
+
0 commit comments