def test_state(self):
     merged = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 130)
     closed = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 129)
     opened = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 126)
     self.assertEqual(merged.state, MergeRequestStates.MERGED)
     self.assertEqual(closed.state, MergeRequestStates.CLOSED)
     self.assertEqual(opened.state, MergeRequestStates.OPEN)
 def test_merge_params(self):
     commit_msg = 'Test commit title\n\nTest commit body'
     head_sha = 'fd2e00646b19fc93e72992761c0b2ef31fe697ae'
     method = 'squash'
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 134)
     mr.merge(message=commit_msg, sha=head_sha, _github_merge_method=method)
     self.assertEqual(mr.state, MergeRequestStates.MERGED)
    def _github_open_merge_request(self, commit_msg, body, branch_name) -> GitHubMergeRequest:
        """Create a GitHub pull request with the given dependency update."""
        url = f'{IGitt.GitHub.BASE_URL}/repos/{self.slug}/pulls'
        response = requests.Session().post(
            url,
            headers={
                'Accept': 'application/vnd.github.v3+json',
                'Authorization': f'token {self.token}'
            },
            json={
                'title': commit_msg,
                'body': body,
                'head': branch_name,
                'base': 'master',
                'maintainer_can_modify': True
            }
        )
        try:
            response.raise_for_status()
        except Exception as exc:
            raise RuntimeError(f"Failed to create a pull request: {response.text}") from exc

        mr_number = response.json()['number']
        _LOGGER.info(f"Newly created pull request #{mr_number} available at {response.json()['html_url']}")
        return GitHubMergeRequest.from_data(
            response.json(), token=GitHubToken(self.token), repository=self.slug, number=mr_number
        )
Beispiel #4
0
    def raw_search(token, raw_query):
        """
        Handles a GitHub search.

        Search syntax reference at
        https://help.github.com/articles/understanding-the-search-syntax/

        :param token:        A GitHubToken object to use for authentication.
        :param raw_query:    A string with the search query following syntax.
        :yields:             Search results as GitHubIssue(...) and
                             GitHubMergeRequest(...) objects for Issues and
                             Merge Requests respectively.
        """
        base_url = '/search/issues'
        query_params = {'q': raw_query, 'per_page': '100'}
        resp = get(token, base_url, query_params)

        issue_url_re = re.compile(
            r'https://(?:.+)/(\S+)/(\S+)/(issues|pull)/(\d+)')
        for item in resp:
            user, repo, item_type, item_number = issue_url_re.match(
                item['html_url']).groups()
            if item_type == 'issues':
                yield GitHubIssue.from_data(item, token, user + '/' + repo,
                                            int(item_number))
            elif item_type == 'pull':
                yield GitHubMergeRequest.from_data(item, token,
                                                   user + '/' + repo,
                                                   int(item_number))
    def test_does_nothing_on_closed_pull_requests(self):
        self.simulate_scheduled_responder_call(
            'pr_stale_reminder.add_stale_label_to_merge_request', self.repo)

        closed_issue = GitHubMergeRequest(self.gh_token,
                                          'gitmate-test-user/test', 5)
        self.assertEqual(closed_issue.labels, set())
    def test_github_pr_sync_stale_label(self, m_search_mrs, m_mr_labels):
        m_mr_labels.return_value = set()
        m_search_mrs.return_value = {
            GitHubMergeRequest(self.gh_token, self.repo.full_name, 7)
        }
        self.simulate_scheduled_responder_call(
            'pr_stale_reminder.add_stale_label_to_merge_requests', self.repo)
        m_mr_labels.assert_called_with({'status/STALE'})

        # testing updated pull requests
        data = {
            'repository': {
                'full_name': environ['GITHUB_TEST_REPO'],
                'id': 49558751
            },
            'pull_request': {
                'number': 7
            },
            'action': 'synchronize'
        }
        m_mr_labels.return_value = {'bug', 'status/STALE'}
        response = self.simulate_github_webhook_call('pull_request', data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # only the 'bug' label remains after removing 'status/STALE'
        m_mr_labels.assert_called_with({'bug'})
 def test_head(self):
     self.assertEqual(self.mr.head.sha,
                      'f6d2b7c66372236a090a2a74df2e47f42a54456b')
     # test for forks
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 113)
     self.assertEqual(mr.head.sha,
                      'fb37d69e72b46a52f8694cf45adb007315de3b6e')
     # GitHub copies commit to the base repo
     self.assertEqual(mr.head.repository.full_name,
                      'gitmate-test-user/test')
