Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 7 | 7 |
| 8 """A git-command for integrating reviews on Rietveld.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
| 9 | 9 |
| 10 import errno | 10 import errno |
| (...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 """Set this branch's issue. If issue=0, clears the issue.""" | 504 """Set this branch's issue. If issue=0, clears the issue.""" |
| 505 if issue: | 505 if issue: |
| 506 RunGit(['config', self._IssueSetting(), str(issue)]) | 506 RunGit(['config', self._IssueSetting(), str(issue)]) |
| 507 if self.rietveld_server: | 507 if self.rietveld_server: |
| 508 RunGit(['config', self._RietveldServer(), self.rietveld_server]) | 508 RunGit(['config', self._RietveldServer(), self.rietveld_server]) |
| 509 else: | 509 else: |
| 510 RunGit(['config', '--unset', self._IssueSetting()]) | 510 RunGit(['config', '--unset', self._IssueSetting()]) |
| 511 self.SetPatchset(0) | 511 self.SetPatchset(0) |
| 512 self.has_issue = False | 512 self.has_issue = False |
| 513 | 513 |
| 514 def RunHook(self, committing, upstream_branch, tbr, may_prompt, verbose): | |
| 515 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" | |
| 516 root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() | |
| 517 if not root: | |
|
M-A Ruel
2011/04/18 14:43:11
While at it;
root = os.path.abspath(root or '.')
| |
| 518 root = '.' | |
| 519 absroot = os.path.abspath(root) | |
| 520 if not root: | |
| 521 raise Exception('Could not get root directory.') | |
| 522 | |
| 523 # We use the sha1 of HEAD as a name of this change. | |
| 524 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() | |
| 525 files = scm.GIT.CaptureStatus([root], upstream_branch) | |
| 526 | |
| 527 issue = ConvertToInteger(self.GetIssue()) | |
| 528 patchset = ConvertToInteger(self.GetPatchset()) | |
| 529 if issue: | |
| 530 description = self.GetDescription() | |
| 531 else: | |
| 532 # If the change was never uploaded, use the log messages of all commits | |
| 533 # up to the branch point, as git cl upload will prefill the description | |
| 534 # with these log messages. | |
| 535 description = RunCommand(['git', 'log', '--pretty=format:%s%n%n%b', | |
| 536 '%s...' % (upstream_branch)]).strip() | |
| 537 change = presubmit_support.GitChange( | |
| 538 name, | |
| 539 description, | |
| 540 absroot, | |
| 541 files, | |
| 542 issue, | |
| 543 patchset, | |
| 544 None) | |
| 545 | |
| 546 # Apply watchlists on upload. | |
| 547 if not committing: | |
| 548 watchlist = watchlists.Watchlists(change.RepositoryRoot()) | |
| 549 files = [f.LocalPath() for f in change.AffectedFiles()] | |
| 550 self.SetWatchers(watchlist.GetWatchersForPaths(files)) | |
| 551 | |
| 552 try: | |
| 553 output = presubmit_support.DoPresubmitChecks(change, committing, | |
| 554 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, | |
| 555 default_presubmit=None, may_prompt=may_prompt, tbr=tbr, | |
| 556 rietveld=self.RpcServer()) | |
| 557 except presubmit_support.PresubmitFailure, e: | |
| 558 DieWithError( | |
| 559 ('%s\nMaybe your depot_tools is out of date?\n' | |
| 560 'If all fails, contact maruel@') % e) | |
| 561 | |
| 562 # TODO(dpranke): We should propagate the error out instead of calling | |
| 563 # exit(). | |
| 564 if not output.should_continue(): | |
| 565 sys.exit(1) | |
| 566 | |
| 567 return output | |
| 568 | |
| 514 def CloseIssue(self): | 569 def CloseIssue(self): |
| 515 rpc_server = self.RpcServer() | 570 rpc_server = self.RpcServer() |
| 516 # Newer versions of Rietveld require us to pass an XSRF token to POST, so | 571 # Newer versions of Rietveld require us to pass an XSRF token to POST, so |
| 517 # we fetch it from the server. (The version used by Chromium has been | 572 # we fetch it from the server. (The version used by Chromium has been |
| 518 # modified so the token isn't required when closing an issue.) | 573 # modified so the token isn't required when closing an issue.) |
| 519 xsrf_token = rpc_server.Send('/xsrf_token', | 574 xsrf_token = rpc_server.Send('/xsrf_token', |
| 520 extra_headers={'X-Requesting-XSRF-Token': '1'}) | 575 extra_headers={'X-Requesting-XSRF-Token': '1'}) |
| 521 | 576 |
| 522 # You cannot close an issue with a GET. | 577 # You cannot close an issue with a GET. |
| 523 # We pass an empty string for the data so it is a POST rather than a GET. | 578 # We pass an empty string for the data so it is a POST rather than a GET. |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 805 | 860 |
| 806 | 861 |
| 807 def ConvertToInteger(inputval): | 862 def ConvertToInteger(inputval): |
| 808 """Convert a string to integer, but returns either an int or None.""" | 863 """Convert a string to integer, but returns either an int or None.""" |
| 809 try: | 864 try: |
| 810 return int(inputval) | 865 return int(inputval) |
| 811 except (TypeError, ValueError): | 866 except (TypeError, ValueError): |
| 812 return None | 867 return None |
| 813 | 868 |
| 814 | 869 |
| 815 def RunHook(committing, upstream_branch, rietveld_server, tbr, may_prompt, | |
| 816 verbose): | |
| 817 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" | |
| 818 root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() | |
| 819 if not root: | |
| 820 root = '.' | |
| 821 absroot = os.path.abspath(root) | |
| 822 if not root: | |
| 823 raise Exception('Could not get root directory.') | |
| 824 | |
| 825 # We use the sha1 of HEAD as a name of this change. | |
| 826 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() | |
| 827 files = scm.GIT.CaptureStatus([root], upstream_branch) | |
| 828 | |
| 829 cl = Changelist() | |
| 830 issue = ConvertToInteger(cl.GetIssue()) | |
| 831 patchset = ConvertToInteger(cl.GetPatchset()) | |
| 832 if issue: | |
| 833 description = cl.GetDescription() | |
| 834 else: | |
| 835 # If the change was never uploaded, use the log messages of all commits | |
| 836 # up to the branch point, as git cl upload will prefill the description | |
| 837 # with these log messages. | |
| 838 description = RunCommand(['git', 'log', '--pretty=format:%s%n%n%b', | |
| 839 '%s...' % (upstream_branch)]).strip() | |
| 840 change = presubmit_support.GitChange( | |
| 841 name, | |
| 842 description, | |
| 843 absroot, | |
| 844 files, | |
| 845 issue, | |
| 846 patchset, | |
| 847 None) | |
| 848 | |
| 849 # Apply watchlists on upload. | |
| 850 if not committing: | |
| 851 watchlist = watchlists.Watchlists(change.RepositoryRoot()) | |
| 852 files = [f.LocalPath() for f in change.AffectedFiles()] | |
| 853 cl.SetWatchers(watchlist.GetWatchersForPaths(files)) | |
| 854 | |
| 855 try: | |
| 856 output = presubmit_support.DoPresubmitChecks(change, committing, | |
| 857 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, | |
| 858 default_presubmit=None, may_prompt=may_prompt, tbr=tbr, | |
| 859 rietveld=cl.RpcServer()) | |
| 860 except presubmit_support.PresubmitFailure, e: | |
| 861 DieWithError( | |
| 862 ('%s\nMaybe your depot_tools is out of date?\n' | |
| 863 'If all fails, contact maruel@') % e) | |
| 864 | |
| 865 # TODO(dpranke): We should propagate the error out instead of calling exit(). | |
| 866 if not output.should_continue(): | |
| 867 sys.exit(1) | |
| 868 | |
| 869 return output | |
| 870 | |
| 871 | |
| 872 def CMDpresubmit(parser, args): | 870 def CMDpresubmit(parser, args): |
| 873 """run presubmit tests on the current changelist""" | 871 """run presubmit tests on the current changelist""" |
| 874 parser.add_option('--upload', action='store_true', | 872 parser.add_option('--upload', action='store_true', |
| 875 help='Run upload hook instead of the push/dcommit hook') | 873 help='Run upload hook instead of the push/dcommit hook') |
| 876 (options, args) = parser.parse_args(args) | 874 (options, args) = parser.parse_args(args) |
| 877 | 875 |
| 878 # Make sure index is up-to-date before running diff-index. | 876 # Make sure index is up-to-date before running diff-index. |
| 879 RunGit(['update-index', '--refresh', '-q'], error_ok=True) | 877 RunGit(['update-index', '--refresh', '-q'], error_ok=True) |
| 880 if RunGit(['diff-index', 'HEAD']): | 878 if RunGit(['diff-index', 'HEAD']): |
| 881 # TODO(maruel): Is this really necessary? | 879 # TODO(maruel): Is this really necessary? |
| 882 print 'Cannot presubmit with a dirty tree. You must commit locally first.' | 880 print 'Cannot presubmit with a dirty tree. You must commit locally first.' |
| 883 return 1 | 881 return 1 |
| 884 | 882 |
| 885 cl = Changelist() | 883 cl = Changelist() |
| 886 if args: | 884 if args: |
| 887 base_branch = args[0] | 885 base_branch = args[0] |
| 888 else: | 886 else: |
| 889 # Default to diffing against the "upstream" branch. | 887 # Default to diffing against the "upstream" branch. |
| 890 base_branch = cl.GetUpstreamBranch() | 888 base_branch = cl.GetUpstreamBranch() |
| 891 | 889 |
| 892 RunHook(committing=not options.upload, upstream_branch=base_branch, | 890 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, |
| 893 rietveld_server=cl.GetRietveldServer(), tbr=False, | 891 tbr=False, may_prompt=False, verbose=options.verbose) |
| 894 may_prompt=False, verbose=options.verbose) | |
| 895 return 0 | 892 return 0 |
| 896 | 893 |
| 897 | 894 |
| 898 @usage('[args to "git diff"]') | 895 @usage('[args to "git diff"]') |
| 899 def CMDupload(parser, args): | 896 def CMDupload(parser, args): |
| 900 """upload the current changelist to codereview""" | 897 """upload the current changelist to codereview""" |
| 901 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 898 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', |
| 902 help='bypass upload presubmit hook') | 899 help='bypass upload presubmit hook') |
| 903 parser.add_option('-f', action='store_true', dest='force', | 900 parser.add_option('-f', action='store_true', dest='force', |
| 904 help="force yes to questions (don't prompt)") | 901 help="force yes to questions (don't prompt)") |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 926 | 923 |
| 927 cl = Changelist() | 924 cl = Changelist() |
| 928 if args: | 925 if args: |
| 929 base_branch = args[0] | 926 base_branch = args[0] |
| 930 else: | 927 else: |
| 931 # Default to diffing against the "upstream" branch. | 928 # Default to diffing against the "upstream" branch. |
| 932 base_branch = cl.GetUpstreamBranch() | 929 base_branch = cl.GetUpstreamBranch() |
| 933 args = [base_branch + "..."] | 930 args = [base_branch + "..."] |
| 934 | 931 |
| 935 if not options.bypass_hooks and not options.force: | 932 if not options.bypass_hooks and not options.force: |
| 936 hook_results = RunHook(committing=False, upstream_branch=base_branch, | 933 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, |
| 937 rietveld_server=cl.GetRietveldServer(), tbr=False, | 934 tbr=False, may_prompt=True, |
| 938 may_prompt=True, verbose=options.verbose) | 935 verbose=options.verbose) |
| 939 if not options.reviewers and hook_results.reviewers: | 936 if not options.reviewers and hook_results.reviewers: |
| 940 options.reviewers = hook_results.reviewers | 937 options.reviewers = hook_results.reviewers |
| 941 | 938 |
| 942 | 939 |
| 943 # --no-ext-diff is broken in some versions of Git, so try to work around | 940 # --no-ext-diff is broken in some versions of Git, so try to work around |
| 944 # this by overriding the environment (but there is still a problem if the | 941 # this by overriding the environment (but there is still a problem if the |
| 945 # git config key "diff.external" is used). | 942 # git config key "diff.external" is used). |
| 946 env = os.environ.copy() | 943 env = os.environ.copy() |
| 947 if 'GIT_EXTERNAL_DIFF' in env: | 944 if 'GIT_EXTERNAL_DIFF' in env: |
| 948 del env['GIT_EXTERNAL_DIFF'] | 945 del env['GIT_EXTERNAL_DIFF'] |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1079 '--pretty=format:%H']) | 1076 '--pretty=format:%H']) |
| 1080 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) | 1077 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) |
| 1081 if extra_commits: | 1078 if extra_commits: |
| 1082 print ('This branch has %d additional commits not upstreamed yet.' | 1079 print ('This branch has %d additional commits not upstreamed yet.' |
| 1083 % len(extra_commits.splitlines())) | 1080 % len(extra_commits.splitlines())) |
| 1084 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' | 1081 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' |
| 1085 'before attempting to %s.' % (base_branch, cmd)) | 1082 'before attempting to %s.' % (base_branch, cmd)) |
| 1086 return 1 | 1083 return 1 |
| 1087 | 1084 |
| 1088 if not options.bypass_hooks and not options.force: | 1085 if not options.bypass_hooks and not options.force: |
| 1089 RunHook(committing=True, upstream_branch=base_branch, | 1086 cl.RunHook(committing=True, upstream_branch=base_branch, |
| 1090 rietveld_server=cl.GetRietveldServer(), tbr=options.tbr, | 1087 tbr=options.tbr, may_prompt=True, verbose=options.verbose) |
| 1091 may_prompt=True, verbose=options.verbose) | |
| 1092 | 1088 |
| 1093 if cmd == 'dcommit': | 1089 if cmd == 'dcommit': |
| 1094 # Check the tree status if the tree status URL is set. | 1090 # Check the tree status if the tree status URL is set. |
| 1095 status = GetTreeStatus() | 1091 status = GetTreeStatus() |
| 1096 if 'closed' == status: | 1092 if 'closed' == status: |
| 1097 print ('The tree is closed. Please wait for it to reopen. Use ' | 1093 print ('The tree is closed. Please wait for it to reopen. Use ' |
| 1098 '"git cl dcommit -f" to commit on a closed tree.') | 1094 '"git cl dcommit -f" to commit on a closed tree.') |
| 1099 return 1 | 1095 return 1 |
| 1100 elif 'unknown' == status: | 1096 elif 'unknown' == status: |
| 1101 print ('Unable to determine tree status. Please verify manually and ' | 1097 print ('Unable to determine tree status. Please verify manually and ' |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1451 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1447 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1452 | 1448 |
| 1453 # Not a known command. Default to help. | 1449 # Not a known command. Default to help. |
| 1454 GenUsage(parser, 'help') | 1450 GenUsage(parser, 'help') |
| 1455 return CMDhelp(parser, argv) | 1451 return CMDhelp(parser, argv) |
| 1456 | 1452 |
| 1457 | 1453 |
| 1458 if __name__ == '__main__': | 1454 if __name__ == '__main__': |
| 1459 fix_encoding.fix_encoding() | 1455 fix_encoding.fix_encoding() |
| 1460 sys.exit(main(sys.argv[1:])) | 1456 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |