예제 #1
0
def hooklistener():
    """Listen for the "issues" webhook event.

    By default, we return a 403 HTTP response.
    """
    # webcompat/webcompat-tests/issues
    if not is_github_hook(request):
        return make_response('Nothing to see here', 401)
    payload = json.loads(request.data)
    event_type = request.headers.get('X-GitHub-Event')
    # Treating events related to issues
    if event_type == 'issues':
        webhook_issue = WebHookIssue.from_dict(payload)
        # we process the action
        return webhook_issue.process_issue_action()
    elif event_type == 'ping':
        return make_response('pong', 200)
    # If nothing worked as expected, the default response is 403.
    return make_response('Not an interesting hook', 403)
예제 #2
0
    def process_issue_action(self):
        """Route the actions and provide different responses.

        There are two possible known scopes:
        * public repo
        * private repo

        Currently the actions we are handling are (for now):
        * opened (public repo only)
        Aka newly issues created and
        need to be assigned labels and milestones
        * milestoned
        When the issue is moved to needscontact
        When the issue is being moderated with a milestone: accepted
        """
        source_repo = self.repository_url
        scope = repo_scope(source_repo)
        # We do not process further in case
        # we don't know what we are dealing with
        if scope == 'unknown':
            return make_response('Wrong repository', 403)
        if self.action == 'opened' and scope == 'public':
            # we are setting labels on each new open issues
            try:
                self.tag_as_public()
            except HTTPError as e:
                msg_log(f'public:opened labels failed ({e})', self.number)
                return oops()
            else:
                return make_response('gracias, amigo.', 200)
        elif (self.action == 'milestoned' and scope == 'public' and
              self.milestoned_with == 'needscontact'):
            # add a comment with a link to outreach template generator
            # when issue is moved to needscontact
            try:
                self.comment_outreach_generator_uri()
            except HTTPError as e:
                msg_log(f'comment failed ({e})', self.number)
                return oops()
            else:
                return make_response('outreach generator url added', 200)
        elif self.action == 'opened' and scope == 'private':
            # webcompat-bot needs to comment public URL of the issue
            # and we try to classify the issue using bugbug
            try:
                self.comment_public_uri()
            except HTTPError as e:
                msg_log(f'comment failed ({e})', self.number)
                return oops()

            try:
                self.classify()
            except (HTTPError, ConnectionError) as e:
                msg_log(f'classification failed ({e})', self.number)
                return oops()

            return make_response('public url added and issue classified', 200)
        elif (self.action == 'milestoned' and scope == 'private' and
              self.milestoned_with == 'accepted'):
            # private issue have been moderated and we will make it public
            try:
                self.moderate_private_issue()
            except HTTPError as e:
                msg_log('private:moving to public failed', self.number)
                return oops()
            else:
                # we didn't get exceptions, so it's safe to close it
                self.close_private_issue()
                return make_response('Moderated issue accepted', 200)
        elif (self.action == 'milestoned' and scope == 'private' and
              self.milestoned_with == 'accepted: incomplete'):
            # The private issue has been set to the "accepted: incomplete"
            # milestone. This will close the public and private issues, and
            # leave a message for the incomplete issue.
            try:
                self.close_public_issue(reason='incomplete')
            except HTTPError as e:
                msg_log(
                    'private:closing public issue as incomplete failed',
                    self.number)
                return oops()
            else:
                # we didn't get exceptions, so it's safe to comment why
                # it was closed as incomplete, and close it.
                self.comment_closed_reason(reason='incomplete')
                self.close_private_issue()
                return make_response('Moderated issue closed as incomplete',
                                     200)
        elif (self.action == 'milestoned' and scope == 'private' and
              self.milestoned_with == 'accepted: invalid'):
            # The private issue has been set to the "accepted: invalid"
            # milestone. This will close the public and private issues, and
            # leave a message for the invalid issue.
            try:
                self.close_public_issue(reason='invalid')
            except HTTPError as e:
                msg_log(
                    'private:closing public issue as invalid failed',
                    self.number)
                return oops()
            else:
                # we didn't get exceptions, so it's safe to comment why
                # it was closed as invalid, and close it.
                self.comment_closed_reason(reason='invalid')
                self.close_private_issue()
                return make_response('Moderated issue closed as invalid', 200)
        elif (self.action == 'milestoned' and scope == 'private' and
              self.milestoned_with == 'ml-autoclosed'):
            # The private issue has been automatically moved to ml-autoclosed
            # milestone. This will close the public and private issues, and
            # will replace the content of the public issue with placeholder.
            try:
                self.close_public_issue(reason='autoclosed')
            except HTTPError as e:
                msg_log(
                    'private:closing public issue as invalid by ml-bot failed',
                    self.number)
                return oops()
            else:
                # we didn't get exceptions, so it's safe to
                # close the private issue.
                self.close_private_issue()
                return make_response('Issue closed as invalid by ml bot', 200)
        elif (scope == 'private' and self.action == 'closed' and
              self.milestone == 'unmoderated'):
            # The private issue has been closed. It is rejected and the
            # private and public issues will be closed with a rejected message.
            try:
                self.close_public_issue(reason='rejected')
            except HTTPError as e:
                msg_log('public rejection failed', self.number)
                return oops()
            else:
                # we didn't get exceptions, so it's safe to close it
                self.close_private_issue()
                return make_response('Moderated issue rejected', 200)
        else:
            return make_response('Not an interesting hook', 403)