-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathhgreview.py
174 lines (151 loc) · 6.29 KB
/
hgreview.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
import BaseHTTPServer
import os
import re
import socket
import sys
import urllib
from mercurial import cmdutil, error
SERVER = 'https://codereview.adblockplus.org'
UPLOADTOOL_URL = SERVER + '/static/upload.py'
cmdtable = {}
try:
command = cmdutil.command(cmdtable)
except AttributeError:
from mercurial import registrar
command = registrar.command(cmdtable)
@command('review',
[
('i', 'issue', '', 'If given, adds a patch set to this review, otherwise create a new one.', 'ISSUE'),
('r', 'revision', '', 'Revision to diff against or a revision range to upload.', 'REV'),
('c', 'change', '', 'A single revision to upload.', 'REV'),
('t', 'title', '', 'New review subject or new patch set title.', 'TITLE'),
('m', 'message', '', 'New review description or new patch set message.', 'MESSAGE'),
('w', 'reviewers', '', 'Add reviewers (comma separated email addresses or @adblockplus.org user names).', 'REVIEWERS'),
('', 'cc', '', 'Add CC (comma separated email addresses or @adblockplus.org user names).', 'CC'),
('', 'private', None, 'Make the review restricted to reviewers and those CCed.'),
('y', 'assume_yes', None, 'Assume that the answer to yes/no questions is \'yes\'.'),
('', 'print_diffs', None, 'Print full diffs.'),
('', 'no_mail', None, 'Don\'t send an email after uploading.'),
], '[options] [path...]')
def review(ui, repo, *paths, **opts):
'''
Uploads a review to https://codereview.adblockplus.org/ or updates an
existing review request. This will always send mails for new reviews, when
updating a review mails will only be sent if a message is given.
'''
args = ['--oauth2', '--server', SERVER]
if ui.debugflag:
args.append('--noisy')
elif ui.verbose:
args.append('--verbose')
elif ui.quiet:
args.append('--quiet')
if (not opts.get('no_mail') and
(not opts.get('issue') or opts.get('message'))):
args.append('--send_mail')
if opts.get('revision') and opts.get('change'):
raise error.Abort('Ambiguous revision range, only one of --revision and --change can be specified.')
if opts.get('change'):
rev_no = repo.revs(opts['change']).first()
rev = repo[rev_no]
args.extend(['--rev', '{}:{}'.format(rev.parents()[0], rev)])
elif opts.get('revision'):
args.extend(['--rev', opts['revision']])
else:
raise error.Abort('What should be reviewed? Either --revision or --change is required.')
if not opts.get('issue'):
# New issue, make sure title and message are set
fulltitle = None
if not opts.get('title') and not opts.get('change'):
opts['title'] = ui.prompt('New review title: ', '')
elif not opts.get('title'):
rev_no = repo.revs(opts['change']).first()
fulltitle = repo[rev_no].description()
opts['title'] = fulltitle.rstrip().split('\n')[0]
if not opts['title'].strip():
raise error.Abort('No review title given.')
if not opts.get('message'):
opts['message'] = fulltitle or opts['title']
path = (ui.config('paths', 'default-push')
or ui.config('paths', 'default')
or '')
match = re.search(r'^(?:https://|ssh://hg@)(.*)', path)
if match:
opts['base_url'] = 'https://' + match.group(1)
# Make sure there is at least one reviewer
if not opts.get('reviewers'):
if opts.get('no_mail'):
ui.status('No reviewers specified, edit the review to add '
'some.\n')
else:
opts['reviewers'] = ui.prompt('Reviewers (comma-separated): ',
'')
if not opts['reviewers'].strip():
raise error.Abort('No reviewers given.')
for opt in ('reviewers', 'cc'):
if opts.get(opt):
users = [u if '@' in u else u + '@adblockplus.org'
for u in re.split(r'\s*,\s*', opts[opt])]
opts[opt] = ','.join(users)
for opt in ('issue', 'title', 'message', 'reviewers', 'cc', 'base_url'):
if opts.get(opt, ''):
args.extend(['--' + opt, opts[opt]])
for opt in ('private', 'assume_yes', 'print_diffs'):
if opts.get(opt, False):
args.append('--' + opt)
args.extend(paths)
upload_path = ui.config('review', 'uploadtool_path',
os.path.join('~', '.hgreview_upload.py'))
upload_path = os.path.expanduser(upload_path)
if not os.path.exists(upload_path):
ui.status('Downloading {0} to {1}.\n'.format(UPLOADTOOL_URL, upload_path))
urllib.urlretrieve(UPLOADTOOL_URL, upload_path)
# Find an available port for our local server
issue = None
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/javascript')
self.end_headers()
self.wfile.write('location.href = "{0}";'.format(SERVER + '/' + issue))
def log_message(*args, **kwargs):
pass
for port in range(54770, 54780):
try:
server = BaseHTTPServer.HTTPServer(('localhost', port), RequestHandler)
break
except socket.error:
pass
# Modify upload tool's auth response in order to redirect to the issue
scope = {}
execfile(upload_path, scope)
if server:
scope['AUTH_HANDLER_RESPONSE'] = '''\
<html>
<head>
<title>Authentication Status</title>
<script>
window.onload = function()
{
setInterval(function()
{
var script = document.createElement("script");
script.src = "http://localhost:%s/?" + (new Date().getTime());
document.body.appendChild(script);
}, 1000)
}
</script>
</head>
<body>
<p>
The authentication flow has completed. This page will redirect to your
review shortly.
</p>
</body>
</html>
''' % port
# Run the upload tool
issue, patchset = scope['RealMain']([upload_path] + args)
# Wait for the page to check in and retrieve issue URL
if server:
server.handle_request()