| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 and Gerrit.""" | 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" |
| 9 | 9 |
| 10 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 return RunGit(['config', param], **kwargs).strip() | 821 return RunGit(['config', param], **kwargs).strip() |
| 822 | 822 |
| 823 | 823 |
| 824 def ShortBranchName(branch): | 824 def ShortBranchName(branch): |
| 825 """Convert a name like 'refs/heads/foo' to just 'foo'.""" | 825 """Convert a name like 'refs/heads/foo' to just 'foo'.""" |
| 826 return branch.replace('refs/heads/', '', 1) | 826 return branch.replace('refs/heads/', '', 1) |
| 827 | 827 |
| 828 | 828 |
| 829 def GetCurrentBranchRef(): | 829 def GetCurrentBranchRef(): |
| 830 """Returns branch ref (e.g., refs/heads/master) or None.""" | 830 """Returns branch ref (e.g., refs/heads/master) or None.""" |
| 831 return RunGit(['symbolic-ref', 'HEAD'], | 831 ref = RunGit(['symbolic-ref', 'HEAD'], |
| 832 stderr=subprocess2.VOID, error_ok=True).strip() or None | 832 stderr=subprocess2.VOID, error_ok=True).strip() or None |
| 833 if ref and not ref.startswith('refs/heads/'): |
| 834 ref = 'refs/heads/'+ref |
| 835 return ref |
| 833 | 836 |
| 834 | 837 |
| 835 def GetCurrentBranch(): | 838 def GetCurrentBranch(): |
| 836 """Returns current branch or None. | 839 """Returns current branch or None. |
| 837 | 840 |
| 838 For refs/heads/* branches, returns just last part. For others, full ref. | 841 For refs/heads/* branches, returns just last part. For others, full ref. |
| 839 """ | 842 """ |
| 840 branchref = GetCurrentBranchRef() | 843 branchref = GetCurrentBranchRef() |
| 841 if branchref: | 844 if branchref: |
| 842 return ShortBranchName(branchref) | 845 return ShortBranchName(branchref) |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 GIT_INSTRUCTIONS_URL) | 1108 GIT_INSTRUCTIONS_URL) |
| 1106 branch = 'HEAD' | 1109 branch = 'HEAD' |
| 1107 if branch.startswith('refs/remotes'): | 1110 if branch.startswith('refs/remotes'): |
| 1108 self._remote = (remote, branch) | 1111 self._remote = (remote, branch) |
| 1109 elif branch.startswith('refs/branch-heads/'): | 1112 elif branch.startswith('refs/branch-heads/'): |
| 1110 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) | 1113 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) |
| 1111 else: | 1114 else: |
| 1112 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) | 1115 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) |
| 1113 return self._remote | 1116 return self._remote |
| 1114 | 1117 |
| 1115 def GitSanityChecks(self, upstream_git_obj): | 1118 def GitSanityChecks(self, upstream_git_obj, local_ref='HEAD'): |
| 1116 """Checks git repo status and ensures diff is from local commits.""" | 1119 """Checks git repo status and ensures diff is from local commits.""" |
| 1117 | 1120 |
| 1118 if upstream_git_obj is None: | 1121 if upstream_git_obj is None: |
| 1119 if self.GetBranch() is None: | 1122 if self.GetBranch() is None: |
| 1120 print >> sys.stderr, ( | 1123 print >> sys.stderr, ( |
| 1121 'ERROR: unable to determine current branch (detached HEAD?)') | 1124 'ERROR: unable to determine current branch (detached HEAD?)') |
| 1122 else: | 1125 else: |
| 1123 print >> sys.stderr, ( | 1126 print >> sys.stderr, ( |
| 1124 'ERROR: no upstream branch') | 1127 'ERROR: no upstream branch') |
| 1125 return False | 1128 return False |
| 1126 | 1129 |
| 1127 # Verify the commit we're diffing against is in our current branch. | 1130 # Verify the commit we're diffing against is in our current branch. |
| 1128 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() | 1131 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() |
| 1129 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip() | 1132 common_anc = RunGit(['merge-base', upstream_sha, local_ref]).strip() |
| 1130 if upstream_sha != common_ancestor: | 1133 if upstream_sha != common_anc: |
| 1131 print >> sys.stderr, ( | 1134 print >> sys.stderr, ( |
| 1132 'ERROR: %s is not in the current branch. You may need to rebase ' | 1135 'ERROR: %s is not in the current branch. You may need to rebase ' |
| 1133 'your tracking branch' % upstream_sha) | 1136 'your tracking branch' % upstream_sha) |
| 1134 return False | 1137 return False |
| 1135 | 1138 |
| 1136 # List the commits inside the diff, and verify they are all local. | 1139 # List the commits inside the diff, and verify they are all local. |
| 1137 commits_in_diff = RunGit( | 1140 commits_in_diff = RunGit( |
| 1138 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines() | 1141 ['rev-list', '^%s' % upstream_sha, local_ref]).splitlines() |
| 1139 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch']) | 1142 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch']) |
| 1140 remote_branch = remote_branch.strip() | 1143 remote_branch = remote_branch.strip() |
| 1141 if code != 0: | 1144 if code != 0: |
| 1142 _, remote_branch = self.GetRemoteBranch() | 1145 _, remote_branch = self.GetRemoteBranch() |
| 1143 | 1146 |
| 1144 commits_in_remote = RunGit( | 1147 commits_in_remote = RunGit( |
| 1145 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines() | 1148 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines() |
| 1146 | 1149 |
| 1147 common_commits = set(commits_in_diff) & set(commits_in_remote) | 1150 common_commits = set(commits_in_diff) & set(commits_in_remote) |
| 1148 if common_commits: | 1151 if common_commits: |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 if codereview_server: | 1254 if codereview_server: |
| 1252 RunGit(['config', codereview_setting, codereview_server]) | 1255 RunGit(['config', codereview_setting, codereview_server]) |
| 1253 else: | 1256 else: |
| 1254 current_issue = self.GetIssue() | 1257 current_issue = self.GetIssue() |
| 1255 if current_issue: | 1258 if current_issue: |
| 1256 RunGit(['config', '--unset', issue_setting]) | 1259 RunGit(['config', '--unset', issue_setting]) |
| 1257 self.issue = None | 1260 self.issue = None |
| 1258 self.SetPatchset(None) | 1261 self.SetPatchset(None) |
| 1259 | 1262 |
| 1260 def GetChange(self, upstream_branch, author): | 1263 def GetChange(self, upstream_branch, author): |
| 1261 if not self.GitSanityChecks(upstream_branch): | 1264 local_ref = self.GetBranchRef() |
| 1265 if not self.GitSanityChecks(upstream_branch, local_ref): |
| 1262 DieWithError('\nGit sanity check failure') | 1266 DieWithError('\nGit sanity check failure') |
| 1263 | 1267 |
| 1264 root = settings.GetRelativeRoot() | 1268 root = settings.GetRelativeRoot() |
| 1265 if not root: | 1269 if not root: |
| 1266 root = '.' | 1270 root = '.' |
| 1267 absroot = os.path.abspath(root) | 1271 absroot = os.path.abspath(root) |
| 1268 | 1272 |
| 1269 # We use the sha1 of HEAD as a name of this change. | 1273 # We use the sha1 of HEAD as a name of this change. |
| 1270 name = RunGitWithCode(['rev-parse', 'HEAD'])[1].strip() | 1274 name = RunGitWithCode(['rev-parse', local_ref])[1].strip() |
| 1271 # Need to pass a relative path for msysgit. | 1275 # Need to pass a relative path for msysgit. |
| 1272 try: | 1276 try: |
| 1273 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) | 1277 files = scm.GIT.CaptureStatus([root], '.', upstream_branch, local_ref) |
| 1274 except subprocess2.CalledProcessError: | 1278 except subprocess2.CalledProcessError: |
| 1275 DieWithError( | 1279 DieWithError( |
| 1276 ('\nFailed to diff against upstream branch %s\n\n' | 1280 ('\nFailed to diff against upstream branch %s\n\n' |
| 1277 'This branch probably doesn\'t exist anymore. To reset the\n' | 1281 'This branch probably doesn\'t exist anymore. To reset the\n' |
| 1278 'tracking branch, please run\n' | 1282 'tracking branch, please run\n' |
| 1279 ' git branch --set-upstream %s trunk\n' | 1283 ' git branch --set-upstream %s trunk\n' |
| 1280 'replacing trunk with origin/master or the relevant branch') % | 1284 'replacing trunk with origin/master or the relevant branch') % |
| 1281 (upstream_branch, self.GetBranch())) | 1285 (upstream_branch, self.GetBranch())) |
| 1282 | 1286 |
| 1283 issue = self.GetIssue() | 1287 issue = self.GetIssue() |
| 1284 patchset = self.GetPatchset() | 1288 patchset = self.GetPatchset() |
| 1285 if issue: | 1289 if issue: |
| 1286 description = self.GetDescription() | 1290 description = self.GetDescription() |
| 1287 else: | 1291 else: |
| 1288 # If the change was never uploaded, use the log messages of all commits | 1292 # If the change was never uploaded, use the log messages of all commits |
| 1289 # up to the branch point, as git cl upload will prefill the description | 1293 # up to the branch point, as git cl upload will prefill the description |
| 1290 # with these log messages. | 1294 # with these log messages. |
| 1291 args = ['log', '--pretty=format:%s%n%n%b', '%s...' % (upstream_branch)] | 1295 args = ['log', '--pretty=format:%s%n%n%b', |
| 1296 '%s...%s' % (upstream_branch, local_ref)] |
| 1292 description = RunGitWithCode(args)[1].strip() | 1297 description = RunGitWithCode(args)[1].strip() |
| 1293 | 1298 |
| 1294 if not author: | 1299 if not author: |
| 1295 author = RunGit(['config', 'user.email']).strip() or None | 1300 author = RunGit(['config', 'user.email']).strip() or None |
| 1296 return presubmit_support.GitChange( | 1301 return presubmit_support.GitChange( |
| 1297 name, | 1302 name, |
| 1298 description, | 1303 description, |
| 1299 absroot, | 1304 absroot, |
| 1300 files, | 1305 files, |
| 1301 issue, | 1306 issue, |
| 1302 patchset, | 1307 patchset, |
| 1303 author, | 1308 author, |
| 1304 upstream=upstream_branch) | 1309 upstream=upstream_branch, |
| 1310 local_ref=local_ref) |
| 1305 | 1311 |
| 1306 def UpdateDescription(self, description): | 1312 def UpdateDescription(self, description): |
| 1307 self.description = description | 1313 self.description = description |
| 1308 return self._codereview_impl.UpdateDescriptionRemote(description) | 1314 return self._codereview_impl.UpdateDescriptionRemote(description) |
| 1309 | 1315 |
| 1310 def RunHook(self, committing, may_prompt, verbose, change): | 1316 def RunHook(self, committing, may_prompt, verbose, change): |
| 1311 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" | 1317 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" |
| 1312 try: | 1318 try: |
| 1313 return presubmit_support.DoPresubmitChecks(change, committing, | 1319 return presubmit_support.DoPresubmitChecks(change, committing, |
| 1314 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, | 1320 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, |
| (...skipping 3505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4820 if __name__ == '__main__': | 4826 if __name__ == '__main__': |
| 4821 # These affect sys.stdout so do it outside of main() to simplify mocks in | 4827 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 4822 # unit testing. | 4828 # unit testing. |
| 4823 fix_encoding.fix_encoding() | 4829 fix_encoding.fix_encoding() |
| 4824 setup_color.init() | 4830 setup_color.init() |
| 4825 try: | 4831 try: |
| 4826 sys.exit(main(sys.argv[1:])) | 4832 sys.exit(main(sys.argv[1:])) |
| 4827 except KeyboardInterrupt: | 4833 except KeyboardInterrupt: |
| 4828 sys.stderr.write('interrupted\n') | 4834 sys.stderr.write('interrupted\n') |
| 4829 sys.exit(1) | 4835 sys.exit(1) |
| OLD | NEW |