diff options
Diffstat (limited to 'subcmds/upload.py')
-rw-r--r-- | subcmds/upload.py | 315 |
1 files changed, 191 insertions, 124 deletions
diff --git a/subcmds/upload.py b/subcmds/upload.py index 5c12aaee..c48deab6 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py | |||
@@ -1,5 +1,3 @@ | |||
1 | # -*- coding:utf-8 -*- | ||
2 | # | ||
3 | # Copyright (C) 2008 The Android Open Source Project | 1 | # Copyright (C) 2008 The Android Open Source Project |
4 | # | 2 | # |
5 | # Licensed under the Apache License, Version 2.0 (the "License"); | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
@@ -14,25 +12,23 @@ | |||
14 | # See the License for the specific language governing permissions and | 12 | # See the License for the specific language governing permissions and |
15 | # limitations under the License. | 13 | # limitations under the License. |
16 | 14 | ||
17 | from __future__ import print_function | ||
18 | import copy | 15 | import copy |
16 | import functools | ||
17 | import optparse | ||
19 | import re | 18 | import re |
20 | import sys | 19 | import sys |
21 | 20 | ||
22 | from command import InteractiveCommand | 21 | from command import DEFAULT_LOCAL_JOBS, InteractiveCommand |
23 | from editor import Editor | 22 | from editor import Editor |
24 | from error import HookError, UploadError | 23 | from error import UploadError |
25 | from git_command import GitCommand | 24 | from git_command import GitCommand |
26 | from project import RepoHook | 25 | from git_refs import R_HEADS |
26 | from hooks import RepoHook | ||
27 | 27 | ||
28 | from pyversion import is_python3 | ||
29 | if not is_python3(): | ||
30 | input = raw_input | ||
31 | else: | ||
32 | unicode = str | ||
33 | 28 | ||
34 | UNUSUAL_COMMIT_THRESHOLD = 5 | 29 | UNUSUAL_COMMIT_THRESHOLD = 5 |
35 | 30 | ||
31 | |||
36 | def _ConfirmManyUploads(multiple_branches=False): | 32 | def _ConfirmManyUploads(multiple_branches=False): |
37 | if multiple_branches: | 33 | if multiple_branches: |
38 | print('ATTENTION: One or more branches has an unusually high number ' | 34 | print('ATTENTION: One or more branches has an unusually high number ' |
@@ -44,19 +40,22 @@ def _ConfirmManyUploads(multiple_branches=False): | |||
44 | answer = input("If you are sure you intend to do this, type 'yes': ").strip() | 40 | answer = input("If you are sure you intend to do this, type 'yes': ").strip() |
45 | return answer == "yes" | 41 | return answer == "yes" |
46 | 42 | ||
43 | |||
47 | def _die(fmt, *args): | 44 | def _die(fmt, *args): |
48 | msg = fmt % args | 45 | msg = fmt % args |
49 | print('error: %s' % msg, file=sys.stderr) | 46 | print('error: %s' % msg, file=sys.stderr) |
50 | sys.exit(1) | 47 | sys.exit(1) |
51 | 48 | ||
49 | |||
52 | def _SplitEmails(values): | 50 | def _SplitEmails(values): |
53 | result = [] | 51 | result = [] |
54 | for value in values: | 52 | for value in values: |
55 | result.extend([s.strip() for s in value.split(',')]) | 53 | result.extend([s.strip() for s in value.split(',')]) |
56 | return result | 54 | return result |
57 | 55 | ||
56 | |||
58 | class Upload(InteractiveCommand): | 57 | class Upload(InteractiveCommand): |
59 | common = True | 58 | COMMON = True |
60 | helpSummary = "Upload changes for code review" | 59 | helpSummary = "Upload changes for code review" |
61 | helpUsage = """ | 60 | helpUsage = """ |
62 | %prog [--re --cc] [<project>]... | 61 | %prog [--re --cc] [<project>]... |
@@ -126,74 +125,89 @@ is set to "true" then repo will assume you always want the equivalent | |||
126 | of the -t option to the repo command. If unset or set to "false" then | 125 | of the -t option to the repo command. If unset or set to "false" then |
127 | repo will make use of only the command line option. | 126 | repo will make use of only the command line option. |
128 | 127 | ||
128 | review.URL.uploadhashtags: | ||
129 | |||
130 | To add hashtags whenever uploading a commit, you can set a per-project | ||
131 | or global Git option to do so. The value of review.URL.uploadhashtags | ||
132 | will be used as comma delimited hashtags like the --hashtag option. | ||
133 | |||
134 | review.URL.uploadlabels: | ||
135 | |||
136 | To add labels whenever uploading a commit, you can set a per-project | ||
137 | or global Git option to do so. The value of review.URL.uploadlabels | ||
138 | will be used as comma delimited labels like the --label option. | ||
139 | |||
140 | review.URL.uploadnotify: | ||
141 | |||
142 | Control e-mail notifications when uploading. | ||
143 | https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify | ||
144 | |||
129 | # References | 145 | # References |
130 | 146 | ||
131 | Gerrit Code Review: https://www.gerritcodereview.com/ | 147 | Gerrit Code Review: https://www.gerritcodereview.com/ |
132 | 148 | ||
133 | """ | 149 | """ |
150 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS | ||
134 | 151 | ||
135 | def _Options(self, p): | 152 | def _Options(self, p): |
136 | p.add_option('-t', | 153 | p.add_option('-t', |
137 | dest='auto_topic', action='store_true', | 154 | dest='auto_topic', action='store_true', |
138 | help='Send local branch name to Gerrit Code Review') | 155 | help='send local branch name to Gerrit Code Review') |
156 | p.add_option('--hashtag', '--ht', | ||
157 | dest='hashtags', action='append', default=[], | ||
158 | help='add hashtags (comma delimited) to the review') | ||
159 | p.add_option('--hashtag-branch', '--htb', | ||
160 | action='store_true', | ||
161 | help='add local branch name as a hashtag') | ||
162 | p.add_option('-l', '--label', | ||
163 | dest='labels', action='append', default=[], | ||
164 | help='add a label when uploading') | ||
139 | p.add_option('--re', '--reviewers', | 165 | p.add_option('--re', '--reviewers', |
140 | type='string', action='append', dest='reviewers', | 166 | type='string', action='append', dest='reviewers', |
141 | help='Request reviews from these people.') | 167 | help='request reviews from these people') |
142 | p.add_option('--cc', | 168 | p.add_option('--cc', |
143 | type='string', action='append', dest='cc', | 169 | type='string', action='append', dest='cc', |
144 | help='Also send email to these email addresses.') | 170 | help='also send email to these email addresses') |
145 | p.add_option('--br', | 171 | p.add_option('--br', '--branch', |
146 | type='string', action='store', dest='branch', | 172 | type='string', action='store', dest='branch', |
147 | help='Branch to upload.') | 173 | help='(local) branch to upload') |
148 | p.add_option('--cbr', '--current-branch', | 174 | p.add_option('-c', '--current-branch', |
175 | dest='current_branch', action='store_true', | ||
176 | help='upload current git branch') | ||
177 | p.add_option('--no-current-branch', | ||
178 | dest='current_branch', action='store_false', | ||
179 | help='upload all git branches') | ||
180 | # Turn this into a warning & remove this someday. | ||
181 | p.add_option('--cbr', | ||
149 | dest='current_branch', action='store_true', | 182 | dest='current_branch', action='store_true', |
150 | help='Upload current git branch.') | 183 | help=optparse.SUPPRESS_HELP) |
151 | p.add_option('-d', '--draft', | ||
152 | action='store_true', dest='draft', default=False, | ||
153 | help='If specified, upload as a draft.') | ||
154 | p.add_option('--ne', '--no-emails', | 184 | p.add_option('--ne', '--no-emails', |
155 | action='store_false', dest='notify', default=True, | 185 | action='store_false', dest='notify', default=True, |
156 | help='If specified, do not send emails on upload.') | 186 | help='do not send e-mails on upload') |
157 | p.add_option('-p', '--private', | 187 | p.add_option('-p', '--private', |
158 | action='store_true', dest='private', default=False, | 188 | action='store_true', dest='private', default=False, |
159 | help='If specified, upload as a private change.') | 189 | help='upload as a private change (deprecated; use --wip)') |
160 | p.add_option('-w', '--wip', | 190 | p.add_option('-w', '--wip', |
161 | action='store_true', dest='wip', default=False, | 191 | action='store_true', dest='wip', default=False, |
162 | help='If specified, upload as a work-in-progress change.') | 192 | help='upload as a work-in-progress change') |
163 | p.add_option('-o', '--push-option', | 193 | p.add_option('-o', '--push-option', |
164 | type='string', action='append', dest='push_options', | 194 | type='string', action='append', dest='push_options', |
165 | default=[], | 195 | default=[], |
166 | help='Additional push options to transmit') | 196 | help='additional push options to transmit') |
167 | p.add_option('-D', '--destination', '--dest', | 197 | p.add_option('-D', '--destination', '--dest', |
168 | type='string', action='store', dest='dest_branch', | 198 | type='string', action='store', dest='dest_branch', |
169 | metavar='BRANCH', | 199 | metavar='BRANCH', |
170 | help='Submit for review on this target branch.') | 200 | help='submit for review on this target branch') |
171 | 201 | p.add_option('-n', '--dry-run', | |
172 | # Options relating to upload hook. Note that verify and no-verify are NOT | 202 | dest='dryrun', default=False, action='store_true', |
173 | # opposites of each other, which is why they store to different locations. | 203 | help='do everything except actually upload the CL') |
174 | # We are using them to match 'git commit' syntax. | 204 | p.add_option('-y', '--yes', |
175 | # | 205 | default=False, action='store_true', |
176 | # Combinations: | 206 | help='answer yes to all safe prompts') |
177 | # - no-verify=False, verify=False (DEFAULT): | ||
178 | # If stdout is a tty, can prompt about running upload hooks if needed. | ||
179 | # If user denies running hooks, the upload is cancelled. If stdout is | ||
180 | # not a tty and we would need to prompt about upload hooks, upload is | ||
181 | # cancelled. | ||
182 | # - no-verify=False, verify=True: | ||
183 | # Always run upload hooks with no prompt. | ||
184 | # - no-verify=True, verify=False: | ||
185 | # Never run upload hooks, but upload anyway (AKA bypass hooks). | ||
186 | # - no-verify=True, verify=True: | ||
187 | # Invalid | ||
188 | p.add_option('--no-cert-checks', | 207 | p.add_option('--no-cert-checks', |
189 | dest='validate_certs', action='store_false', default=True, | 208 | dest='validate_certs', action='store_false', default=True, |
190 | help='Disable verifying ssl certs (unsafe).') | 209 | help='disable verifying ssl certs (unsafe)') |
191 | p.add_option('--no-verify', | 210 | RepoHook.AddOptionGroup(p, 'pre-upload') |
192 | dest='bypass_hooks', action='store_true', | ||
193 | help='Do not run the upload hook.') | ||
194 | p.add_option('--verify', | ||
195 | dest='allow_all_hooks', action='store_true', | ||
196 | help='Run the upload hook without prompting.') | ||
197 | 211 | ||
198 | def _SingleBranch(self, opt, branch, people): | 212 | def _SingleBranch(self, opt, branch, people): |
199 | project = branch.project | 213 | project = branch.project |
@@ -212,20 +226,24 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
212 | 226 | ||
213 | destination = opt.dest_branch or project.dest_branch or project.revisionExpr | 227 | destination = opt.dest_branch or project.dest_branch or project.revisionExpr |
214 | print('Upload project %s/ to remote branch %s%s:' % | 228 | print('Upload project %s/ to remote branch %s%s:' % |
215 | (project.relpath, destination, ' (draft)' if opt.draft else '')) | 229 | (project.relpath, destination, ' (private)' if opt.private else '')) |
216 | print(' branch %s (%2d commit%s, %s):' % ( | 230 | print(' branch %s (%2d commit%s, %s):' % ( |
217 | name, | 231 | name, |
218 | len(commit_list), | 232 | len(commit_list), |
219 | len(commit_list) != 1 and 's' or '', | 233 | len(commit_list) != 1 and 's' or '', |
220 | date)) | 234 | date)) |
221 | for commit in commit_list: | 235 | for commit in commit_list: |
222 | print(' %s' % commit) | 236 | print(' %s' % commit) |
223 | 237 | ||
224 | print('to %s (y/N)? ' % remote.review, end='') | 238 | print('to %s (y/N)? ' % remote.review, end='') |
225 | # TODO: When we require Python 3, use flush=True w/print above. | 239 | # TODO: When we require Python 3, use flush=True w/print above. |
226 | sys.stdout.flush() | 240 | sys.stdout.flush() |
227 | answer = sys.stdin.readline().strip().lower() | 241 | if opt.yes: |
228 | answer = answer in ('y', 'yes', '1', 'true', 't') | 242 | print('<--yes>') |
243 | answer = True | ||
244 | else: | ||
245 | answer = sys.stdin.readline().strip().lower() | ||
246 | answer = answer in ('y', 'yes', '1', 'true', 't') | ||
229 | 247 | ||
230 | if answer: | 248 | if answer: |
231 | if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD: | 249 | if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD: |
@@ -322,12 +340,12 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
322 | 340 | ||
323 | key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review | 341 | key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review |
324 | raw_list = project.config.GetString(key) | 342 | raw_list = project.config.GetString(key) |
325 | if not raw_list is None: | 343 | if raw_list is not None: |
326 | people[0].extend([entry.strip() for entry in raw_list.split(',')]) | 344 | people[0].extend([entry.strip() for entry in raw_list.split(',')]) |
327 | 345 | ||
328 | key = 'review.%s.autocopy' % project.GetBranch(name).remote.review | 346 | key = 'review.%s.autocopy' % project.GetBranch(name).remote.review |
329 | raw_list = project.config.GetString(key) | 347 | raw_list = project.config.GetString(key) |
330 | if not raw_list is None and len(people[0]) > 0: | 348 | if raw_list is not None and len(people[0]) > 0: |
331 | people[1].extend([entry.strip() for entry in raw_list.split(',')]) | 349 | people[1].extend([entry.strip() for entry in raw_list.split(',')]) |
332 | 350 | ||
333 | def _FindGerritChange(self, branch): | 351 | def _FindGerritChange(self, branch): |
@@ -364,7 +382,11 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
364 | print('Continue uploading? (y/N) ', end='') | 382 | print('Continue uploading? (y/N) ', end='') |
365 | # TODO: When we require Python 3, use flush=True w/print above. | 383 | # TODO: When we require Python 3, use flush=True w/print above. |
366 | sys.stdout.flush() | 384 | sys.stdout.flush() |
367 | a = sys.stdin.readline().strip().lower() | 385 | if opt.yes: |
386 | print('<--yes>') | ||
387 | a = 'yes' | ||
388 | else: | ||
389 | a = sys.stdin.readline().strip().lower() | ||
368 | if a not in ('y', 'yes', 't', 'true', 'on'): | 390 | if a not in ('y', 'yes', 't', 'true', 'on'): |
369 | print("skipping upload", file=sys.stderr) | 391 | print("skipping upload", file=sys.stderr) |
370 | branch.uploaded = False | 392 | branch.uploaded = False |
@@ -376,12 +398,51 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
376 | key = 'review.%s.uploadtopic' % branch.project.remote.review | 398 | key = 'review.%s.uploadtopic' % branch.project.remote.review |
377 | opt.auto_topic = branch.project.config.GetBoolean(key) | 399 | opt.auto_topic = branch.project.config.GetBoolean(key) |
378 | 400 | ||
401 | def _ExpandCommaList(value): | ||
402 | """Split |value| up into comma delimited entries.""" | ||
403 | if not value: | ||
404 | return | ||
405 | for ret in value.split(','): | ||
406 | ret = ret.strip() | ||
407 | if ret: | ||
408 | yield ret | ||
409 | |||
410 | # Check if hashtags should be included. | ||
411 | key = 'review.%s.uploadhashtags' % branch.project.remote.review | ||
412 | hashtags = set(_ExpandCommaList(branch.project.config.GetString(key))) | ||
413 | for tag in opt.hashtags: | ||
414 | hashtags.update(_ExpandCommaList(tag)) | ||
415 | if opt.hashtag_branch: | ||
416 | hashtags.add(branch.name) | ||
417 | |||
418 | # Check if labels should be included. | ||
419 | key = 'review.%s.uploadlabels' % branch.project.remote.review | ||
420 | labels = set(_ExpandCommaList(branch.project.config.GetString(key))) | ||
421 | for label in opt.labels: | ||
422 | labels.update(_ExpandCommaList(label)) | ||
423 | # Basic sanity check on label syntax. | ||
424 | for label in labels: | ||
425 | if not re.match(r'^.+[+-][0-9]+$', label): | ||
426 | print('repo: error: invalid label syntax "%s": labels use forms ' | ||
427 | 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr) | ||
428 | sys.exit(1) | ||
429 | |||
430 | # Handle e-mail notifications. | ||
431 | if opt.notify is False: | ||
432 | notify = 'NONE' | ||
433 | else: | ||
434 | key = 'review.%s.uploadnotify' % branch.project.remote.review | ||
435 | notify = branch.project.config.GetString(key) | ||
436 | |||
379 | destination = opt.dest_branch or branch.project.dest_branch | 437 | destination = opt.dest_branch or branch.project.dest_branch |
380 | 438 | ||
381 | # Make sure our local branch is not setup to track a different remote branch | 439 | # Make sure our local branch is not setup to track a different remote branch |
382 | merge_branch = self._GetMergeBranch(branch.project) | 440 | merge_branch = self._GetMergeBranch(branch.project) |
383 | if destination: | 441 | if destination: |
384 | full_dest = 'refs/heads/%s' % destination | 442 | full_dest = destination |
443 | if not full_dest.startswith(R_HEADS): | ||
444 | full_dest = R_HEADS + full_dest | ||
445 | |||
385 | if not opt.dest_branch and merge_branch and merge_branch != full_dest: | 446 | if not opt.dest_branch and merge_branch and merge_branch != full_dest: |
386 | print('merge branch %s does not match destination branch %s' | 447 | print('merge branch %s does not match destination branch %s' |
387 | % (merge_branch, full_dest)) | 448 | % (merge_branch, full_dest)) |
@@ -392,10 +453,12 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
392 | continue | 453 | continue |
393 | 454 | ||
394 | branch.UploadForReview(people, | 455 | branch.UploadForReview(people, |
456 | dryrun=opt.dryrun, | ||
395 | auto_topic=opt.auto_topic, | 457 | auto_topic=opt.auto_topic, |
396 | draft=opt.draft, | 458 | hashtags=hashtags, |
459 | labels=labels, | ||
397 | private=opt.private, | 460 | private=opt.private, |
398 | notify=None if opt.notify else 'NONE', | 461 | notify=notify, |
399 | wip=opt.wip, | 462 | wip=opt.wip, |
400 | dest_branch=destination, | 463 | dest_branch=destination, |
401 | validate_certs=opt.validate_certs, | 464 | validate_certs=opt.validate_certs, |
@@ -418,18 +481,18 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
418 | else: | 481 | else: |
419 | fmt = '\n (%s)' | 482 | fmt = '\n (%s)' |
420 | print(('[FAILED] %-15s %-15s' + fmt) % ( | 483 | print(('[FAILED] %-15s %-15s' + fmt) % ( |
421 | branch.project.relpath + '/', \ | 484 | branch.project.relpath + '/', |
422 | branch.name, \ | 485 | branch.name, |
423 | str(branch.error)), | 486 | str(branch.error)), |
424 | file=sys.stderr) | 487 | file=sys.stderr) |
425 | print() | 488 | print() |
426 | 489 | ||
427 | for branch in todo: | 490 | for branch in todo: |
428 | if branch.uploaded: | 491 | if branch.uploaded: |
429 | print('[OK ] %-15s %s' % ( | 492 | print('[OK ] %-15s %s' % ( |
430 | branch.project.relpath + '/', | 493 | branch.project.relpath + '/', |
431 | branch.name), | 494 | branch.name), |
432 | file=sys.stderr) | 495 | file=sys.stderr) |
433 | 496 | ||
434 | if have_errors: | 497 | if have_errors: |
435 | sys.exit(1) | 498 | sys.exit(1) |
@@ -437,68 +500,72 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
437 | def _GetMergeBranch(self, project): | 500 | def _GetMergeBranch(self, project): |
438 | p = GitCommand(project, | 501 | p = GitCommand(project, |
439 | ['rev-parse', '--abbrev-ref', 'HEAD'], | 502 | ['rev-parse', '--abbrev-ref', 'HEAD'], |
440 | capture_stdout = True, | 503 | capture_stdout=True, |
441 | capture_stderr = True) | 504 | capture_stderr=True) |
442 | p.Wait() | 505 | p.Wait() |
443 | local_branch = p.stdout.strip() | 506 | local_branch = p.stdout.strip() |
444 | p = GitCommand(project, | 507 | p = GitCommand(project, |
445 | ['config', '--get', 'branch.%s.merge' % local_branch], | 508 | ['config', '--get', 'branch.%s.merge' % local_branch], |
446 | capture_stdout = True, | 509 | capture_stdout=True, |
447 | capture_stderr = True) | 510 | capture_stderr=True) |
448 | p.Wait() | 511 | p.Wait() |
449 | merge_branch = p.stdout.strip() | 512 | merge_branch = p.stdout.strip() |
450 | return merge_branch | 513 | return merge_branch |
451 | 514 | ||
515 | @staticmethod | ||
516 | def _GatherOne(opt, project): | ||
517 | """Figure out the upload status for |project|.""" | ||
518 | if opt.current_branch: | ||
519 | cbr = project.CurrentBranch | ||
520 | up_branch = project.GetUploadableBranch(cbr) | ||
521 | avail = [up_branch] if up_branch else None | ||
522 | else: | ||
523 | avail = project.GetUploadableBranches(opt.branch) | ||
524 | return (project, avail) | ||
525 | |||
452 | def Execute(self, opt, args): | 526 | def Execute(self, opt, args): |
453 | project_list = self.GetProjects(args) | 527 | projects = self.GetProjects(args) |
454 | pending = [] | 528 | |
455 | reviewers = [] | 529 | def _ProcessResults(_pool, _out, results): |
456 | cc = [] | 530 | pending = [] |
457 | branch = None | 531 | for result in results: |
458 | 532 | project, avail = result | |
459 | if opt.branch: | 533 | if avail is None: |
460 | branch = opt.branch | 534 | print('repo: error: %s: Unable to upload branch "%s". ' |
461 | 535 | 'You might be able to fix the branch by running:\n' | |
462 | for project in project_list: | 536 | ' git branch --set-upstream-to m/%s' % |
463 | if opt.current_branch: | 537 | (project.relpath, project.CurrentBranch, self.manifest.branch), |
464 | cbr = project.CurrentBranch | ||
465 | up_branch = project.GetUploadableBranch(cbr) | ||
466 | if up_branch: | ||
467 | avail = [up_branch] | ||
468 | else: | ||
469 | avail = None | ||
470 | print('ERROR: Current branch (%s) not uploadable. ' | ||
471 | 'You may be able to type ' | ||
472 | '"git branch --set-upstream-to m/master" to fix ' | ||
473 | 'your branch.' % str(cbr), | ||
474 | file=sys.stderr) | 538 | file=sys.stderr) |
475 | else: | 539 | elif avail: |
476 | avail = project.GetUploadableBranches(branch) | 540 | pending.append(result) |
477 | if avail: | 541 | return pending |
478 | pending.append((project, avail)) | 542 | |
543 | pending = self.ExecuteInParallel( | ||
544 | opt.jobs, | ||
545 | functools.partial(self._GatherOne, opt), | ||
546 | projects, | ||
547 | callback=_ProcessResults) | ||
479 | 548 | ||
480 | if not pending: | 549 | if not pending: |
481 | print("no branches ready for upload", file=sys.stderr) | 550 | if opt.branch is None: |
482 | return | 551 | print('repo: error: no branches ready for upload', file=sys.stderr) |
483 | 552 | else: | |
484 | if not opt.bypass_hooks: | 553 | print('repo: error: no branches named "%s" ready for upload' % |
485 | hook = RepoHook('pre-upload', self.manifest.repo_hooks_project, | 554 | (opt.branch,), file=sys.stderr) |
486 | self.manifest.topdir, | 555 | return 1 |
487 | self.manifest.manifestProject.GetRemote('origin').url, | 556 | |
488 | abort_if_user_denies=True) | 557 | pending_proj_names = [project.name for (project, available) in pending] |
489 | pending_proj_names = [project.name for (project, available) in pending] | 558 | pending_worktrees = [project.worktree for (project, available) in pending] |
490 | pending_worktrees = [project.worktree for (project, available) in pending] | 559 | hook = RepoHook.FromSubcmd( |
491 | try: | 560 | hook_type='pre-upload', manifest=self.manifest, |
492 | hook.Run(opt.allow_all_hooks, project_list=pending_proj_names, | 561 | opt=opt, abort_if_user_denies=True) |
493 | worktree_list=pending_worktrees) | 562 | if not hook.Run( |
494 | except HookError as e: | 563 | project_list=pending_proj_names, |
495 | print("ERROR: %s" % str(e), file=sys.stderr) | 564 | worktree_list=pending_worktrees): |
496 | return | 565 | return 1 |
497 | 566 | ||
498 | if opt.reviewers: | 567 | reviewers = _SplitEmails(opt.reviewers) if opt.reviewers else [] |
499 | reviewers = _SplitEmails(opt.reviewers) | 568 | cc = _SplitEmails(opt.cc) if opt.cc else [] |
500 | if opt.cc: | ||
501 | cc = _SplitEmails(opt.cc) | ||
502 | people = (reviewers, cc) | 569 | people = (reviewers, cc) |
503 | 570 | ||
504 | if len(pending) == 1 and len(pending[0][1]) == 1: | 571 | if len(pending) == 1 and len(pending[0][1]) == 1: |