/
status.py
240 lines (192 loc) · 8.21 KB
/
status.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
"""Implementation of rbt status."""
import logging
import re
from shutil import get_terminal_size
import texttable as tt
from rbtools.commands.base import BaseCommand, Option
from rbtools.utils.users import get_username
class Status(BaseCommand):
"""Display review requests for the current repository."""
name = 'status'
author = 'The Review Board Project'
description = 'Output a list of your pending review requests.'
needs_api = True
args = '[review-request [revision]]'
option_list = [
Option('--format',
dest='format',
default=None,
help='Set the output format. The format is in the form of '
'`%%(field_name)s`, where `field_name` is one of: `id`, '
'`status`, `summary`, or `description`.\n'
'A character escape can be included via `\\xXX` where '
'`XX` the hex code of a character.\n'
'For example: --format="%%(id)s\\x09%%(summary)s"\n'
'This option will print out the ID and summary tab-'
'separated. This is incompatible with --json.'),
Option('-z',
dest='format_nul',
default=False,
action='store_true',
help='Null-terminate each entry. Otherwise, the entries will '
'be newline-terminated. This is incompatible with '
'--json.'),
Option('--all',
dest='all_repositories',
action='store_true',
default=False,
help='Shows review requests for all repositories instead '
'of just the detected repository.'),
BaseCommand.server_options,
BaseCommand.repository_options,
BaseCommand.perforce_options,
BaseCommand.tfs_options,
]
# The number of spaces between the request's status and the request's id
# and summary.
TAB_SIZE = 3
# The number of spaces after the end of the request's summary.
PADDING = 5
_HEX_RE = re.compile(r'\\x([0-9a-fA-f]{2})')
def tabulate(self, review_requests):
"""Print review request summary and status in a table.
Args:
review_requests (list of dict):
A list that contains statistics about each review request.
"""
self.json.add('review_requests', [])
if len(review_requests):
has_branches = False
has_bookmarks = False
table = tt.Texttable(get_terminal_size().columns)
header = ['Status', 'Review Request']
for info in review_requests:
if 'branch' in info:
has_branches = True
if 'bookmark' in info:
has_bookmarks = True
if has_branches:
header.append('Branch')
if has_bookmarks:
header.append('Bookmark')
table.header(header)
for info in review_requests:
row = [
info['status'],
'r/%s - %s' % (info['id'], info['summary']),
]
summary = {
'approval_failure': info['approval_failure'],
'approved': info['approved'],
'description': info['description'],
'has_draft': info['has_draft'],
'open_issue_count': info['open_issue_count'],
'review_request_id': info['id'],
'review_request_url': info['url'],
'shipit_count': info['shipit_count'],
'status': info['status'],
'summary': info['summary'],
}
if has_branches:
row.append(info.get('branch') or '')
summary['branch'] = row[-1]
if has_bookmarks:
row.append(info.get('bookmark') or '')
summary['bookmark'] = row[-1]
table.add_row(row)
self.json.append('review_requests', summary)
self.stdout.write(table.draw())
else:
self.stdout.write('No review requests found.')
self.stdout.new_line()
def get_data(self, review_requests):
"""Return current status and review summary for all review requests.
Args:
review_requests (ListResource):
A ListResource that contains data on all open/draft
review requests.
Returns:
list:
A list whose elements are dicts of each review request's
statistics.
"""
review_requests_stats = []
for review_request in review_requests.all_items:
if review_request.draft:
status = 'Draft'
elif review_request.issue_open_count:
status = 'Open Issues (%s)' % review_request.issue_open_count
elif review_request.ship_it_count:
status = 'Ship It! (%s)' % review_request.ship_it_count
else:
status = 'Pending'
if review_request.draft:
summary = review_request.draft[0]['summary']
else:
summary = review_request.summary
info = {
'approval_failure': review_request.approval_failure,
'approved': review_request.approved,
'description': review_request.description,
'id': review_request.id,
'status': status,
'summary': summary,
'url': review_request.absolute_url,
'shipit_count': review_request.ship_it_count,
'open_issue_count': review_request.issue_open_count,
'has_draft': review_request.draft is not None
}
if 'local_branch' in review_request.extra_data:
info['branch'] = review_request.extra_data['local_branch']
elif 'local_bookmark' in review_request.extra_data:
info['bookmark'] = review_request.extra_data['local_bookmark']
review_requests_stats.append(info)
return review_requests_stats
def initialize(self):
"""Initialize the command.
This override of the base command initialize method exists so we can
conditionally set whether the SCM Client is necessary. Without any
options, this command will only print the status of review requests on
the current repository, which requires the client. If --all is passed,
this command only needs the API.
"""
self.needs_repository = not self.options.all_repositories
super(Status, self).initialize()
def main(self):
username = get_username(self.api_client, self.api_root,
auth_required=True)
query_args = {
'from_user': username,
'status': 'pending',
'expand': 'draft',
}
if not self.options.all_repositories:
if self.repository:
query_args['repository'] = self.repository.id
else:
logging.warning('The repository detected in the current '
'directory was not found on\n'
'the Review Board server. Displaying review '
'requests from all repositories.')
review_requests = self.api_root.get_review_requests(**query_args)
review_request_info = self.get_data(review_requests)
if self.options.format:
self.format_results(review_request_info)
else:
self.tabulate(review_request_info)
def format_results(self, review_requests):
"""Print formatted information about the review requests.
Args:
review_requests (list of dict):
The information about the review requests.
"""
fmt = self._HEX_RE.sub(
lambda m: chr(int(m.group(1), 16)),
self.options.format,
)
if self.options.format_nul:
end = '\x00'
else:
end = '\n'
for info in review_requests:
self.stdout.write(fmt % info, end=end)