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.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
9 | 9 |
10 import json | 10 import json |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 dirty = RunGit(['diff-index', '--name-status', 'HEAD']) | 156 dirty = RunGit(['diff-index', '--name-status', 'HEAD']) |
157 if dirty: | 157 if dirty: |
158 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd | 158 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd |
159 print 'Uncommitted files: (git diff-index --name-status HEAD)' | 159 print 'Uncommitted files: (git diff-index --name-status HEAD)' |
160 print dirty[:4096] | 160 print dirty[:4096] |
161 if len(dirty) > 4096: | 161 if len(dirty) > 4096: |
162 print '... (run "git diff-index --name-status HEAD" to see full output).' | 162 print '... (run "git diff-index --name-status HEAD" to see full output).' |
163 return True | 163 return True |
164 return False | 164 return False |
165 | 165 |
166 | |
167 def git_cl_sanity_checks(upstream_git_obj): | |
168 """Checks git repo status and ensures diff is from local commits.""" | |
169 | |
170 # Verify the commit we're diffing against is in our current branch. | |
171 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() | |
172 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip() | |
173 if upstream_sha != common_ancestor: | |
174 print >> sys.stderr, ( | |
175 'ERROR: %s is not in the current branch. You may need to rebase your ' | |
176 'tracking branch' % upstream_sha) | |
177 return False | |
178 | |
179 # List the commits inside the diff, and verify they are all local. | |
180 commits_in_diff = RunGit( | |
181 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines() | |
182 commits_in_origin = RunGit( | |
183 ['rev-list', '^%s' % upstream_sha, 'remotes/origin/master']).splitlines() | |
M-A Ruel
2012/10/28 22:29:52
I don't understand why remotes/origin/master is ha
| |
184 | |
185 common_commits = set(commits_in_diff) & set(commits_in_origin) | |
186 if common_commits: | |
187 print >> sys.stderr, ( | |
188 'ERROR: Your diff contains %d commits already in origin/master.\n' | |
189 'Run "git log --oneline origin/master..HEAD" to get a list of commits ' | |
190 'in the diff' % len(common_commits)) | |
191 return False | |
192 return True | |
193 | |
194 | |
166 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 195 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
167 """Return the corresponding git ref if |base_url| together with |glob_spec| | 196 """Return the corresponding git ref if |base_url| together with |glob_spec| |
168 matches the full |url|. | 197 matches the full |url|. |
169 | 198 |
170 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | 199 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
171 """ | 200 """ |
172 fetch_suburl, as_ref = glob_spec.split(':') | 201 fetch_suburl, as_ref = glob_spec.split(':') |
173 if allow_wildcards: | 202 if allow_wildcards: |
174 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) | 203 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) |
175 if glob_match: | 204 if glob_match: |
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 if issue: | 629 if issue: |
601 RunGit(['config', self._IssueSetting(), str(issue)]) | 630 RunGit(['config', self._IssueSetting(), str(issue)]) |
602 if self.rietveld_server: | 631 if self.rietveld_server: |
603 RunGit(['config', self._RietveldServer(), self.rietveld_server]) | 632 RunGit(['config', self._RietveldServer(), self.rietveld_server]) |
604 else: | 633 else: |
605 RunGit(['config', '--unset', self._IssueSetting()]) | 634 RunGit(['config', '--unset', self._IssueSetting()]) |
606 self.SetPatchset(0) | 635 self.SetPatchset(0) |
607 self.has_issue = False | 636 self.has_issue = False |
608 | 637 |
609 def GetChange(self, upstream_branch, author): | 638 def GetChange(self, upstream_branch, author): |
639 if not git_cl_sanity_checks(upstream_branch): | |
640 DieWithError('\nGit sanity check failure') | |
641 | |
610 root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() or '.' | 642 root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() or '.' |
611 absroot = os.path.abspath(root) | 643 absroot = os.path.abspath(root) |
612 | 644 |
613 # We use the sha1 of HEAD as a name of this change. | 645 # We use the sha1 of HEAD as a name of this change. |
614 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() | 646 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() |
615 # Need to pass a relative path for msysgit. | 647 # Need to pass a relative path for msysgit. |
616 try: | 648 try: |
617 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) | 649 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) |
618 except subprocess2.CalledProcessError: | 650 except subprocess2.CalledProcessError: |
619 DieWithError( | 651 DieWithError( |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1011 (options, args) = parser.parse_args(args) | 1043 (options, args) = parser.parse_args(args) |
1012 | 1044 |
1013 if not options.force and is_dirty_git_tree('presubmit'): | 1045 if not options.force and is_dirty_git_tree('presubmit'): |
1014 print 'use --force to check even if tree is dirty.' | 1046 print 'use --force to check even if tree is dirty.' |
1015 return 1 | 1047 return 1 |
1016 | 1048 |
1017 cl = Changelist() | 1049 cl = Changelist() |
1018 if args: | 1050 if args: |
1019 base_branch = args[0] | 1051 base_branch = args[0] |
1020 else: | 1052 else: |
1021 # Default to diffing against the "upstream" branch. | 1053 # Default to diffing against the common ancestor of the upstream branch. |
1022 base_branch = cl.GetUpstreamBranch() | 1054 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() |
1023 | 1055 |
1024 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, | 1056 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, |
1025 may_prompt=False, verbose=options.verbose, | 1057 may_prompt=False, verbose=options.verbose, |
1026 author=None) | 1058 author=None) |
1027 return 0 | 1059 return 0 |
1028 | 1060 |
1029 | 1061 |
1030 def AddChangeIdToCommitMessage(options, args): | 1062 def AddChangeIdToCommitMessage(options, args): |
1031 """Re-commits using the current message, assumes the commit hook is in | 1063 """Re-commits using the current message, assumes the commit hook is in |
1032 place. | 1064 place. |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 'See http://goo.gl/JGg0Z for details.\n') | 1241 'See http://goo.gl/JGg0Z for details.\n') |
1210 | 1242 |
1211 if is_dirty_git_tree('upload'): | 1243 if is_dirty_git_tree('upload'): |
1212 return 1 | 1244 return 1 |
1213 | 1245 |
1214 cl = Changelist() | 1246 cl = Changelist() |
1215 if args: | 1247 if args: |
1216 # TODO(ukai): is it ok for gerrit case? | 1248 # TODO(ukai): is it ok for gerrit case? |
1217 base_branch = args[0] | 1249 base_branch = args[0] |
1218 else: | 1250 else: |
1219 # Default to diffing against the "upstream" branch. | 1251 # Default to diffing against common ancestor of upstream branch |
1220 base_branch = cl.GetUpstreamBranch() | 1252 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() |
1221 args = [base_branch + "..."] | 1253 args = [base_branch] |
1222 | 1254 |
1223 if not options.bypass_hooks: | 1255 if not options.bypass_hooks: |
1224 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, | 1256 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, |
1225 may_prompt=not options.force, | 1257 may_prompt=not options.force, |
1226 verbose=options.verbose, | 1258 verbose=options.verbose, |
1227 author=None) | 1259 author=None) |
1228 if not hook_results.should_continue(): | 1260 if not hook_results.should_continue(): |
1229 return 1 | 1261 return 1 |
1230 if not options.reviewers and hook_results.reviewers: | 1262 if not options.reviewers and hook_results.reviewers: |
1231 options.reviewers = hook_results.reviewers | 1263 options.reviewers = hook_results.reviewers |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1649 cl = Changelist() | 1681 cl = Changelist() |
1650 if not cl.GetIssue(): | 1682 if not cl.GetIssue(): |
1651 parser.error('Need to upload first') | 1683 parser.error('Need to upload first') |
1652 | 1684 |
1653 if not options.name: | 1685 if not options.name: |
1654 options.name = cl.GetBranch() | 1686 options.name = cl.GetBranch() |
1655 | 1687 |
1656 # Process --bot and --testfilter. | 1688 # Process --bot and --testfilter. |
1657 if not options.bot: | 1689 if not options.bot: |
1658 # Get try slaves from PRESUBMIT.py files if not specified. | 1690 # Get try slaves from PRESUBMIT.py files if not specified. |
1659 change = cl.GetChange(cl.GetUpstreamBranch(), None) | 1691 change = cl.GetChange( |
1692 RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip(), | |
1693 None) | |
1660 options.bot = presubmit_support.DoGetTrySlaves( | 1694 options.bot = presubmit_support.DoGetTrySlaves( |
1661 change, | 1695 change, |
1662 change.LocalPaths(), | 1696 change.LocalPaths(), |
1663 settings.GetRoot(), | 1697 settings.GetRoot(), |
1664 None, | 1698 None, |
1665 None, | 1699 None, |
1666 options.verbose, | 1700 options.verbose, |
1667 sys.stdout) | 1701 sys.stdout) |
1668 if not options.bot: | 1702 if not options.bot: |
1669 parser.error('No default try builder to try, use --bot') | 1703 parser.error('No default try builder to try, use --bot') |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1809 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1843 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1810 | 1844 |
1811 # Not a known command. Default to help. | 1845 # Not a known command. Default to help. |
1812 GenUsage(parser, 'help') | 1846 GenUsage(parser, 'help') |
1813 return CMDhelp(parser, argv) | 1847 return CMDhelp(parser, argv) |
1814 | 1848 |
1815 | 1849 |
1816 if __name__ == '__main__': | 1850 if __name__ == '__main__': |
1817 fix_encoding.fix_encoding() | 1851 fix_encoding.fix_encoding() |
1818 sys.exit(main(sys.argv[1:])) | 1852 sys.exit(main(sys.argv[1:])) |
OLD | NEW |