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 __future__ import print_function | 10 from __future__ import print_function |
(...skipping 1375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1386 return presubmit_support.GitChange( | 1386 return presubmit_support.GitChange( |
1387 name, | 1387 name, |
1388 description, | 1388 description, |
1389 absroot, | 1389 absroot, |
1390 files, | 1390 files, |
1391 issue, | 1391 issue, |
1392 patchset, | 1392 patchset, |
1393 author, | 1393 author, |
1394 upstream=upstream_branch) | 1394 upstream=upstream_branch) |
1395 | 1395 |
1396 def UpdateDescription(self, description): | 1396 def UpdateDescription(self, description, force=False): |
1397 self.description = description | 1397 self.description = description |
1398 return self._codereview_impl.UpdateDescriptionRemote(description) | 1398 return self._codereview_impl.UpdateDescriptionRemote( |
| 1399 description, force=force) |
1399 | 1400 |
1400 def RunHook(self, committing, may_prompt, verbose, change): | 1401 def RunHook(self, committing, may_prompt, verbose, change): |
1401 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" | 1402 """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" |
1402 try: | 1403 try: |
1403 return presubmit_support.DoPresubmitChecks(change, committing, | 1404 return presubmit_support.DoPresubmitChecks(change, committing, |
1404 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, | 1405 verbose=verbose, output_stream=sys.stdout, input_stream=sys.stdin, |
1405 default_presubmit=None, may_prompt=may_prompt, | 1406 default_presubmit=None, may_prompt=may_prompt, |
1406 rietveld_obj=self._codereview_impl.GetRieveldObjForPresubmit(), | 1407 rietveld_obj=self._codereview_impl.GetRieveldObjForPresubmit(), |
1407 gerrit_obj=self._codereview_impl.GetGerritObjForPresubmit()) | 1408 gerrit_obj=self._codereview_impl.GetGerritObjForPresubmit()) |
1408 except presubmit_support.PresubmitFailure as e: | 1409 except presubmit_support.PresubmitFailure as e: |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1596 | 1597 |
1597 def GetRieveldObjForPresubmit(self): | 1598 def GetRieveldObjForPresubmit(self): |
1598 # This is an unfortunate Rietveld-embeddedness in presubmit. | 1599 # This is an unfortunate Rietveld-embeddedness in presubmit. |
1599 # For non-Rietveld codereviews, this probably should return a dummy object. | 1600 # For non-Rietveld codereviews, this probably should return a dummy object. |
1600 raise NotImplementedError() | 1601 raise NotImplementedError() |
1601 | 1602 |
1602 def GetGerritObjForPresubmit(self): | 1603 def GetGerritObjForPresubmit(self): |
1603 # None is valid return value, otherwise presubmit_support.GerritAccessor. | 1604 # None is valid return value, otherwise presubmit_support.GerritAccessor. |
1604 return None | 1605 return None |
1605 | 1606 |
1606 def UpdateDescriptionRemote(self, description): | 1607 def UpdateDescriptionRemote(self, description, force=False): |
1607 """Update the description on codereview site.""" | 1608 """Update the description on codereview site.""" |
1608 raise NotImplementedError() | 1609 raise NotImplementedError() |
1609 | 1610 |
1610 def CloseIssue(self): | 1611 def CloseIssue(self): |
1611 """Closes the issue.""" | 1612 """Closes the issue.""" |
1612 raise NotImplementedError() | 1613 raise NotImplementedError() |
1613 | 1614 |
1614 def GetApprovingReviewers(self): | 1615 def GetApprovingReviewers(self): |
1615 """Returns a list of reviewers approving the change. | 1616 """Returns a list of reviewers approving the change. |
1616 | 1617 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1791 break | 1792 break |
1792 | 1793 |
1793 if not messages: | 1794 if not messages: |
1794 # No message was sent. | 1795 # No message was sent. |
1795 return 'unsent' | 1796 return 'unsent' |
1796 if messages[-1]['sender'] != props.get('owner_email'): | 1797 if messages[-1]['sender'] != props.get('owner_email'): |
1797 # Non-LGTM reply from non-owner and not CQ bot. | 1798 # Non-LGTM reply from non-owner and not CQ bot. |
1798 return 'reply' | 1799 return 'reply' |
1799 return 'waiting' | 1800 return 'waiting' |
1800 | 1801 |
1801 def UpdateDescriptionRemote(self, description): | 1802 def UpdateDescriptionRemote(self, description, force=False): |
1802 return self.RpcServer().update_description( | 1803 return self.RpcServer().update_description( |
1803 self.GetIssue(), self.description) | 1804 self.GetIssue(), self.description) |
1804 | 1805 |
1805 def CloseIssue(self): | 1806 def CloseIssue(self): |
1806 return self.RpcServer().close_issue(self.GetIssue()) | 1807 return self.RpcServer().close_issue(self.GetIssue()) |
1807 | 1808 |
1808 def SetFlag(self, flag, value): | 1809 def SetFlag(self, flag, value): |
1809 return self.SetFlags({flag: value}) | 1810 return self.SetFlags({flag: value}) |
1810 | 1811 |
1811 def SetFlags(self, flags): | 1812 def SetFlags(self, flags): |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2287 def GetMostRecentPatchset(self): | 2288 def GetMostRecentPatchset(self): |
2288 data = self._GetChangeDetail(['CURRENT_REVISION']) | 2289 data = self._GetChangeDetail(['CURRENT_REVISION']) |
2289 return data['revisions'][data['current_revision']]['_number'] | 2290 return data['revisions'][data['current_revision']]['_number'] |
2290 | 2291 |
2291 def FetchDescription(self): | 2292 def FetchDescription(self): |
2292 data = self._GetChangeDetail(['CURRENT_REVISION']) | 2293 data = self._GetChangeDetail(['CURRENT_REVISION']) |
2293 current_rev = data['current_revision'] | 2294 current_rev = data['current_revision'] |
2294 url = data['revisions'][current_rev]['fetch']['http']['url'] | 2295 url = data['revisions'][current_rev]['fetch']['http']['url'] |
2295 return gerrit_util.GetChangeDescriptionFromGitiles(url, current_rev) | 2296 return gerrit_util.GetChangeDescriptionFromGitiles(url, current_rev) |
2296 | 2297 |
2297 def UpdateDescriptionRemote(self, description): | 2298 def UpdateDescriptionRemote(self, description, force=False): |
| 2299 if gerrit_util.HasPendingChangeEdit(self._GetGerritHost(), self.GetIssue()): |
| 2300 if not force: |
| 2301 ask_for_data( |
| 2302 'The description cannot be modified while the issue has a pending ' |
| 2303 'unpublished edit. Either publish the edit in the Gerrit web UI ' |
| 2304 'or delete it.\n\n' |
| 2305 'Press Enter to delete the unpublished edit, Ctrl+C to abort.') |
| 2306 |
| 2307 gerrit_util.DeletePendingChangeEdit(self._GetGerritHost(), |
| 2308 self.GetIssue()) |
2298 gerrit_util.SetCommitMessage(self._GetGerritHost(), self.GetIssue(), | 2309 gerrit_util.SetCommitMessage(self._GetGerritHost(), self.GetIssue(), |
2299 description) | 2310 description) |
2300 | 2311 |
2301 def CloseIssue(self): | 2312 def CloseIssue(self): |
2302 gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='') | 2313 gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='') |
2303 | 2314 |
2304 def GetApprovingReviewers(self): | 2315 def GetApprovingReviewers(self): |
2305 """Returns a list of reviewers approving the change. | 2316 """Returns a list of reviewers approving the change. |
2306 | 2317 |
2307 Note: not necessarily committers. | 2318 Note: not necessarily committers. |
(...skipping 1292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3600 | 3611 |
3601 | 3612 |
3602 @subcommand.usage('[codereview url or issue id]') | 3613 @subcommand.usage('[codereview url or issue id]') |
3603 def CMDdescription(parser, args): | 3614 def CMDdescription(parser, args): |
3604 """Brings up the editor for the current CL's description.""" | 3615 """Brings up the editor for the current CL's description.""" |
3605 parser.add_option('-d', '--display', action='store_true', | 3616 parser.add_option('-d', '--display', action='store_true', |
3606 help='Display the description instead of opening an editor') | 3617 help='Display the description instead of opening an editor') |
3607 parser.add_option('-n', '--new-description', | 3618 parser.add_option('-n', '--new-description', |
3608 help='New description to set for this issue (- for stdin, ' | 3619 help='New description to set for this issue (- for stdin, ' |
3609 '+ to load from local commit HEAD)') | 3620 '+ to load from local commit HEAD)') |
| 3621 parser.add_option('-f', '--force', action='store_true', |
| 3622 help='Delete any unpublished Gerrit edits for this issue ' |
| 3623 'without prompting') |
3610 | 3624 |
3611 _add_codereview_select_options(parser) | 3625 _add_codereview_select_options(parser) |
3612 auth.add_auth_options(parser) | 3626 auth.add_auth_options(parser) |
3613 options, args = parser.parse_args(args) | 3627 options, args = parser.parse_args(args) |
3614 _process_codereview_select_options(parser, options) | 3628 _process_codereview_select_options(parser, options) |
3615 | 3629 |
3616 target_issue = None | 3630 target_issue = None |
3617 if len(args) > 0: | 3631 if len(args) > 0: |
3618 target_issue = ParseIssueNumberArgument(args[0]) | 3632 target_issue = ParseIssueNumberArgument(args[0]) |
3619 if not target_issue.valid: | 3633 if not target_issue.valid: |
(...skipping 28 matching lines...) Expand all Loading... |
3648 elif text == '+': | 3662 elif text == '+': |
3649 base_branch = cl.GetCommonAncestorWithUpstream() | 3663 base_branch = cl.GetCommonAncestorWithUpstream() |
3650 change = cl.GetChange(base_branch, None, local_description=True) | 3664 change = cl.GetChange(base_branch, None, local_description=True) |
3651 text = change.FullDescriptionText() | 3665 text = change.FullDescriptionText() |
3652 | 3666 |
3653 description.set_description(text) | 3667 description.set_description(text) |
3654 else: | 3668 else: |
3655 description.prompt() | 3669 description.prompt() |
3656 | 3670 |
3657 if cl.GetDescription() != description.description: | 3671 if cl.GetDescription() != description.description: |
3658 cl.UpdateDescription(description.description) | 3672 cl.UpdateDescription(description.description, force=options.force) |
3659 return 0 | 3673 return 0 |
3660 | 3674 |
3661 | 3675 |
3662 def CreateDescriptionFromLog(args): | 3676 def CreateDescriptionFromLog(args): |
3663 """Pulls out the commit log to use as a base for the CL description.""" | 3677 """Pulls out the commit log to use as a base for the CL description.""" |
3664 log_args = [] | 3678 log_args = [] |
3665 if len(args) == 1 and not args[0].endswith('.'): | 3679 if len(args) == 1 and not args[0].endswith('.'): |
3666 log_args = [args[0] + '..'] | 3680 log_args = [args[0] + '..'] |
3667 elif len(args) == 1 and args[0].endswith('...'): | 3681 elif len(args) == 1 and args[0].endswith('...'): |
3668 log_args = [args[0][:-1]] | 3682 log_args = [args[0][:-1]] |
(...skipping 1591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5260 if __name__ == '__main__': | 5274 if __name__ == '__main__': |
5261 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5275 # These affect sys.stdout so do it outside of main() to simplify mocks in |
5262 # unit testing. | 5276 # unit testing. |
5263 fix_encoding.fix_encoding() | 5277 fix_encoding.fix_encoding() |
5264 setup_color.init() | 5278 setup_color.init() |
5265 try: | 5279 try: |
5266 sys.exit(main(sys.argv[1:])) | 5280 sys.exit(main(sys.argv[1:])) |
5267 except KeyboardInterrupt: | 5281 except KeyboardInterrupt: |
5268 sys.stderr.write('interrupted\n') | 5282 sys.stderr.write('interrupted\n') |
5269 sys.exit(1) | 5283 sys.exit(1) |
OLD | NEW |