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 )
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')
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)
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}
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'})
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'])
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) ], [])
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 ]
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)