Skip to content
Permalink
Browse files
2010-10-18 Adam Barth <abarth@webkit.org>
        Reviewed by Eric Seidel.

        Implement webkit-patch suggest-reviewers
        https://bugs.webkit.org/show_bug.cgi?id=47866

        * Scripts/webkitpy/common/checkout/api.py:
            - The main logic.  We look at the last five changes to each
              modified (non-ChangeLog) file and collect up the reviewers of
              those changes as well as the authors of those changes who are
              reviewers.
        * Scripts/webkitpy/common/checkout/api_unittest.py:
            - Test the logic with some fun mocks.
        * Scripts/webkitpy/common/checkout/scm.py:
            - Fix a bug when you have local git commits.
        * Scripts/webkitpy/common/checkout/scm_unittest.py:
            - Test that the bug is fixed.
        * Scripts/webkitpy/tool/commands/queries.py:
            - Add the query.

Canonical link: https://commits.webkit.org/60585@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@70020 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Adam Barth committed Oct 19, 2010
1 parent 1180654 commit 49d7c8d4ceca5222c44e80d905a606a3dc72bd21
Showing 6 changed files with 84 additions and 4 deletions.
@@ -1,3 +1,24 @@
2010-10-18 Adam Barth <abarth@webkit.org>

Reviewed by Eric Seidel.

Implement webkit-patch suggest-reviewers
https://bugs.webkit.org/show_bug.cgi?id=47866

* Scripts/webkitpy/common/checkout/api.py:
- The main logic. We look at the last five changes to each
modified (non-ChangeLog) file and collect up the reviewers of
those changes as well as the authors of those changes who are
reviewers.
* Scripts/webkitpy/common/checkout/api_unittest.py:
- Test the logic with some fun mocks.
* Scripts/webkitpy/common/checkout/scm.py:
- Fix a bug when you have local git commits.
* Scripts/webkitpy/common/checkout/scm_unittest.py:
- Test that the bug is fixed.
* Scripts/webkitpy/tool/commands/queries.py:
- Add the query.

2010-10-18 Kenneth Russell <kbr@google.com>

Reviewed by Eric Seidel.
@@ -83,13 +83,19 @@ def commit_info_for_revision(self, revision):
def bug_id_for_revision(self, revision):
return self.commit_info_for_revision(revision).bug_id()

def modified_changelogs(self, git_commit):
def _modified_files_matching_predicate(self, git_commit, predicate):
# SCM returns paths relative to scm.checkout_root
# Callers (especially those using the ChangeLog class) may
# expect absolute paths, so this method returns absolute paths.
changed_files = self._scm.changed_files(git_commit)
absolute_paths = [os.path.join(self._scm.checkout_root, path) for path in changed_files]
return [path for path in absolute_paths if self._is_path_to_changelog(path)]
return [path for path in absolute_paths if predicate(path)]

def modified_changelogs(self, git_commit):
return self._modified_files_matching_predicate(git_commit, self._is_path_to_changelog)

def modified_non_changelogs(self, git_commit):
return self._modified_files_matching_predicate(git_commit, lambda path: not self._is_path_to_changelog(path))

def commit_message_for_this_commit(self, git_commit):
changelog_paths = self.modified_changelogs(git_commit)
@@ -109,6 +115,14 @@ def commit_message_for_this_commit(self, git_commit):
# FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
return CommitMessage("".join(changelog_messages).splitlines())

def suggested_reviewers(self, git_commit):
changed_files = self.modified_non_changelogs(git_commit)
revisions = set(sum(map(self._scm.revisions_changing_file, changed_files), []))
commit_infos = set(map(self.commit_info_for_revision, revisions))
reviewers = [commit_info.reviewer() for commit_info in commit_infos if commit_info.reviewer()]
reviewers.extend([commit_info.author() for commit_info in commit_infos if commit_info.author() and commit_info.author().can_review])
return sorted(set(reviewers))

def bug_id_for_this_commit(self, git_commit):
try:
return parse_bug_id(self.commit_message_for_this_commit(git_commit).message())
@@ -173,3 +173,24 @@ def test_modified_changelogs(self):
checkout = Checkout(scm)
expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"]
self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs)

def test_suggested_reviewers(self):
def mock_changelog_entries_for_revision(revision):
if revision % 2 == 0:
return [ChangeLogEntry(_changelog1entry1)]
return [ChangeLogEntry(_changelog1entry2)]

def mock_revisions_changing_file(path, limit=5):
if path.endswith("ChangeLog"):
return [3]
return [4, 8]

scm = Mock()
scm.checkout_root = "/foo/bar"
scm.changed_files = lambda git_commit: ["file1", "file2", "relative/path/ChangeLog"]
scm.revisions_changing_file = mock_revisions_changing_file
checkout = Checkout(scm)
checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision
reviewers = checkout.suggested_reviewers(git_commit=None)
reviewer_names = [reviewer.full_name for reviewer in reviewers]
self.assertEqual(reviewer_names, [u'Tor Arne Vestb\xf8'])
@@ -668,7 +668,7 @@ def changed_files_for_revision(self, revision):

def revisions_changing_file(self, path, limit=5):
commit_ids = self.run(["git", "log", "--pretty=format:%H", "-%s" % limit, path]).splitlines()
return map(self.svn_revision_from_git_commit, commit_ids)
return filter(lambda revision: revision, map(self.svn_revision_from_git_commit, commit_ids))

def conflicted_files(self):
# We do not need to pass decode_output for this diff command
@@ -706,7 +706,10 @@ def git_commit_from_svn_revision(cls, revision):
return git_commit

def svn_revision_from_git_commit(self, commit_id):
return int(self.run(['git', 'svn', 'find-rev', commit_id]).rstrip())
try:
return int(self.run(['git', 'svn', 'find-rev', commit_id]).rstrip())
except ValueError, e:
return None

def contents_at_revision(self, path, revision):
"""Returns a byte array (str()) containing the contents
@@ -971,6 +971,10 @@ def _three_local_commits(self):
self.scm.commit_locally_with_message("another test commit")
self._two_local_commits()

def test_revisions_changing_files_with_local_commit(self):
self._one_local_commit()
self.assertEquals(self.scm.revisions_changing_file('test_file_commit1'), [])

def test_commit_with_message(self):
self._one_local_commit_plus_working_copy_changes()
scm = detect_scm_system(self.git_checkout_path)
@@ -30,6 +30,8 @@

from optparse import make_option

import webkitpy.tool.steps as steps

from webkitpy.common.checkout.commitinfo import CommitInfo
from webkitpy.common.config.committers import CommitterList
from webkitpy.common.net.buildbot import BuildBot
@@ -41,6 +43,21 @@
from webkitpy.layout_tests import port


class SuggestReviewers(AbstractDeclarativeCommand):
name = "suggest-reviewers"
help_text = "Suggest reviewers for a patch based on recent changes to the modified files."

def __init__(self):
options = [
steps.Options.git_commit,
]
AbstractDeclarativeCommand.__init__(self, options=options)

def execute(self, options, args, tool):
reviewers = tool.checkout().suggested_reviewers(options.git_commit)
print "\n".join([reviewer.full_name for reviewer in reviewers])


class BugsToCommit(AbstractDeclarativeCommand):
name = "bugs-to-commit"
help_text = "List bugs in the commit-queue"

0 comments on commit 49d7c8d

Please sign in to comment.