Пример #1
0
class SetReviewerWhenMovedToRFR(ConditionalTask):
    """This task adding a reviewer once the title includes an '[RFR]' tag"""

    Endpoint = Github()  # The third party Endpoint for this task is Github.
    EndpointScope = PullRequest  # The scope of this task is pull request.
    NAME = 'SetReviewerWhenMovedToRFR'  # The name of the task.

    @property
    def condition(self):
        # We get the `title_tags` and `reviewers` statistics to check whether the title tag has moved
        # to RFR and that there are no reviewers that have been assigned.
        return ('RFR' in self.statistics.my_pulls_statistics.title_tags
                and not self.statistics.my_pulls_statistics.reviewers)

    def get_data(self):
        """Collecting data"""
        repos_data = next(
            repo for repo in CurrentProject().config.config.github.repositories
            if repo.name == self.statistics.my_repo_statistics.repository)
        maintainers = repos_data.maintainers
        reviewer = choice(maintainers)
        owner = self.statistics.my_pulls_statistics.owner
        reviewer_contact = User.get_user(github_login=reviewer)
        owner_contact = User.get_user(github_login=owner) or owner
        return owner_contact, reviewer_contact

    def get_artifacts(self):
        return self.statistics.my_pulls_statistics.title_tags

    def run(self):
        """Running the task"""
        owner_contact, reviewer_contact = self.get_data()
        owner_contact = (owner_contact.irc_nick if isinstance(
            owner_contact, User) else owner_contact)
        self.scopes[PullRequest].add_reviewers(reviewer_contact.github)
Пример #2
0
class GithubEventsFactory(EventsFactory):
    Endpoint = Github()
    _max_recent_check = 100  # Checking for at most <_max_recent_check> recent events and then break TODO: parameterize

    def build_events(self) -> dict:
        events = []
        event_getter_names = ('get_events', 'get_issues_events')
        for repo in self.Endpoint.repositories:
            for getter in event_getter_names:
                i = 0
                for event in getattr(repo, getter)():
                    # We assume that the most recent event are in the top of the timeline in github, so if the first we receive
                    # is already in the buffer or delivered, we assume that there are no new events.
                    hsh = GithubEventBase.hash_by_id(event.id)
                    if hsh in map(lambda e: e.hash, self._events_buffer):
                        self.logger.debug('Event "{}" already in the buffer. dismissing...'.format(hsh))
                        break
                    if hsh in self._dilivered_events_stack:
                        self.logger.debug('Event "{}" already delivered. dismissing...'.format(hsh))
                        break
                    if i >= self._max_recent_check:
                        self.logger.debug('Max recent checks exceeded for getter "{}", events collected: {}...'.format(
                            getter, len(events), hsh))
                        break
                    # TODO: Check whether the following is necessary...
                    # elif event.actor.login == CurrentProject().config.credentials.github.username:
                    #     continue
                    try:
                        data = event.raw_data
                    except UnknownObjectException:
                        break  # stale event
                    # Fill some required fields that could be missing in the timeline API but
                    data['organization'], data['repository'] = getattr(repo.owner, 'login', repo.owner.name), repo.name
                    data['sender'] = {'login': event.actor.login}
                    data['type'] = data.get('type') or data.get('event')
                    # Gathering facts
                    payload = data.get('payload') or {}
                    issue = payload.get('issue') or data.get('issue')
                    pull_request = (issue or {}).get('pull_request') or payload.get('pull_request')
                    # Classifying event:
                    if pull_request:
                        data['issue_number'] = int(pull_request['url'].split('/')[-1])
                        event_obj = PullRequestEvent(data, event.artifacts)
                    elif issue:
                        data['issue_number'] = issue['number']
                        event_obj = IssueEvent(data, event.artifacts)
                    else:
                        event_obj = RepositoryEvent(data, event.artifacts)
                    #
                    events.append(event_obj)
                    # since we have number of getters we want to collect only (1 / len(event_getter_names))
                    # from each getter so we are adding the following to `i`
                    i += 1.0 * len(event_getter_names)
        return events
Пример #3
0
class GithubScopesCollector(ScopesCollector):
    Endpoint = Github()

    def collect_all(self):
        scopes = []
        for repo in self.Endpoint.repositories:
            scopes.append(repo)
            for pull_request in repo.get_pulls():
                pull_request.repository = repo
                scopes.append(pull_request)
            for issue in repo.get_issues():
                if not issue.pull_request:
                    issue.repository = repo
                    scopes.append(issue)
        return scopes
