16b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# Copyright (c) 2009 Google Inc. All rights reserved.
26b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# Copyright (c) 2009 Apple Inc. All rights reserved.
36b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# Copyright (c) 2010 Research In Motion Limited. All rights reserved.
46b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#
56b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# Redistribution and use in source and binary forms, with or without
66b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# modification, are permitted provided that the following conditions are
76b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# met:
86b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#
96b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#     * Redistributions of source code must retain the above copyright
106b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# notice, this list of conditions and the following disclaimer.
116b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#     * Redistributions in binary form must reproduce the above
126b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# copyright notice, this list of conditions and the following disclaimer
136b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# in the documentation and/or other materials provided with the
146b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# distribution.
156b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#     * Neither the name of Google Inc. nor the names of its
166b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# contributors may be used to endorse or promote products derived from
176b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# this software without specific prior written permission.
186b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#
196b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
206b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
216b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
226b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
246b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
256b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
266b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
276b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
296b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
306b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
316b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerimport os
326b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
336b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerfrom webkitpy.common.system.ospath import relpath
34f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochfrom webkitpy.common.config import committers, urls
356b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
366b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerclass CommitterValidator(object):
386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def __init__(self, bugzilla):
406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._bugzilla = bugzilla
416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _checkout_root(self):
436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # FIXME: This is a hack, we would have this from scm.checkout_root
446b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # if we had any way to get to an scm object here.
456b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        components = __file__.split(os.sep)
46f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        tools_index = components.index("Tools")
476b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return os.sep.join(components[:tools_index])
486b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
496b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _committers_py_path(self):
506b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # extension can sometimes be .pyc, we always want .py
516b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        (path, extension) = os.path.splitext(committers.__file__)
526b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # FIXME: When we're allowed to use python 2.6 we can use the real
536b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # os.path.relpath
546b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        path = relpath(path, self._checkout_root())
556b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return ".".join([path, "py"])
566b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
576b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _flag_permission_rejection_message(self, setter_email, flag_name):
586b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # This could be queried from the status_server.
596b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        queue_administrator = "eseidel@chromium.org"
606b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # This could be queried from the tool.
616b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        queue_name = "commit-queue"
626b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        committers_list = self._committers_py_path()
636b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        message = "%s does not have %s permissions according to %s." % (
646b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                        setter_email,
656b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                        flag_name,
66f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                        urls.view_source_url(committers_list))
676b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        message += "\n\n- If you do not have %s rights please read %s for instructions on how to use bugzilla flags." % (
68f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                        flag_name, urls.contribution_guidelines)
696b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        message += "\n\n- If you have %s rights please correct the error in %s by adding yourself to the file (no review needed).  " % (
706b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                        flag_name, committers_list)
716b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        message += "The %s restarts itself every 2 hours.  After restart the %s will correctly respect your %s rights." % (
726b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                        queue_name, queue_name, flag_name)
736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return message
746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _validate_setter_email(self, patch, result_key, rejection_function):
766b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        committer = getattr(patch, result_key)()
776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # If the flag is set, and we don't recognize the setter, reject the
786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # flag!
796b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        setter_email = patch._attachment_dictionary.get("%s_email" % result_key)
806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if setter_email and not committer:
816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            rejection_function(patch.id(),
826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                self._flag_permission_rejection_message(setter_email,
836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                                        result_key))
846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return False
856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return True
866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _reject_patch_if_flags_are_invalid(self, patch):
886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return (self._validate_setter_email(
896b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                patch, "reviewer", self.reject_patch_from_review_queue)
906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            and self._validate_setter_email(
916b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                patch, "committer", self.reject_patch_from_commit_queue))
926b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
936b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def patches_after_rejecting_invalid_commiters_and_reviewers(self, patches):
946b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return [patch for patch in patches if self._reject_patch_if_flags_are_invalid(patch)]
956b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
966b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def reject_patch_from_commit_queue(self,
976b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                       attachment_id,
986b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                       additional_comment_text=None):
99f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        comment_text = "Rejecting attachment %s from commit-queue." % attachment_id
1006b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._bugzilla.set_flag_on_attachment(attachment_id,
1016b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              "commit-queue",
1026b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              "-",
1036b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              comment_text,
1046b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              additional_comment_text)
1056b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1066b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def reject_patch_from_review_queue(self,
1076b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                       attachment_id,
1086b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                       additional_comment_text=None):
109f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        comment_text = "Rejecting attachment %s from review queue." % attachment_id
1106b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._bugzilla.set_flag_on_attachment(attachment_id,
1116b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              'review',
1126b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              '-',
1136b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              comment_text,
1146b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                              additional_comment_text)
115