Review Board

beta

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

  1. /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 ]
  2. /trunk/reviewboard/webapi/json.py: 2 changes [ 1 2 ]
/trunk/reviewboard/contrib/tools/post-review
Revision 1377 New Change
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
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
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
        """
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.
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
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)
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
    """
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:
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):
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
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
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
        """
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.
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 = ""
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
    """
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,
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:
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)
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,
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:
/trunk/reviewboard/webapi/json.py
Revision 1377 New Change
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
  1. /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 ]
  2. /trunk/reviewboard/webapi/json.py: 2 changes [ 1 2 ]