Beispiel #8
0
    def get_mr(self, mr_number: int):
        """
        Retrieves an MR:

        :param mr_number: The merge_request ID of the MR to retrieve.
        :return: A MergeRequest object.
        :raises ElementDoesntExistError: If the MR doesn't exist.
        :raises RuntimeError: If something goes wrong (network, auth...).
        """
        from IGitt.GitHub.GitHubMergeRequest import GitHubMergeRequest
        return GitHubMergeRequest(self._token, self.full_name, mr_number)
Beispiel #9
0
    def mrs_closed_by(self):
        """
        Returns the merge requests that close this issue.
        """
        from IGitt.GitHub.GitHubMergeRequest import GitHubMergeRequest

        r = requests.get(GH_INSTANCE_URL + self._url.replace('/repos', ''))

        matches = CLOSED_BY_PATTERN.findall(r.text)

        return {GitHubMergeRequest(self._token, repo_name, int(number))
                for repo_name, number in matches}
Beispiel #10
0
    def merge_requests(self) -> set:
        """
        Retrieves a set of merge request objects.

        >>> from os import environ
        >>> repo = GitHubRepository(environ['GITHUB_TEST_TOKEN'],
        ...                         'gitmate-test-user/test')
        >>> len(repo.merge_requests)
        3
        """
        from IGitt.GitHub.GitHubMergeRequest import GitHubMergeRequest
        return {GitHubMergeRequest(self._token, self.full_name, res['number'])
                for res in get(self._token, self._url + '/pulls')}
    def test_github_pr_comment_stale_label(self, m_body, m_search_mrs,
                                           m_mr_labels):
        m_mr_labels.return_value = set()
        m_search_mrs.return_value = {
            GitHubMergeRequest(self.gh_token, self.repo.full_name, 7)
        }
        self.simulate_scheduled_responder_call(
            'pr_stale_reminder.add_stale_label_to_merge_requests', self.repo)
        m_mr_labels.assert_called_with({'status/STALE'})

        # test nothing happens on stale label added
        m_mr_labels.reset_mock()
        data = {
            'repository': {
                'full_name': environ['GITHUB_TEST_REPO'],
                'id': 49558751
            },
            'pull_request': {
                'number': 0
            },
            'action': 'labeled',
            'label': {
                'name': 'status/STALE'
            }
        }
        response = self.simulate_github_webhook_call('pull_request', data)
        m_mr_labels.assert_not_called()

        # testing updated pull requests
        data = {
            'repository': {
                'full_name': self.repo.full_name,
                'id': 49558751
            },
            'issue': {
                'number': 7,
                'pull_request': {}
            },
            'comment': {
                'id': 0
            },
            'action': 'created'
        }
        m_body.return_value = 'This is a mistake.'
        m_mr_labels.return_value = {'bug', 'status/STALE'}
        response = self.simulate_github_webhook_call('issue_comment', data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # only the 'bug' label remains after removing 'status/STALE'
        m_mr_labels.assert_called_with({'bug'})
Beispiel #12
0
    def create_merge_request(self, title:str, base:str, head:str,
                             body: Optional[str]=None,
                             target_project_id: Optional[int]=None,
                             target_project: Optional[str]= None):
        """
        Creates a merge request to that repository
        """
        data = {'title': title, 'body': body, 'base': base,
                'head': head}
        url = self._url + '/pulls'
        json = post(self._token, url, data=data)

        from IGitt.GitHub.GitHubMergeRequest import GitHubMergeRequest
        return GitHubMergeRequest(self._token,
                                  json['base']['repo']['full_name'],
                                  json['number'])
Beispiel #13
0
    def test_blocked_comment_response(self, m_body):
        @ResponderRegistrar.responder(self.plugin,
                                      MergeRequestActions.COMMENTED)
        def test_blocked_responder(mr, comment, *args, **kwargs):
            # this should never run
            return comment.body  # pragma: no cover

        mr = GitHubMergeRequest(None, 'test/1', 0)
        comment = GitHubComment(None, 'test/1', CommentType.MERGE_REQUEST, 0)
        m_body.return_value = ('Hello\n'
                               '(Powered by [GitMate.io](https://gitmate.io))')

        # ensures that the event was blocked, if it weren't it will return the
        # comment body.
        self.assertEqual([
            result.get() for result in ResponderRegistrar.respond(
                MergeRequestActions.COMMENTED, mr, comment, repo=self.repo)
        ], [])
Beispiel #14
0
    def _handle_webhook_issue_comment(self, data, repository):
        """Handles 'issue_comment' event."""
        if data['action'] != 'deleted':
            comment_obj = GitHubComment.from_data(data['comment'], self._token,
                                                  repository,
                                                  CommentType.MERGE_REQUEST,
                                                  data['comment']['id'])

            if 'pull_request' in data['issue']:
                yield (MergeRequestActions.COMMENTED, [
                    GitHubMergeRequest.from_data(data['issue'], self._token,
                                                 repository,
                                                 data['issue']['number']),
                    comment_obj
                ])
            else:
                yield IssueActions.COMMENTED, [
                    GitHubIssue.from_data(data['issue'], self._token,
                                          repository, data['issue']['number']),
                    comment_obj
                ]
Beispiel #15
0
    def _handle_webhook_pull_request(self, data, repository):
        """Handles 'pull_request' event."""
        pull_request = data['pull_request']
        pull_request_obj = GitHubMergeRequest.from_data(
            pull_request, self._token, repository, pull_request['number'])
        trigger_event = {
            'synchronize': MergeRequestActions.SYNCHRONIZED,
            'opened': MergeRequestActions.OPENED,
            'closed': MergeRequestActions.CLOSED,
            'labeled': MergeRequestActions.LABELED,
            'unlabeled': MergeRequestActions.UNLABELED,
        }.get(data['action'], MergeRequestActions.ATTRIBUTES_CHANGED)
        if (trigger_event == MergeRequestActions.CLOSED
                and pull_request['merged'] is True):
            trigger_event = MergeRequestActions.MERGED

        if (trigger_event is MergeRequestActions.LABELED
                or trigger_event is MergeRequestActions.UNLABELED):
            yield trigger_event, [pull_request_obj, data['label']['name']]
        else:
            yield trigger_event, [pull_request_obj]
 def test_mentioned_issues(self):
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 96)
     self.assertEqual({int(issue.number)
                       for issue in mr.mentioned_issues}, {114, 115, 127})
 def setUp(self):
     self.token = GitHubToken(os.environ.get('GITHUB_TEST_TOKEN', ''))
     self.mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 7)
 def test_merge_empty(self):
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 133)
     mr.merge()
     self.assertEqual(mr.state, MergeRequestStates.MERGED)
 def test_closes_issues(self):
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 113)
     self.assertEqual({int(issue.number)
                       for issue in mr.closes_issues},
                      {98, 104, 1, 107, 97, 105})
