Made _discard_pending() always post a message. Added meaningful
default messages to all the places where it is called in the code. In
particular, CQ will now always post a message whenever the Commit
checkbox is unchecked, for any reason.
Updated unit tests accordingly, and made them a bit more robust by
adding an error message to the failing FakeVerifier.
This does NOT fix the bug, but will hopefully give more visibility to
developers when a CL is dropped.
BUG=238283
Review URL: https://codereview.chromium.org/138173005
git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/commit-queue@247488 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/pending_manager.py b/pending_manager.py
index b8b176b..c392a91 100644
--- a/pending_manager.py
+++ b/pending_manager.py
@@ -197,13 +197,8 @@
# are str due to json support.
if pending.issue not in new_issues:
logging.info('Flushing issue %d' % pending.issue)
- self.context.status.send(
- pending,
- { 'verification': 'abort',
- 'payload': {
- 'output': 'CQ bit was unchecked on CL. Ignoring.' }})
pending.get_state = lambda: base.IGNORED
- self._discard_pending(pending, None)
+ self._discard_pending(pending, 'CQ bit was unchecked on CL. Ignoring.')
# Find new issues.
for issue_id in new_issues:
@@ -271,7 +266,10 @@
pending.issue, missing, pending.get_state()))
self._verify_pending(pending)
except base.DiscardPending as e:
- self._discard_pending(e.pending, e.status)
+ message = e.status
+ if not message:
+ message = 'process_new_pending_commit: ' + self.FAILED_NO_MESSAGE
+ self._discard_pending(e.pending, message)
def update_status(self):
"""Updates the status for each pending commit verifier."""
@@ -283,7 +281,10 @@
except base.DiscardPending as e:
# It's not efficient since it takes a full loop for each pending
# commit to discard.
- self._discard_pending(e.pending, e.status)
+ message = e.status
+ if not message:
+ message = 'update_status: ' + self.FAILED_NO_MESSAGE
+ self._discard_pending(e.pending, message)
for pending in self.queue.iterate():
why_not = pending.why_not()
@@ -299,8 +300,10 @@
for pending in self.queue.iterate():
state = pending.get_state()
if state == base.FAILED:
- self._discard_pending(
- pending, pending.error_message() or self.FAILED_NO_MESSAGE)
+ message = pending.error_message()
+ if not message:
+ message = 'scan_results(FAILED): ' + self.FAILED_NO_MESSAGE
+ self._discard_pending(pending, message)
elif state == base.SUCCEEDED:
if self._throttle(pending):
continue
@@ -316,9 +319,13 @@
self._commit_patch(pending)
except base.DiscardPending as e:
- self._discard_pending(e.pending, e.status)
+ message = e.status
+ if not message:
+ message = 'scan_results(discard): ' + self.FAILED_NO_MESSAGE
+ self._discard_pending(e.pending, message)
except Exception as e:
- self._discard_pending(pending, self.INTERNAL_EXCEPTION)
+ message = 'scan_result(Exception): ' + self.INTERNAL_EXCEPTION
+ self._discard_pending(pending, message)
raise
else:
# When state is IGNORED, we need to keep this issue so it's not fetched
@@ -423,6 +430,7 @@
def _discard_pending(self, pending, message):
"""Discards a pending commit. Attach an optional message to the review."""
logging.debug('_discard_pending(%s, %s)', pending.issue, message)
+ msg = message or self.FAILED_NO_MESSAGE
try:
try:
if pending.get_state() != base.IGNORED:
@@ -431,24 +439,23 @@
except urllib2.HTTPError as e:
logging.error(
'Failed to set the flag to False for %s with message %s' % (
- pending.pending_name(), message))
+ pending.pending_name(), msg))
traceback.print_stack()
logging.error(str(e))
errors.send_stack(e)
- if message:
- try:
- self.context.rietveld.add_comment(pending.issue, message)
- except urllib2.HTTPError as e:
- logging.error(
- 'Failed to add comment for %s with message %s' % (
- pending.pending_name(), message))
- traceback.print_stack()
- errors.send_stack(e)
- self.context.status.send(
- pending,
- { 'verification': 'abort',
- 'payload': {
- 'output': message }})
+ try:
+ self.context.rietveld.add_comment(pending.issue, msg)
+ except urllib2.HTTPError as e:
+ logging.error(
+ 'Failed to add comment for %s with message %s' % (
+ pending.pending_name(), msg))
+ traceback.print_stack()
+ errors.send_stack(e)
+ self.context.status.send(
+ pending,
+ { 'verification': 'abort',
+ 'payload': {
+ 'output': msg }})
finally:
# Most importantly, remove the PendingCommit from the queue.
self.queue.remove(pending.issue)
@@ -527,7 +534,10 @@
out += '\n%s' % stdout
raise base.DiscardPending(pending, out)
except base.DiscardPending as e:
- self._discard_pending(e.pending, e.status)
+ message = e.status
+ if not message:
+ message = '_commit_patch: ' + self.FAILED_NO_MESSAGE
+ self._discard_pending(e.pending, message)
def _throttle(self, pending):
"""Returns True if a commit should be delayed."""
diff --git a/tests/pending_manager_test.py b/tests/pending_manager_test.py
index 0407eae..12f73d4 100755
--- a/tests/pending_manager_test.py
+++ b/tests/pending_manager_test.py
@@ -114,7 +114,7 @@
self.context.rietveld.check_calls(
[ _try_comment(),
"set_flag(%d, 1, 'commit', False)" % issue,
- "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)])
+ "add_comment(%d, %r)" % (issue, fake.failed_message())])
else:
if success:
self.context.checkout.check_calls(
@@ -131,11 +131,11 @@
self.context.rietveld.check_calls(
[ _try_comment(),
"set_flag(%d, 1, 'commit', False)" % issue,
- "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)])
+ "add_comment(%d, %r)" % (issue, fake.failed_message())])
else:
self.context.rietveld.check_calls(
[ "set_flag(%d, 1, 'commit', False)" % issue,
- "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)])
+ "add_comment(%d, %r)" % (issue, fake.failed_message())])
def _prepare_apply_commit(self, index, issue, server_hooks_missing=False):
"""Returns a frequent sequence of action happening on the Checkout object.
@@ -265,7 +265,7 @@
])
self.context.rietveld.check_calls(
[ _try_comment(),
- "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE),
+ "add_comment(%d, %r)" % (issue, fake.failed_message()),
])
self.context.status.check_names(['initial', 'abort'])
@@ -571,7 +571,7 @@
self.context.checkout.check_calls(
self._prepare_apply_commit(0, issue, server_hooks_missing=True))
- def testDisapeared(self):
+ def testDisappeared(self):
issue = 31337
verifiers = [
project_base.ProjectBaseUrlVerifier(
@@ -591,6 +591,8 @@
pc.scan_results()
self.assertEqual(0, len(pc.queue.iterate()))
self.context.status.check_names(['abort'])
+ self.context.rietveld.check_calls(
+ ["add_comment(%d, 'CQ bit was unchecked on CL. Ignoring.')" % issue])
def _get_pc_reviewer(self):
verifiers = [
diff --git a/verification/fake.py b/verification/fake.py
index c38009e..9b95854 100644
--- a/verification/fake.py
+++ b/verification/fake.py
@@ -6,6 +6,8 @@
from verification import base
+def failed_message():
+ return 'FakeVerifier FAILED'
class FakeVerifier(base.Verifier):
name = 'fake'
@@ -15,7 +17,11 @@
self.state = state
def verify(self, pending):
- pending.verifications[self.name] = base.SimpleStatus(self.state)
+ fake = base.SimpleStatus(self.state)
+ # Make sure to leave a message, so CQ tests can reliably test for it.
+ if self.state == base.FAILED:
+ fake.error_message = failed_message()
+ pending.verifications[self.name] = fake
def update_status(self, queue):
pass
@@ -39,3 +45,6 @@
for _, fake in self.loop(queue, base.SimpleStatus, True):
fake.state = self.state
+ # Make sure to leave a message, so CQ tests can reliably test for it.
+ if self.state == base.FAILED:
+ fake.error_message = failed_message()