Пример #4
0
class AlertOnMergedEvent(ConditionalTask):
    """Alert when some pull request has been merged"""

    Endpoint = Github()  # The third party Endpoint for this task is Github.
    EndpointScope = Repository  # The scope of this task is pull request.
    NAME = 'AlertOnMergedEvent'  # The name of the task.

    @property
    def condition(self):
        return (self.event and self.event.data['type'] == 'PullRequestEvent'
                and getnode(self.event.data, ['payload', 'action']) == 'closed'
                and getnode(self.event.data,
                            ['payload', 'pull_request', 'merged']))

    def get_artifacts(self):
        return [str(self.event.data['id'])]

    def run(self):
        actor = self.event.data['sender']['login']
        number = self.event.data['payload']['pull_request']['number']
        IRCendpoint().client.msg('##bot-testing',
                                 f'{actor} has merged PR#{number}')
Пример #5
0
class PromptWhenLargeNumberOfComments(ConditionalTask):
    """This task is prompting on IRC when there is a large number of comment in a pull request"""

    Endpoint = Github()  # The third party Endpoint for this task is Github.
    EndpointScope = PullRequest  # The scope of this task is pull request.
    NAME = 'PromptWhenLargeNumberOfComments'  # The name of the task.
    PR_MAX_NUMBER_OF_COMMENTS = 10

    @property
    def condition(self):
        # Checking that total number of comment is greater than 10.
        return self.statistics.my_pr_stats.total_number_of_comments > self.PR_MAX_NUMBER_OF_COMMENTS

    def get_artifacts(self):
        return [str(self.statistics.my_pr_stats.total_number_of_comments)]

    def run(self):
        """Running the task"""
        IRCendpoint().client.msg(
            '##bot-testing',
            f'PR#{self.statistics.my_pr_stats.number} has more than {self.PR_MAX_NUMBER_OF_COMMENTS} comments! '
            f'({self.statistics.my_pr_stats.total_number_of_comments} comments)'
        )
Пример #6
0
class AlertOnMentionedUser(ConditionalTask):
    """This task prompt the user in IRC once he was mentioned in some pull request."""

    Endpoint = Github()
    EndpointScope = PullRequest
    NAME = 'AlertOnMentionedUser'
    RUN_ONCE = False

    def get_artifacts(self):
        return [str(self.event.data['id'])]

    @property
    def condition(self):
        """
        Checking that the task triggered by event, the event is a comment event
        and there are mentioned users in the comment.
        """
        return bool(self.event and self.event.artifacts
                    and self.event.artifacts.get('comment')
                    and self.event.artifacts['comment'].mentioned_users)

    def run(self):
        mentioned, actor = self.event.artifacts[
            'comment'].mentioned_users, self.event.artifacts['actor']
        # Getting IRC nick in case that the actor in the users list
        user = User.get_user(github_login=actor.login)
        actor = (user.irc_nick if user else actor.login)
        for mentioned_user in mentioned:
            # Getting IRC nick in case that the user in the users list
            user = User.get_user(github_login=mentioned_user.login)
            mentioned_user = (user.irc_nick if user else mentioned_user.login)
            # Composing the comment from the statistics, mentioned users and actor
            IRCendpoint().client.msg(
                '##bot-testing', f'{mentioned_user}, {actor} has '
                f'mentioned you in {self.statistics.my_repo_statistics.organization}/'
                f'{self.statistics.my_repo_statistics.repository} '
                f'@ PR#{self.statistics.my_pulls_statistics.issue_number}.')
Пример #7
0
class GithubEventBase(Event):
    """A base class for Github event."""
    Endpoint = Github()

    def __init__(self, data: dict, artifacts: dict):
        assert isinstance(data, dict)
        self._data = data
        self._artifacts = artifacts

    @property
    def artifacts(self) -> dict:
        return self._artifacts

    @property
    def type(self):
        return self.data['type']

    @property
    def id(self):
        return self._data['id']

    @property
    def data(self):
        return self._data
Пример #8
0
class GithubBot(BotSlave):
    Endpoint = Github()
    EventsFactory = GithubEventsFactory()
    ScopeCollector = GithubScopesCollector()
Пример #9
0
class GithubStatisticsBase(Statistics):
    Endpoint = Github()