class GitHubMergeRequestTest(IGittTestCase):
    def setUp(self):
        self.token = GitHubToken(os.environ.get('GITHUB_TEST_TOKEN', ''))
        self.mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 7)

    def test_base(self):
        self.assertEqual(self.mr.base.sha,
                         '674498fd415cfadc35c5eb28b8951e800f357c6f')

    def test_head(self):
        self.assertEqual(self.mr.head.sha,
                         'f6d2b7c66372236a090a2a74df2e47f42a54456b')
        # test for forks
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 113)
        self.assertEqual(mr.head.sha,
                         'fb37d69e72b46a52f8694cf45adb007315de3b6e')
        # GitHub copies commit to the base repo
        self.assertEqual(mr.head.repository.full_name,
                         'gitmate-test-user/test')

    def test_description(self):
        self.mr.description = 'changed description'
        self.assertEqual(self.mr.description, 'changed description')

    def test_title(self):
        self.mr.title = 'changed title'
        self.assertEqual(self.mr.title, 'changed title')

    def test_base_branch_name(self):
        self.assertEqual(self.mr.base_branch_name, 'master')

    def test_head_branch_name(self):
        self.assertEqual(self.mr.head_branch_name, 'gitmate-test-user-patch-2')

    def test_commits(self):
        self.assertEqual([commit.sha for commit in self.mr.commits],
                         ['f6d2b7c66372236a090a2a74df2e47f42a54456b'])

    def test_repository(self):
        self.assertEqual(self.mr.target_repository.full_name,
                         'gitmate-test-user/test')
        self.assertEqual(self.mr.source_repository.full_name,
                         'gitmate-test-user/test')

    def test_diffstat(self):
        self.assertEqual(self.mr.diffstat, (2, 0))

    def test_time(self):
        self.assertEqual(self.mr.created,
                         datetime.datetime(2016, 1, 24, 19, 47, 19))
        self.assertEqual(self.mr.updated,
                         datetime.datetime(2017, 10, 18, 8, 34, 21))

    def test_affected_files(self):
        self.assertEqual(self.mr.affected_files, {'README.md'})

    def test_number(self):
        self.assertEqual(self.mr.number, 7)

    def test_url(self):
        self.assertEqual(
            self.mr.url,
            'https://api.github.com/repos/gitmate-test-user/test/issues/7')

    def test_web_url(self):
        self.assertEqual(self.mr.web_url,
                         'https://github.com/gitmate-test-user/test/pull/7')

    def test_change_state(self):
        self.mr.close()
        self.assertEqual(self.mr.state, MergeRequestStates.CLOSED)
        self.mr.reopen()
        self.assertEqual(self.mr.state, MergeRequestStates.OPEN)

    def test_closes_issues(self):
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 113)
        self.assertEqual({int(issue.number)
                          for issue in mr.closes_issues},
                         {98, 104, 1, 107, 97, 105})

    def test_mentioned_issues(self):
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 96)
        self.assertEqual({int(issue.number)
                          for issue in mr.mentioned_issues}, {114, 115, 127})

    def test_tests_passed(self):
        self.assertEqual(self.mr.tests_passed, True)
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 6)
        self.assertEqual(mr.tests_passed, False)

    def test_assignees(self):
        # test merge request with no assignees
        self.assertEqual(self.mr.assignees, set())

    def test_author(self):
        self.assertEqual(self.mr.author.username, 'gitmate-test-user')

    def test_state(self):
        merged = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 130)
        closed = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 129)
        opened = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 126)
        self.assertEqual(merged.state, MergeRequestStates.MERGED)
        self.assertEqual(closed.state, MergeRequestStates.CLOSED)
        self.assertEqual(opened.state, MergeRequestStates.OPEN)

    def test_merge_empty(self):
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 133)
        mr.merge()
        self.assertEqual(mr.state, MergeRequestStates.MERGED)

    def test_merge_params(self):
        commit_msg = 'Test commit title\n\nTest commit body'
        head_sha = 'fd2e00646b19fc93e72992761c0b2ef31fe697ae'
        method = 'squash'
        mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 134)
        mr.merge(message=commit_msg, sha=head_sha, _github_merge_method=method)
        self.assertEqual(mr.state, MergeRequestStates.MERGED)
 def test_tests_passed(self):
     self.assertEqual(self.mr.tests_passed, True)
     mr = GitHubMergeRequest(self.token, 'gitmate-test-user/test', 6)
     self.assertEqual(mr.tests_passed, False)