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 absroot = os.path.abspath(root or '.') |
| 518 |
| 519 # We use the sha1 of HEAD as a name of this change. |
| 520 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() |
| 521 files = scm.GIT.CaptureStatus([absroot], upstream_branch) |
| 522 |
| 523 issue = ConvertToInteger(self.GetIssue()) |
| 524 patchset = ConvertToInteger(self.GetPatchset()) |
| 525 if issue: |
| 526 description = self.GetDescription() |
| 527 else: |
| 528 # If the change was never uploaded, use the log messages of all commits |
| 529 # up to the branch point, as git cl upload will prefill the description |
| 530 # with these log messages. |
| 531 description = RunCommand(['git', 'log', '--pretty=format:%s%n%n%b', |
| 532 '%s...' % (upstream_branch)]).strip() |
| 533 change = presubmit_support.GitChange( |
| 534 name, |
| 535 description, |
| 536 absroot, |
| 537 files, |
| 538 issue, |
| 539 patchset, |
| 540 None) |
| 541 |
| 542 # Apply watchlists on upload. |
| 543 if not committing: |
| 544 watchlist = watchlists.Watchlists(change.RepositoryRoot()) |
| 545 files = [f.LocalPath() for f in change.AffectedFiles()] |
| 546 self.SetWatchers(watchlist.GetWatchersForPaths(files)) |
| 547 |
| 548 try: |
| 549 output = presubmit_support.DoPresubmitChecks(change, committing, |
| 550 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, |
| 551 default_presubmit=None, may_prompt=may_prompt, tbr=tbr, |
| 552 rietveld=self.RpcServer()) |
| 553 except presubmit_support.PresubmitFailure, e: |
| 554 DieWithError( |
| 555 ('%s\nMaybe your depot_tools is out of date?\n' |
| 556 'If all fails, contact maruel@') % e) |
| 557 |
| 558 # TODO(dpranke): We should propagate the error out instead of calling |
| 559 # exit(). |
| 560 if not output.should_continue(): |
| 561 sys.exit(1) |
| 562 |
| 563 return output |
| 564 |
514 def CloseIssue(self): | 565 def CloseIssue(self): |
515 rpc_server = self.RpcServer() | 566 rpc_server = self.RpcServer() |
516 # Newer versions of Rietveld require us to pass an XSRF token to POST, so | 567 # 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 | 568 # 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.) | 569 # modified so the token isn't required when closing an issue.) |
519 xsrf_token = rpc_server.Send('/xsrf_token', | 570 xsrf_token = rpc_server.Send('/xsrf_token', |
520 extra_headers={'X-Requesting-XSRF-Token': '1'}) | 571 extra_headers={'X-Requesting-XSRF-Token': '1'}) |
521 | 572 |
522 # You cannot close an issue with a GET. | 573 # 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. | 574 # 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 | 856 |
806 | 857 |
807 def ConvertToInteger(inputval): | 858 def ConvertToInteger(inputval): |
808 """Convert a string to integer, but returns either an int or None.""" | 859 """Convert a string to integer, but returns either an int or None.""" |
809 try: | 860 try: |
810 return int(inputval) | 861 return int(inputval) |
811 except (TypeError, ValueError): | 862 except (TypeError, ValueError): |
812 return None | 863 return None |
813 | 864 |
814 | 865 |
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): | 866 def CMDpresubmit(parser, args): |
873 """run presubmit tests on the current changelist""" | 867 """run presubmit tests on the current changelist""" |
874 parser.add_option('--upload', action='store_true', | 868 parser.add_option('--upload', action='store_true', |
875 help='Run upload hook instead of the push/dcommit hook') | 869 help='Run upload hook instead of the push/dcommit hook') |
876 (options, args) = parser.parse_args(args) | 870 (options, args) = parser.parse_args(args) |
877 | 871 |
878 # Make sure index is up-to-date before running diff-index. | 872 # Make sure index is up-to-date before running diff-index. |
879 RunGit(['update-index', '--refresh', '-q'], error_ok=True) | 873 RunGit(['update-index', '--refresh', '-q'], error_ok=True) |
880 if RunGit(['diff-index', 'HEAD']): | 874 if RunGit(['diff-index', 'HEAD']): |
881 # TODO(maruel): Is this really necessary? | 875 # TODO(maruel): Is this really necessary? |
882 print 'Cannot presubmit with a dirty tree. You must commit locally first.' | 876 print 'Cannot presubmit with a dirty tree. You must commit locally first.' |
883 return 1 | 877 return 1 |
884 | 878 |
885 cl = Changelist() | 879 cl = Changelist() |
886 if args: | 880 if args: |
887 base_branch = args[0] | 881 base_branch = args[0] |
888 else: | 882 else: |
889 # Default to diffing against the "upstream" branch. | 883 # Default to diffing against the "upstream" branch. |
890 base_branch = cl.GetUpstreamBranch() | 884 base_branch = cl.GetUpstreamBranch() |
891 | 885 |
892 RunHook(committing=not options.upload, upstream_branch=base_branch, | 886 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, |
893 rietveld_server=cl.GetRietveldServer(), tbr=False, | 887 tbr=False, may_prompt=False, verbose=options.verbose) |
894 may_prompt=False, verbose=options.verbose) | |
895 return 0 | 888 return 0 |
896 | 889 |
897 | 890 |
898 @usage('[args to "git diff"]') | 891 @usage('[args to "git diff"]') |
899 def CMDupload(parser, args): | 892 def CMDupload(parser, args): |
900 """upload the current changelist to codereview""" | 893 """upload the current changelist to codereview""" |
901 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 894 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', |
902 help='bypass upload presubmit hook') | 895 help='bypass upload presubmit hook') |
903 parser.add_option('-f', action='store_true', dest='force', | 896 parser.add_option('-f', action='store_true', dest='force', |
904 help="force yes to questions (don't prompt)") | 897 help="force yes to questions (don't prompt)") |
(...skipping 21 matching lines...) Expand all Loading... |
926 | 919 |
927 cl = Changelist() | 920 cl = Changelist() |
928 if args: | 921 if args: |
929 base_branch = args[0] | 922 base_branch = args[0] |
930 else: | 923 else: |
931 # Default to diffing against the "upstream" branch. | 924 # Default to diffing against the "upstream" branch. |
932 base_branch = cl.GetUpstreamBranch() | 925 base_branch = cl.GetUpstreamBranch() |
933 args = [base_branch + "..."] | 926 args = [base_branch + "..."] |
934 | 927 |
935 if not options.bypass_hooks and not options.force: | 928 if not options.bypass_hooks and not options.force: |
936 hook_results = RunHook(committing=False, upstream_branch=base_branch, | 929 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, |
937 rietveld_server=cl.GetRietveldServer(), tbr=False, | 930 tbr=False, may_prompt=True, |
938 may_prompt=True, verbose=options.verbose) | 931 verbose=options.verbose) |
939 if not options.reviewers and hook_results.reviewers: | 932 if not options.reviewers and hook_results.reviewers: |
940 options.reviewers = hook_results.reviewers | 933 options.reviewers = hook_results.reviewers |
941 | 934 |
942 | 935 |
943 # --no-ext-diff is broken in some versions of Git, so try to work around | 936 # --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 | 937 # this by overriding the environment (but there is still a problem if the |
945 # git config key "diff.external" is used). | 938 # git config key "diff.external" is used). |
946 env = os.environ.copy() | 939 env = os.environ.copy() |
947 if 'GIT_EXTERNAL_DIFF' in env: | 940 if 'GIT_EXTERNAL_DIFF' in env: |
948 del env['GIT_EXTERNAL_DIFF'] | 941 del env['GIT_EXTERNAL_DIFF'] |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 '--pretty=format:%H']) | 1072 '--pretty=format:%H']) |
1080 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) | 1073 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) |
1081 if extra_commits: | 1074 if extra_commits: |
1082 print ('This branch has %d additional commits not upstreamed yet.' | 1075 print ('This branch has %d additional commits not upstreamed yet.' |
1083 % len(extra_commits.splitlines())) | 1076 % len(extra_commits.splitlines())) |
1084 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' | 1077 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' |
1085 'before attempting to %s.' % (base_branch, cmd)) | 1078 'before attempting to %s.' % (base_branch, cmd)) |
1086 return 1 | 1079 return 1 |
1087 | 1080 |
1088 if not options.bypass_hooks and not options.force: | 1081 if not options.bypass_hooks and not options.force: |
1089 RunHook(committing=True, upstream_branch=base_branch, | 1082 cl.RunHook(committing=True, upstream_branch=base_branch, |
1090 rietveld_server=cl.GetRietveldServer(), tbr=options.tbr, | 1083 tbr=options.tbr, may_prompt=True, verbose=options.verbose) |
1091 may_prompt=True, verbose=options.verbose) | |
1092 | 1084 |
1093 if cmd == 'dcommit': | 1085 if cmd == 'dcommit': |
1094 # Check the tree status if the tree status URL is set. | 1086 # Check the tree status if the tree status URL is set. |
1095 status = GetTreeStatus() | 1087 status = GetTreeStatus() |
1096 if 'closed' == status: | 1088 if 'closed' == status: |
1097 print ('The tree is closed. Please wait for it to reopen. Use ' | 1089 print ('The tree is closed. Please wait for it to reopen. Use ' |
1098 '"git cl dcommit -f" to commit on a closed tree.') | 1090 '"git cl dcommit -f" to commit on a closed tree.') |
1099 return 1 | 1091 return 1 |
1100 elif 'unknown' == status: | 1092 elif 'unknown' == status: |
1101 print ('Unable to determine tree status. Please verify manually and ' | 1093 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))) | 1443 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1452 | 1444 |
1453 # Not a known command. Default to help. | 1445 # Not a known command. Default to help. |
1454 GenUsage(parser, 'help') | 1446 GenUsage(parser, 'help') |
1455 return CMDhelp(parser, argv) | 1447 return CMDhelp(parser, argv) |
1456 | 1448 |
1457 | 1449 |
1458 if __name__ == '__main__': | 1450 if __name__ == '__main__': |
1459 fix_encoding.fix_encoding() | 1451 fix_encoding.fix_encoding() |
1460 sys.exit(main(sys.argv[1:])) | 1452 sys.exit(main(sys.argv[1:])) |
OLD | NEW |