blob: 23f9b31e5527b8bf302e1aca81200286d1fe6035 [file] [log] [blame]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from infra_api_clients.codereview import gerrit
from services import git
class GerritActions(object):
"""Houses functions for interacting with Gerrit for auto-actions in findit_v2.
"""
def __init__(self, project_api):
self.project_api = project_api
def ChangeInfoAndClientFromCommit(self, commit):
"""Gets a commit's code review information and a configured client."""
repo_url = git.GetRepoUrlFromCommit(commit)
change_info = git.GetCodeReviewInfoForACommit(commit.gitiles_id, repo_url,
commit.gitiles_ref)
assert change_info, 'Missing CL info for %s' % commit.key.id()
return change_info, gerrit.Gerrit(change_info['review_server_host'])
def NotifyCulprit(self, culprit, message, silent_notification=True):
"""Post comment on culprit's CL about Findit's findings.
This is intended for Findit to notify the culprit's author/reviewers that
change was identified by Findit as causing certain CI failures.
Args:
culprit (findit_v2.model.gitiles_commit.Culprit), the culprit to notify.
message(str): A message explaining the findings, and providing an example
of a failed build caused by the change. This will be posted in the CL
as a comment.
silent_notification(bool): If true, make the comment posting not send
email to the reviewers. For example, when the culprit is already being
reverted by a human, such as the sheriff or the author.
Returns:
sent: A boolean indicating whether the notification was sent successfully.
"""
change_info, gerrit_client = self.ChangeInfoAndClientFromCommit(culprit)
return gerrit_client.PostMessage(
change_info['review_change_id'],
message,
should_email=not silent_notification)
def CreateRevert(self, culprit, reason):
"""Create a revert of a culprit.
If a commit is identified as the root cause of a CI failure, Findit may
choose to create a revert if the project is so configured. This revert may
then be landed automatically by Findit or manually by Sheriffs or other
group in charge of the CI waterfall, again depending on how the project is
configured.
Args:
culrpit (findit_v2.model.gitiles_commit.Culprit) The culprit to revert.
reason(str): A message explaining the reason for the revert, this will
be included in the commit description of the revert.
Returns:
revert_info:
A dictionary as returned by Gerrit. E.g.:
{
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
"change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
"subject": "Revert \"Implementing Feature X\"",
"status": "NEW",
"created": "2013-02-01 09:59:32.126000000",
"updated": "2013-02-21 11:16:36.775000000",
"mergeable": true,
"insertions": 6,
"deletions": 4,
"_number": 3965,
"owner": {
"name": "John Doe"
}
}
"""
change_info, gerrit_client = self.ChangeInfoAndClientFromCommit(culprit)
revert_info = gerrit_client.CreateRevert(
reason, change_info['review_change_id'], full_change_info=True)
revert_info['client'] = gerrit_client
return revert_info
def RequestReview(self, revert_info, message):
"""Add appropriate reviewers to revert for manual submission.
In case the project is not configured to automatically land reverts, or the
configured limit of auto-submitted reverts has been reached, this method may
be called to add the appropriate reviewers and post a message requesting
that they manually land the revert if they agree with Findit's findings.
Args:
revert_info (dict): A dictionary identifying the revert to be reviewed
as generated by CreateRevert()
message(str): A message explaining that Findit will not commit the revert
automatically, instructions about how to land it and where to report a
false positive. This will be added to the CL as a comment.
"""
client = revert_info['client']
return bool(
client.AddReviewers(
revert_info['review_change_id'],
self.project_api.GetAutoRevertReviewers(),
message=message))
def CommitRevert(self, revert_info, request_confirmation_message):
"""Attempt to submit a revert created by Findit.
Once a revert has been created, Findit may land it if the project is
configured to allow it. It will also add the Sheriffs on rotation as
reviewers of the revert and post a message with the justification for
landing the revert, as well as informing the reviewers on how to report a
false positive.
Args:
revert_info (dict): A dictionary identifying the revert to be committed
as generated by CreateRevert()
request_confirmation_message(str): A message explaining that Findit
committed the change automatically and where to report a false
positive. This will be added to the CL as a comment.
Returns:
A boolean indicating whether the revert was landed successfully.
"""
client = revert_info['client']
submitted = client.SubmitRevert(revert_info['review_change_id'])
if submitted:
return self.RequestReview(revert_info, request_confirmation_message)
return False