Add parent diff support to the JSON API and post-review
Updated 7 months ago
| Christian Hammond | Reviewers | ||
| trunk | reviewboard | ||
| None | Review Board SVN | ||
This adds support for uploading parent diffs in the JSON API, and also introduces a --parent flag to post-review for doing parent diffs on supporting repository types (currently only git-svn). It should be pretty easy to add the support to the other types.
Posted some standard diffs to make sure they didn't break. Then posted a diff with a parent diff. Saw that it uploaded as I expected.
Diff revision 2 (Latest)
|
1
2
|
|
|
1
2
|
- /trunk/reviewboard/contrib/tools/post-review: 69 changes [ 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 ]
- /trunk/reviewboard/webapi/json.py: 2 changes [ 1 2 ]
| /trunk/reviewboard/contrib/tools/post-review | |||
|---|---|---|---|
| Revision 1377 | New Change | ||
| ... | 68 lines hidden [Expand] | ||
| 69 | ### |
69 | ### |
| 70 | # End user-settable variables. |
70 | # End user-settable variables. |
| 71 | ### |
71 | ### |
| 72 | 72 | ||
| 73 | 73 | ||
| 74 | VERSION = "0.7" |
74 | VERSION = "0.8" |
| 75 | 75 | ||
| 76 | user_config = None |
76 | user_config = None |
| 77 | tempfiles = [] |
77 | tempfiles = [] |
| 78 | options = None |
78 | options = None |
| 79 | 79 | ||
| ... | 4 lines hidden [Expand] | ||
| 84 | 84 | ||
| 85 | class RepositoryInfo: |
85 | class RepositoryInfo: |
| 86 | """ |
86 | """ |
| 87 | A representation of a source code repository. |
87 | A representation of a source code repository. |
| 88 | """ |
88 | """ |
| 89 | def __init__(self, path=None, base_path=None, supports_changesets=False): |
89 | def __init__(self, path=None, base_path=None, supports_changesets=False, |
| 90 | supports_parent_diffs=False): |
||
| 90 | self.path = path |
91 | self.path = path |
| 91 | self.base_path = base_path |
92 | self.base_path = base_path |
| 92 | self.supports_changesets = supports_changesets |
93 | self.supports_changesets = supports_changesets |
| 94 | self.supports_parent_diffs = supports_parent_diffs |
||
| 93 | 95 | ||
| 94 | def __str__(self): |
96 | def __str__(self): |
| 95 | return "Path: %s, Base path: %s, Supports changesets: %s" % \ |
97 | return "Path: %s, Base path: %s, Supports changesets: %s" % \ |
| 96 | (self.path, self.base_path, self.supports_changesets) |
98 | (self.path, self.base_path, self.supports_changesets) |
| 97 | 99 | ||
| ... | 175 lines hidden [Expand] | ||
| 273 | """ |
275 | """ |
| 274 | self.api_post("api/json/reviewrequests/%s/draft/save/" % |
276 | self.api_post("api/json/reviewrequests/%s/draft/save/" % |
| 275 | review_request['id']) |
277 | review_request['id']) |
| 276 | debug("Review request draft saved") |
278 | debug("Review request draft saved") |
| 277 | 279 | ||
| 278 | def upload_diff(self, review_request, diff_content): |
280 | def upload_diff(self, review_request, diff_content, parent_diff_content): |
| 279 | """ |
281 | """ |
| 280 | Uploads a diff to a Review Board server. |
282 | Uploads a diff to a Review Board server. |
| 281 | """ |
283 | """ |
| 282 | debug("Uploading diff, size: %d" % (len(diff_content),)) |
284 | debug("Uploading diff, size: %d" % len(diff_content)) |
| 285 | |||
| 286 | if parent_diff_content: |
||
| 287 | debug("Uploading parent diff, size: %d" % len(parent_diff_content)) |
||
| 288 | |||
| 283 | fields = {} |
289 | fields = {} |
| 290 | files = {} |
||
| 284 | 291 | ||
| 285 | if self.info.base_path: |
292 | if self.info.base_path: |
| 286 | fields['basedir'] = self.info.base_path |
293 | fields['basedir'] = self.info.base_path |
| 287 | 294 | ||
| 295 | files['path'] = { |
||
| 296 | 'filename': 'diff', |
||
| 297 | 'content': diff_content |
||
| 298 | } |
||
| 299 | |||
| 300 | if parent_diff_content: |
||
| 301 | files['parent_diff_path'] = { |
||
| 302 | 'filename': 'parent_diff', |
||
| 303 | 'content': parent_diff_content |
||
| 304 | } |
||
| 305 | |||
| 288 | self.api_post('api/json/reviewrequests/%s/diff/new/' % |
306 | self.api_post('api/json/reviewrequests/%s/diff/new/' % |
| 289 | review_request['id'], fields, |
307 | review_request['id'], fields, files) |
| 290 | {'path': {'filename': 'diff', |
||
| 291 | 'content': diff_content}}) |
||
| 292 | 308 | ||
| 293 | def publish(self, review_request): |
309 | def publish(self, review_request): |
| 294 | """ |
310 | """ |
| 295 | Publishes a review request. |
311 | Publishes a review request. |
| 296 | """ |
312 | """ |
| ... | 152 lines hidden [Expand] | ||
| 449 | return server_url |
465 | return server_url |
| 450 | 466 | ||
| 451 | return None |
467 | return None |
| 452 | 468 | ||
| 453 | def diff(self, args): |
469 | def diff(self, args): |
| 454 | return None |
470 | """ |
| 471 | Returns the generated diff and optional parent diff for this |
||
| 472 | repository. |
||
| 473 | |||
| 474 | The returned tuple is (diff_string, parent_diff_string) |
||
| 475 | """ |
||
| 476 | return (None, None) |
||
| 455 | 477 | ||
| 456 | def diff_between_revisions(self, revision_range): |
478 | def diff_between_revisions(self, revision_range): |
| 479 | """ |
||
| 480 | Returns the generated diff between revisions in the repository. |
||
| 481 | """ |
||
| 457 | return None |
482 | return None |
| 458 | 483 | ||
| 459 | def add_options(self, parser): |
484 | def add_options(self, parser): |
| 460 | """ |
485 | """ |
| 461 | Adds options to an OptionParser. |
486 | Adds options to an OptionParser. |
| ... | 40 lines hidden [Expand] | ||
| 502 | return RepositoryInfo(path=repository_path) |
527 | return RepositoryInfo(path=repository_path) |
| 503 | 528 | ||
| 504 | def diff(self, files): |
529 | def diff(self, files): |
| 505 | """ |
530 | """ |
| 506 | Performs a diff across all modified files in a CVS repository. |
531 | Performs a diff across all modified files in a CVS repository. |
| 532 | |||
| 533 | CVS repositories do not support branches of branches in a way that |
||
| 534 | makes parent diffs possible, so we never return a parent diff |
||
| 535 | (the second value in the tuple). |
||
| 507 | """ |
536 | """ |
| 508 | return self.do_diff(' '.join(files)) |
537 | return (self.do_diff(' '.join(files)), None) |
| 509 | 538 | ||
| 510 | def diff_between_revisions(self, revision_range): |
539 | def diff_between_revisions(self, revision_range): |
| 511 | """ |
540 | """ |
| 512 | Performs a diff between 2 revisions of a CVS repository. |
541 | Performs a diff between 2 revisions of a CVS repository. |
| 513 | """ |
542 | """ |
| 514 | rev_str = '' |
543 | rev_str = '' |
| 515 | 544 | ||
| 516 | for rev in revision_range.split(":"): |
545 | for rev in revision_range.split(":"): |
| 517 | rev_str += "-r %s" % rev |
546 | rev_str += "-r %s" % rev |
| 518 | 547 | ||
| 519 | return self.do_diff(rev_str) |
548 | return self.do_diff(rev_str) |
| 520 | 549 | ||
| 521 | def do_diff(self, params): |
550 | def do_diff(self, params): |
| 551 | """ |
||
| 552 | Performs the actual diff operation through cvs diff, handling |
||
| 553 | fake errors generated by CVS. |
||
| 554 | """ |
||
| 522 | # Diff returns "1" if differences were found. |
555 | # Diff returns "1" if differences were found. |
| 523 | return execute('cvs diff -u %s' % params, |
556 | return execute('cvs diff -u %s' % params, |
| 524 | extra_ignore_errors=(1,)) |
557 | extra_ignore_errors=(1,)) |
| 525 | 558 | ||
| 526 | 559 | ||
| ... | 53 lines hidden [Expand] | ||
| 580 | return get_url_prop(repository_info.path) |
613 | return get_url_prop(repository_info.path) |
| 581 | 614 | ||
| 582 | def diff(self, files): |
615 | def diff(self, files): |
| 583 | """ |
616 | """ |
| 584 | Performs a diff across all modified files in a Subversion repository. |
617 | Performs a diff across all modified files in a Subversion repository. |
| 618 | |||
| 619 | SVN repositories do not support branches of branches in a way that |
||
| 620 | makes parent diffs possible, so we never return a parent diff |
||
| 621 | (the second value in the tuple). |
||
| 585 | """ |
622 | """ |
| 586 | return self.do_diff('svn diff --diff-cmd=diff %s' % ' '.join(files)) |
623 | return (self.do_diff('svn diff --diff-cmd=diff %s' % ' '.join(files)), |
| 624 | None) |
||
| 587 | 625 | ||
| 588 | def diff_between_revisions(self, revision_range): |
626 | def diff_between_revisions(self, revision_range): |
| 589 | """ |
627 | """ |
| 590 | Performs a diff between 2 revisions of a Subversion repository. |
628 | Performs a diff between 2 revisions of a Subversion repository. |
| 591 | """ |
629 | """ |
| 592 | return self.do_diff('svn diff --diff-cmd=diff -r %s' % revision_range) |
630 | return self.do_diff('svn diff --diff-cmd=diff -r %s' % revision_range) |
| 593 | 631 | ||
| 594 | def do_diff(self, cmd): |
632 | def do_diff(self, cmd): |
| 633 | """ |
||
| 634 | Performs the actual diff operation, handling renames and converting |
||
| 635 | paths to absolute. |
||
| 636 | """ |
||
| 595 | diff = execute(cmd, split_lines=True) |
637 | diff = execute(cmd, split_lines=True) |
| 596 | diff = self.handle_renames(diff) |
638 | diff = self.handle_renames(diff) |
| 597 | diff = self.convert_to_absolute_paths(diff) |
639 | diff = self.convert_to_absolute_paths(diff) |
| 598 | 640 | ||
| 599 | return ''.join(diff) |
641 | return ''.join(diff) |
| ... | 98 lines hidden [Expand] | ||
| 698 | return parts |
740 | return parts |
| 699 | 741 | ||
| 700 | # strip off ending newline, and return it as the second component |
742 | # strip off ending newline, and return it as the second component |
| 701 | return [s.split('\n')[0], '\n'] |
743 | return [s.split('\n')[0], '\n'] |
| 702 | 744 | ||
| 745 | |||
| 703 | class PerforceClient(SCMClient): |
746 | class PerforceClient(SCMClient): |
| 704 | """ |
747 | """ |
| 705 | A wrapper around the p4 Perforce tool that fetches repository information |
748 | A wrapper around the p4 Perforce tool that fetches repository information |
| 706 | and generates compatible diffs. |
749 | and generates compatible diffs. |
| 707 | """ |
750 | """ |
| ... | 56 lines hidden [Expand] | ||
| 764 | description = description[line_num+2:] |
807 | description = description[line_num+2:] |
| 765 | 808 | ||
| 766 | cwd = os.getcwd() |
809 | cwd = os.getcwd() |
| 767 | diff_lines = [] |
810 | diff_lines = [] |
| 768 | 811 | ||
| 769 | |||
| 770 | empty_filename = make_tempfile() |
812 | empty_filename = make_tempfile() |
| 771 | tmp_diff_from_filename = make_tempfile() |
813 | tmp_diff_from_filename = make_tempfile() |
| 772 | tmp_diff_to_filename = make_tempfile() |
814 | tmp_diff_to_filename = make_tempfile() |
| 773 | 815 | ||
| 774 | for line in description: |
816 | for line in description: |
| ... | 61 lines hidden [Expand] | ||
| 836 | old_file = tmp_diff_from_filename |
878 | old_file = tmp_diff_from_filename |
| 837 | changetype_short = "D" |
879 | changetype_short = "D" |
| 838 | else: |
880 | else: |
| 839 | die("Unknown change type '%s' for %s" % (changetype, depot_path)) |
881 | die("Unknown change type '%s' for %s" % (changetype, depot_path)) |
| 840 | 882 | ||
| 841 | |||
| 842 | diff_cmd = 'diff -urNp "%s" "%s"' % (old_file, new_file) |
883 | diff_cmd = 'diff -urNp "%s" "%s"' % (old_file, new_file) |
| 843 | # Diff returns "1" if differences were found. |
884 | # Diff returns "1" if differences were found. |
| 844 | dl = execute(diff_cmd, extra_ignore_errors=(1,)).splitlines(True) |
885 | dl = execute(diff_cmd, extra_ignore_errors=(1,)).splitlines(True) |
| 845 | 886 | ||
| 846 | if local_name.startswith(cwd): |
887 | if local_name.startswith(cwd): |
| ... | 7 lines hidden [Expand] | ||
| 854 | # "Binary files " |
895 | # "Binary files " |
| 855 | if len(dl) == 1 and \ |
896 | if len(dl) == 1 and \ |
| 856 | dl[0] == ('Files %s and %s differ'% (old_file, new_file)): |
897 | dl[0] == ('Files %s and %s differ'% (old_file, new_file)): |
| 857 | dl = ['Binary files %s and %s differ'% (old_file, new_file)] |
898 | dl = ['Binary files %s and %s differ'% (old_file, new_file)] |
| 858 | 899 | ||
| 859 | |||
| 860 | if dl == [] or dl[0].startswith("Binary files "): |
900 | if dl == [] or dl[0].startswith("Binary files "): |
| 861 | if dl == []: |
901 | if dl == []: |
| 862 | print "Warning: %s in your changeset is unmodified" % \ |
902 | print "Warning: %s in your changeset is unmodified" % \ |
| 863 | local_path |
903 | local_path |
| 864 | 904 | ||
| 865 | dl.insert(0, "==== %s#%s ==%s== %s ====\n" % \ |
905 | dl.insert(0, "==== %s#%s ==%s== %s ====\n" % \ |
| 866 | (depot_path, base_revision, changetype_short, local_path)) |
906 | (depot_path, base_revision, changetype_short, local_path)) |
| 867 | else: |
907 | else: |
| 868 | |||
| 869 | m = re.search(r'(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)', dl[1]) |
908 | m = re.search(r'(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)', dl[1]) |
| 870 | if m: |
909 | if m: |
| 871 | timestamp = m.group(1) |
910 | timestamp = m.group(1) |
| 872 | else: |
911 | else: |
| 873 | # Thu Sep 3 11:24:48 2007 |
912 | # Thu Sep 3 11:24:48 2007 |
| ... | 25 lines hidden [Expand] | ||
| 899 | dl[0] = "--- %s\t%s#%s\n" % (local_path, depot_path, base_revision) |
938 | dl[0] = "--- %s\t%s#%s\n" % (local_path, depot_path, base_revision) |
| 900 | dl[1] = "+++ %s\t%s\n" % (local_path, timestamp) |
939 | dl[1] = "+++ %s\t%s\n" % (local_path, timestamp) |
| 901 | 940 | ||
| 902 | diff_lines += dl |
941 | diff_lines += dl |
| 903 | 942 | ||
| 904 | |||
| 905 | os.unlink(empty_filename) |
943 | os.unlink(empty_filename) |
| 906 | os.unlink(tmp_diff_from_filename) |
944 | os.unlink(tmp_diff_from_filename) |
| 907 | os.unlink(tmp_diff_to_filename) |
945 | os.unlink(tmp_diff_to_filename) |
| 908 | 946 | ||
| 909 | return ''.join(diff_lines) |
947 | return (''.join(diff_lines), None) |
| 910 | 948 | ||
| 911 | def _write_file(self, depot_path, tmpfile): |
949 | def _write_file(self, depot_path, tmpfile): |
| 912 | """ |
950 | """ |
| 913 | Grabs a file from Perforce and writes it to a temp file. We do this |
951 | Grabs a file from Perforce and writes it to a temp file. We do this |
| 914 | wrather than telling p4 print to write it out in order to work around |
952 | wrather than telling p4 print to write it out in order to work around |
| ... | 44 lines hidden [Expand] | ||
| 959 | # We save data here to use it as a fallback. See below |
997 | # We save data here to use it as a fallback. See below |
| 960 | local_data = data.strip() |
998 | local_data = data.strip() |
| 961 | 999 | ||
| 962 | # We are going to search .hg/hgrc for the default path. |
1000 | # We are going to search .hg/hgrc for the default path. |
| 963 | file_name = os.path.join(local_data,'.hg', 'hgrc') |
1001 | file_name = os.path.join(local_data,'.hg', 'hgrc') |
| 964 | if not os.path.exists(file_name): |
1002 | if not os.path.exists(file_name): |
| 965 | return RepositoryInfo(path=local_data, base_path='/') |
1003 | return RepositoryInfo(path=local_data, base_path='/', |
| 1004 | supports_parent_diffs=True) |
||
| 966 | 1005 | ||
| 967 | f = open(file_name) |
1006 | f = open(file_name) |
| 968 | data = f.read() |
1007 | data = f.read() |
| 969 | f.close() |
1008 | f.close() |
| 970 | 1009 | ||
| 971 | m = re.search(r'^default\s+=\s+(.+)$', data, re.M) |
1010 | m = re.search(r'^default\s+=\s+(.+)$', data, re.M) |
| 972 | if not m: |
1011 | if not m: |
| 973 | # Return the local path, if no default value is found. |
1012 | # Return the local path, if no default value is found. |
| 974 | return RepositoryInfo(path=local_data, base_path='/') |
1013 | return RepositoryInfo(path=local_data, base_path='/', |
| 1014 | supports_parent_diffs=True) |
||
| 975 | 1015 | ||
| 976 | path = m.group(1).strip() |
1016 | path = m.group(1).strip() |
| 977 | 1017 | ||
| 978 | return RepositoryInfo(path=path, base_path='') |
1018 | return RepositoryInfo(path=path, base_path='', |
| 1019 | supports_parent_diffs=True) |
||
| 979 | 1020 | ||
| 980 | def diff(self, files): |
1021 | def diff(self, files): |
| 981 | """ |
1022 | """ |
| 982 | Performs a diff across all modified files in a Mercurial repository. |
1023 | Performs a diff across all modified files in a Mercurial repository. |
| 983 | """ |
1024 | """ |
| 984 | return execute('hg diff %s' % ' '.join(files)) |
1025 | # We don't support parent diffs with Mercurial yet, so return None |
| 1026 | # for the parent diff. |
||
| 1027 | return (execute('hg diff %s' % ' '.join(files)), None) |
||
| 985 | 1028 | ||
| 986 | def diff_between_revisions(self, revision_range): |
1029 | def diff_between_revisions(self, revision_range): |
| 987 | """ |
1030 | """ |
| 988 | Performs a diff between 2 revisions of a Mercurial repository. |
1031 | Performs a diff between 2 revisions of a Mercurial repository. |
| 989 | """ |
1032 | """ |
| ... | 26 lines hidden [Expand] | ||
| 1016 | m = re.search(r'^URL: (.+)$', data, re.M) |
1059 | m = re.search(r'^URL: (.+)$', data, re.M) |
| 1017 | 1060 | ||
| 1018 | if m: |
1061 | if m: |
| 1019 | base_path = m.group(1)[len(path):] |
1062 | base_path = m.group(1)[len(path):] |
| 1020 | self.type = "svn" |
1063 | self.type = "svn" |
| 1021 | return RepositoryInfo(path=path, base_path=base_path) |
1064 | return RepositoryInfo(path=path, base_path=base_path, |
| 1065 | supports_parent_diffs=True) |
||
| 1022 | else: |
1066 | else: |
| 1023 | # Versions of git-svn before 1.5.4 don't (appear to) support |
1067 | # Versions of git-svn before 1.5.4 don't (appear to) support |
| 1024 | # 'git svn info'. If we fail because of an older git install, |
1068 | # 'git svn info'. If we fail because of an older git install, |
| 1025 | # here, figure out what version of git is installed and give |
1069 | # here, figure out what version of git is installed and give |
| 1026 | # the user a hint about what to do next. |
1070 | # the user a hint about what to do next. |
| ... | 45 lines hidden [Expand] | ||
| 1072 | 1116 | ||
| 1073 | return None |
1117 | return None |
| 1074 | 1118 | ||
| 1075 | def diff(self, args): |
1119 | def diff(self, args): |
| 1076 | """ |
1120 | """ |
| 1077 | Performs a diff across all modified files in the branch. |
1121 | Performs a diff across all modified files in the branch, taking into |
| 1122 | account a parent branch. |
||
| 1078 | """ |
1123 | """ |
| 1079 | if len(args) == 0: |
1124 | parent_branch = options.parent_branch or "master" |
| 1080 | branch_against = "master" |
1125 | |
| 1081 | elif len(args) == 1: |
1126 | diff_lines = self.make_diff(parent_branch) |
| 1082 | branch_against = args[0] |
1127 | |
| 1128 | if parent_branch != "master": |
||
| 1129 | parent_diff_lines = self.make_diff("master", parent_branch) |
||
| 1083 | else: |
1130 | else: |
| 1084 | print "No more than one branch can be supplied." |
1131 | parent_diff_lines = None |
| 1085 | sys.exit(1) |
1132 | |
| 1133 | return (diff_lines, parent_diff_lines) |
||
| 1086 | 1134 | ||
| 1087 | diff_lines = execute("git diff --no-color --no-prefix -r -u %s.." % |
1135 | def make_diff(self, parent_branch, source_branch=""): |
| 1088 | branch_against, |
1136 | """ |
| 1137 | Performs a diff on a particular branch range. |
||
| 1138 | """ |
||
| 1139 | diff_lines = execute("git diff --no-color --no-prefix -r -u %s..%s" % |
||
| 1140 | (parent_branch, source_branch), |
||
| 1089 | split_lines=True) |
1141 | split_lines=True) |
| 1090 | 1142 | ||
| 1091 | if self.type == "svn": |
1143 | if self.type == "svn": |
| 1092 | return self.make_svn_diff(branch_against, diff_lines) |
1144 | return self.make_svn_diff(parent_branch, diff_lines) |
| 1093 | 1145 | ||
| 1094 | return None |
1146 | return None |
| 1095 | 1147 | ||
| 1096 | 1148 | ||
| 1097 | def make_svn_diff(self, branch_against, diff_lines): |
1149 | def make_svn_diff(self, parent_branch, diff_lines): |
| 1098 | """ |
1150 | """ |
| 1099 | Formats the output of git diff such that it's in a form that |
1151 | Formats the output of git diff such that it's in a form that |
| 1100 | svn diff would generate. This is needed so the SVNTool in Review |
1152 | svn diff would generate. This is needed so the SVNTool in Review |
| 1101 | Board can properly parse this diff. |
1153 | Board can properly parse this diff. |
| 1102 | """ |
1154 | """ |
| 1103 | rev = execute("git-svn find-rev %s" % branch_against).strip() |
1155 | rev = execute("git-svn find-rev master").strip() |
| 1104 | 1156 | ||
| 1105 | if not rev: |
1157 | if not rev: |
| 1106 | return None |
1158 | return None |
| 1107 | 1159 | ||
| 1108 | diff_data = "" |
1160 | diff_data = "" |
| ... | 40 lines hidden [Expand] | ||
| 1149 | 1201 | ||
| 1150 | def debug(s): |
1202 | def debug(s): |
| 1151 | """ |
1203 | """ |
| 1152 | Prints debugging information if post-review was run with --debug |
1204 | Prints debugging information if post-review was run with --debug |
| 1153 | """ |
1205 | """ |
| 1154 | if options.debug: |
1206 | if options and options.debug: |
| 1155 | print ">>> %s" % s |
1207 | print ">>> %s" % s |
| 1156 | 1208 | ||
| 1157 | 1209 | ||
| 1158 | def make_tempfile(): |
1210 | def make_tempfile(): |
| 1159 | """ |
1211 | """ |
| ... | 26 lines hidden [Expand] | ||
| 1186 | def execute(command, split_lines=False, ignore_errors=False, |
1238 | def execute(command, split_lines=False, ignore_errors=False, |
| 1187 | extra_ignore_errors=()): |
1239 | extra_ignore_errors=()): |
| 1188 | """ |
1240 | """ |
| 1189 | Utility function to execute a command and return the output. |
1241 | Utility function to execute a command and return the output. |
| 1190 | """ |
1242 | """ |
| 1243 | debug(command) |
||
| 1244 | |||
| 1191 | if sys.platform.startswith('win'): |
1245 | if sys.platform.startswith('win'): |
| 1192 | p = subprocess.Popen(command, |
1246 | p = subprocess.Popen(command, |
| 1193 | stdin=subprocess.PIPE, |
1247 | stdin=subprocess.PIPE, |
| 1194 | stdout=subprocess.PIPE, |
1248 | stdout=subprocess.PIPE, |
| 1195 | stderr=subprocess.STDOUT, |
1249 | stderr=subprocess.STDOUT, |
| ... | 59 lines hidden [Expand] | ||
| 1255 | pass |
1309 | pass |
| 1256 | 1310 | ||
| 1257 | return config |
1311 | return config |
| 1258 | 1312 | ||
| 1259 | 1313 | ||
| 1260 | def tempt_fate(server, tool, changenum, diff_content=None, submit_as=None): |
1314 | def tempt_fate(server, tool, changenum, diff_content=None, |
| 1315 | parent_diff_content=None, submit_as=None): |
||
| 1261 | """ |
1316 | """ |
| 1262 | Attempts to create a review request on a Review Board server and upload |
1317 | Attempts to create a review request on a Review Board server and upload |
| 1263 | a diff. On success, the review request path is displayed. |
1318 | a diff. On success, the review request path is displayed. |
| 1264 | """ |
1319 | """ |
| 1265 | try: |
1320 | try: |
| ... | 28 lines hidden [Expand] | ||
| 1294 | server.save_draft(review_request) |
1349 | server.save_draft(review_request) |
| 1295 | except APIError, e: |
1350 | except APIError, e: |
| 1296 | rsp, = e.args |
1351 | rsp, = e.args |
| 1297 | if rsp['err']['code'] == 103: # Not logged in |
1352 | if rsp['err']['code'] == 103: # Not logged in |
| 1298 | server.login() |
1353 | server.login() |
| 1299 | tempt_fate(server, tool, changenum, diff_content, submit_as) |
1354 | tempt_fate(server, tool, changenum, diff_content, |
| 1355 | parent_diff_content, submit_as) |
||
| 1300 | return |
1356 | return |
| 1301 | 1357 | ||
| 1302 | if options.rid: |
1358 | if options.rid: |
| 1303 | die("Error getting review request %s: %s (code %s)" % \ |
1359 | die("Error getting review request %s: %s (code %s)" % \ |
| 1304 | (options.rid, rsp['err']['msg'], rsp['err']['code'])) |
1360 | (options.rid, rsp['err']['msg'], rsp['err']['code'])) |
| 1305 | else: |
1361 | else: |
| 1306 | die("Error creating review request: %s (code %s)" % \ |
1362 | die("Error creating review request: %s (code %s)" % \ |
| 1307 | (rsp['err']['msg'], rsp['err']['code'])) |
1363 | (rsp['err']['msg'], rsp['err']['code'])) |
| 1308 | 1364 | ||
| 1309 | 1365 | ||
| 1310 | if not server.info.supports_changesets or not options.change_only: |
1366 | if not server.info.supports_changesets or not options.change_only: |
| 1311 | try: |
1367 | try: |
| 1312 | server.upload_diff(review_request, diff_content) |
1368 | server.upload_diff(review_request, diff_content, |
| 1369 | parent_diff_content) |
||
| 1313 | except APIError, e: |
1370 | except APIError, e: |
| 1314 | rsp, = e.args |
1371 | rsp, = e.args |
| 1315 | print "Error uploading diff: %s (%s)" % (rsp['err']['msg'], |
1372 | print "Error uploading diff: %s (%s)" % (rsp['err']['msg'], |
| 1316 | rsp['err']['code']) |
1373 | rsp['err']['code']) |
| 1317 | debug(rsp) |
1374 | debug(rsp) |
| ... | 20 lines hidden [Expand] | ||
| 1338 | parser = OptionParser(usage="%prog [-pond] [-r review_id] [changenum]", |
1395 | parser = OptionParser(usage="%prog [-pond] [-r review_id] [changenum]", |
| 1339 | version="%prog " + VERSION) |
1396 | version="%prog " + VERSION) |
| 1340 | 1397 | ||
| 1341 | parser.add_option("-p", "--publish", |
1398 | parser.add_option("-p", "--publish", |
| 1342 | dest="publish", action="store_true", default=PUBLISH, |
1399 | dest="publish", action="store_true", default=PUBLISH, |
| 1343 | help="publish the review request immediately after " + |
1400 | help="publish the review request immediately after " |
| 1344 | "submitting") |
1401 | "submitting") |
| 1345 | parser.add_option("-r", "--review-request-id", |
1402 | parser.add_option("-r", "--review-request-id", |
| 1346 | dest="rid", metavar="ID", default=None, |
1403 | dest="rid", metavar="ID", default=None, |
| 1347 | help="existing review request ID to update") |
1404 | help="existing review request ID to update") |
| 1348 | parser.add_option("-o", "--open", |
1405 | parser.add_option("-o", "--open", |
| 1349 | dest="open_browser", action="store_true", |
1406 | dest="open_browser", action="store_true", |
| 1350 | default=OPEN_BROWSER, |
1407 | default=OPEN_BROWSER, |
| 1351 | help="open a web browser to the review request page") |
1408 | help="open a web browser to the review request page") |
| 1352 | parser.add_option("-n", "--output-diff", |
1409 | parser.add_option("-n", "--output-diff", |
| 1353 | dest="output_diff_only", action="store_true", |
1410 | dest="output_diff_only", action="store_true", |
| 1354 | default=False, |
1411 | default=False, |
| 1355 | help="outputs a diff to the console and exits. " + |
1412 | help="outputs a diff to the console and exits. " |
| 1356 | "Does not post") |
1413 | "Does not post") |
| 1357 | parser.add_option("--server", |
1414 | parser.add_option("--server", |
| 1358 | dest="server", default=REVIEWBOARD_URL, |
1415 | dest="server", default=REVIEWBOARD_URL, |
| 1359 | metavar="SERVER", |
1416 | metavar="SERVER", |
| 1360 | help="specify a different Review Board server " + |
1417 | help="specify a different Review Board server " |
| 1361 | "to use") |
1418 | "to use") |
| 1362 | parser.add_option("--diff-only", |
1419 | parser.add_option("--diff-only", |
| 1363 | dest="diff_only", action="store_true", default=False, |
1420 | dest="diff_only", action="store_true", default=False, |
| 1364 | help="uploads a new diff, but does not update " + |
1421 | help="uploads a new diff, but does not update " |
| 1365 | "info from changelist") |
1422 | "info from changelist") |
| 1366 | parser.add_option("--target-groups", |
1423 | parser.add_option("--target-groups", |
| 1367 | dest="target_groups", default=TARGET_GROUPS, |
1424 | dest="target_groups", default=TARGET_GROUPS, |
| 1368 | help="names of the groups who will perform " + |
1425 | help="names of the groups who will perform " |
| 1369 | "the review") |
1426 | "the review") |
| 1370 | parser.add_option("--target-people", |
1427 | parser.add_option("--target-people", |
| 1371 | dest="target_people", default=TARGET_PEOPLE, |
1428 | dest="target_people", default=TARGET_PEOPLE, |
| 1372 | help="names of the people who will perform " + |
1429 | help="names of the people who will perform " |
| 1373 | "the review") |
1430 | "the review") |
| 1374 | parser.add_option("--summary", |
1431 | parser.add_option("--summary", |
| 1375 | dest="summary", default=None, |
1432 | dest="summary", default=None, |
| 1376 | help="summary of the review ") |
1433 | help="summary of the review ") |
| 1377 | parser.add_option("--description", |
1434 | parser.add_option("--description", |
| 1378 | dest="description", default=None, |
1435 | dest="description", default=None, |
| 1379 | help="description of the review ") |
1436 | help="description of the review ") |
| 1380 | parser.add_option("--revision-range", |
1437 | parser.add_option("--revision-range", |
| 1381 | dest="revision_range", default=None, |
1438 | dest="revision_range", default=None, |
| 1382 | help="generate the diff for review based on given " + |
1439 | help="generate the diff for review based on given " |
| 1383 | "revision range") |
1440 | "revision range") |
| 1384 | parser.add_option("--submit-as", |
1441 | parser.add_option("--submit-as", |
| 1385 | dest="submit_as", default=SUBMIT_AS, metavar="USERNAME", |
1442 | dest="submit_as", default=SUBMIT_AS, metavar="USERNAME", |
| 1386 | help="user name to be recorded as the author of the " |
1443 | help="user name to be recorded as the author of the " |
| 1387 | "review request, instead of the logged in user") |
1444 | "review request, instead of the logged in user") |
| 1388 | 1445 | ||
| 1389 | if repository_info: |
1446 | if repository_info: |
| 1390 | if repository_info.supports_changesets: |
1447 | if repository_info.supports_changesets: |
| 1391 | parser.add_option("--change-only", |
1448 | parser.add_option("--change-only", |
| 1392 | dest="change_only", action="store_true", |
1449 | dest="change_only", action="store_true", |
| 1393 | default=False, |
1450 | default=False, |
| 1394 | help="updates info from changelist, but does " + |
1451 | help="updates info from changelist, but does " |
| 1395 | "not upload a new diff") |
1452 | "not upload a new diff") |
| 1396 | 1453 | ||
| 1454 | if repository_info.supports_parent_diffs: |
||
| 1455 | parser.add_option("--parent", |
||
| 1456 | dest="parent_branch", default=None, |
||
| 1457 | metavar="PARENT_BRANCH", |
||
| 1458 | help="the parent branch this diff should be " |
||
| 1459 | "against") |
||
| 1460 | |||
| 1397 | tool.add_options(parser) |
1461 | tool.add_options(parser) |
| 1398 | 1462 | ||
| 1399 | 1463 | ||
| 1400 | parser.add_option("-d", "--debug", |
1464 | parser.add_option("-d", "--debug", |
| 1401 | action="store_true", dest="debug", default=DEBUG, |
1465 | action="store_true", dest="debug", default=DEBUG, |
| ... | 57 lines hidden [Expand] | ||
| 1459 | else: |
1523 | else: |
| 1460 | changenum = None |
1524 | changenum = None |
| 1461 | 1525 | ||
| 1462 | if options.revision_range: |
1526 | if options.revision_range: |
| 1463 | diff = tool.diff_between_revisions(options.revision_range) |
1527 | diff = tool.diff_between_revisions(options.revision_range) |
| 1528 | parent_diff = None |
||
| 1464 | else: |
1529 | else: |
| 1465 | diff = tool.diff(args) |
1530 | diff, parent_diff = tool.diff(args) |
| 1466 | 1531 | ||
| 1467 | if options.output_diff_only: |
1532 | if options.output_diff_only: |
| 1468 | print diff |
1533 | print diff |
| 1469 | sys.exit(0) |
1534 | sys.exit(0) |
| 1470 | 1535 | ||
| 1471 | # Let's begin. |
1536 | # Let's begin. |
| 1472 | server.login() |
1537 | server.login() |
| 1473 | 1538 | ||
| 1474 | review_url = tempt_fate(server, tool, changenum, diff_content=diff, |
1539 | review_url = tempt_fate(server, tool, changenum, diff_content=diff, |
| 1540 | parent_diff_content=parent_diff, |
||
| 1475 | submit_as=options.submit_as) |
1541 | submit_as=options.submit_as) |
| 1476 | 1542 | ||
| 1477 | # Load the review up in the browser if requested to: |
1543 | # Load the review up in the browser if requested to: |
| 1478 | if options.open_browser: |
1544 | if options.open_browser: |
| 1479 | try: |
1545 | try: |
| ... | 14 lines hidden [Expand] | ||
| /trunk/reviewboard/webapi/json.py | |||
|---|---|---|---|
| Revision 1377 | New Change | ||
| ... | 1002 lines hidden [Expand] | ||
| 1003 | 1003 | ||
| 1004 | if not form.is_valid(): |
1004 | if not form.is_valid(): |
| 1005 | return WebAPIResponseFormError(request, form) |
1005 | return WebAPIResponseFormError(request, form) |
| 1006 | 1006 | ||
| 1007 | try: |
1007 | try: |
| 1008 | diffset = form.create(request.FILES['path']) |
1008 | diffset = form.create(request.FILES['path'], |
| 1009 | request.FILES.get('parent_diff_path')) |
||
| 1009 | 1010 | ||
| 1010 | # Set the initial revision to be one newer than the most recent |
1011 | # Set the initial revision to be one newer than the most recent |
| 1011 | # public revision, so we can reference it in the diff viewer. |
1012 | # public revision, so we can reference it in the diff viewer. |
| 1012 | # |
1013 | # |
| 1013 | # TODO: It would be nice to later consolidate this with the logic in |
1014 | # TODO: It would be nice to later consolidate this with the logic in |
| ... | 235 lines hidden [Expand] | ||
- /trunk/reviewboard/contrib/tools/post-review: 69 changes [ 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 ]
- /trunk/reviewboard/webapi/json.py: 2 changes [ 1 2 ]
Other reviews