class TestGithubReleaseNotesGenerator(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.current_tag = 'prod/1.4' self.last_tag = 'prod/1.3' self.github_info = { 'github_owner': 'TestOwner', 'github_repo': 'TestRepo', 'github_username': '******', 'github_password': '******', } self.gh = get_github_api('TestUser', 'TestPass') self.mock_util = MockUtil('TestOwner', 'TestRepo') @responses.activate def test_init_without_last_tag(self): github_info = self.github_info.copy() self.mock_util.mock_get_repo() generator = GithubReleaseNotesGenerator( self.gh, github_info, PARSER_CONFIG, self.current_tag, ) self.assertEqual(generator.github_info, github_info) self.assertEqual(generator.current_tag, self.current_tag) self.assertEqual(generator.last_tag, None) self.assertEqual(generator.change_notes.current_tag, self.current_tag) self.assertEqual(generator.change_notes._last_tag, None) @responses.activate def test_init_with_last_tag(self): github_info = self.github_info.copy() self.mock_util.mock_get_repo() generator = GithubReleaseNotesGenerator( self.gh, github_info, PARSER_CONFIG, self.current_tag, self.last_tag, ) self.assertEqual(generator.github_info, github_info) self.assertEqual(generator.current_tag, self.current_tag) self.assertEqual(generator.last_tag, self.last_tag) self.assertEqual(generator.change_notes.current_tag, self.current_tag) self.assertEqual(generator.change_notes._last_tag, self.last_tag)
class TestCommentingGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api("TestUser", "TestPass") self.mock_util = MockUtil("TestOwner", "TestRepo") self.title = "Issues" self.issue_number_without_comments = 1 self.issue_number_with_beta_comment = 2 self.issue_number_without_beta_comment = 3 self.issue_number_with_prod_comment = 4 self.issue_number_without_prod_comment = 5 self.pr_number = 6 self.pr_url = "http://example.com/pulls/{}".format(self.pr_number) self.tag_prod = "release/1.2" self.tag_beta = "beta/1.2-Beta_3" self.tag_not_prod_or_beta = "foo" self.version_number_prod = "1.1" self.version_number_beta = "1.2 (Beta 3)" def _create_generator(self, tag): generator = GithubReleaseNotesGenerator(self.gh, self.github_info.copy(), PARSER_CONFIG, tag, publish=True) return generator @responses.activate def test_render_issue_without_comments(self): issue_number = self.issue_number_without_comments tag = self.tag_not_prod_or_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) responses.add(method=responses.GET, url=api_url, body="", content_type="application/json") generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render(issue_number, expected_issue["title"], False) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 3) @responses.activate def test_render_issue_with_beta_comment(self): issue_number = self.issue_number_with_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT["beta"]) expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, json=expected_comments) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render(issue_number, expected_issue["title"], False) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 4) @responses.activate def test_render_issue_without_beta_comment(self): issue_number = self.issue_number_without_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( "Some other comment") expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, body="", content_type="application/json") # Mock the comment post response api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment("{} {}".format( GithubIssuesParser.ISSUE_COMMENT["beta"], self.version_number_beta)) responses.add(method=responses.POST, url=api_url, json=expected_comment_1) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render(issue_number, expected_issue["title"], False) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 5) @responses.activate def test_render_issue_with_prod_comment(self): issue_number = self.issue_number_with_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT["prod"]) expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, json=expected_comments) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render(issue_number, expected_issue["title"], False) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 4) @responses.activate def test_render_issue_without_prod_comment(self): issue_number = self.issue_number_without_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( "Some other comment") expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, body="", content_type="application/json") # Mock the comment post response api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment("{} {}".format( GithubIssuesParser.ISSUE_COMMENT["prod"], self.version_number_prod)) responses.add(method=responses.POST, url=api_url, json=expected_comment_1) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render(issue_number, expected_issue["title"], False) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 5) def _create_expected_render(self, issue_number, issue_title, link_pr): render = "# {}\r\n\r\n#{}: {}".format(self.title, issue_number, issue_title) if link_pr: render += " [[PR{}]({})]".format(self.pr_number, self.pr_url) return render
class TestGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api("TestUser", "TestPass") self.title = "Issues" # Set up the mock release_tag lookup response self.issue_number_valid = 123 self.issue_number_invalid = 456 self.pr_number = 789 self.pr_url = "https://github.com/{}/{}/pulls/{}".format( "TestOwner", "TestRepo", self.pr_number) self.mock_util = MockUtil("TestOwner", "TestRepo") @responses.activate def test_issue_numbers(self): self.mock_util.mock_get_repo() change_note = "# {}\r\nFixes #2, Closed #3 and Resolve #5".format( self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = "https://github.com/TestOwner/TestRepo/pulls/{}".format( self.pr_number) expected_content = self._create_expected_content([2, 3, 5], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_issue_numbers_and_other_numbers(self): self.mock_util.mock_get_repo() change_note = "# {}\r\nFixes #2 but not #5".format(self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = "https://github.com/TestOwner/TestRepo/pulls/{}".format( self.pr_number) expected_content = self._create_expected_content([2], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_no_issue_numbers(self): pr_number = 1 self.mock_util.mock_get_repo() change_note = "# {}\r\n#2 and #3 are fixed by this change".format( self.title) self.mock_util.mock_pull_request(pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) self.assertEqual(parser.content, []) @responses.activate def test_render_issue_number_valid(self): api_url = "{}/issues/{}".format(self.repo_api_url, self.issue_number_valid) expected_response = self._get_expected_issue(self.issue_number_valid) self.mock_util.mock_get_repo() responses.add(method=responses.GET, url=api_url, json=expected_response) generator = self._create_generator() generator.link_pr = True parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": self.issue_number_valid, "pr_number": self.pr_number, "pr_url": self.pr_url, }] expected_render = self._create_expected_render( self.issue_number_valid, expected_response["title"], True) self.assertEqual(parser.render(), expected_render) @responses.activate def test_render_issue_number_invalid(self): api_url = "{}/issues/{}".format(self.repo_api_url, self.issue_number_invalid) expected_response = self._get_expected_not_found() self.mock_util.mock_get_repo() responses.add( method=responses.GET, url=api_url, json=expected_response, status=http.client.NOT_FOUND, ) generator = self._create_generator() parser = GithubIssuesParser(generator, self.title) parser.content = [{ "issue_number": self.issue_number_invalid, "pr_number": self.pr_number, "pr_url": self.pr_url, }] with self.assertRaises(GithubApiNotFoundError): parser.render() def test_init__issues_disabled(self): generator = mock.Mock(has_issues=False) with self.assertRaises(GithubIssuesError): parser = GithubIssuesParser(generator, self.title) def _create_expected_content(self, issue_numbers, pr_url): y = [] for n in issue_numbers: y.append({ "issue_number": n, "pr_number": self.pr_number, "pr_url": pr_url }) return y def _create_expected_render(self, issue_number, issue_title, link_pr): render = "# {}\r\n\r\n#{}: {}".format(self.title, issue_number, issue_title) if link_pr: render += " [[PR{}]({})]".format(self.pr_number, self.pr_url) return render def _create_generator(self): generator = GithubReleaseNotesGenerator(self.gh, self.github_info.copy(), PARSER_CONFIG, "release/1.1") return generator
class TestGithubChangeNotesProvider(unittest.TestCase, GithubApiTestMixin): def setUp(self): # Set up the mock release_tag lookup response self.repo_api_url = "https://api.github.com/repos/TestOwner/TestRepo" # Tag that does not exist self.invalid_tag = "release/1.4" # The current production release self.current_tag = "release/1.3" # The previous beta release self.beta_tag = "beta/1.3-Beta_1" # The previous production release with no change notes vs 1.3 self.last_tag = "release/1.2" # The second previous production release with one change note vs 1.3 self.last2_tag = "release/1.1" # The third previous production release with three change notes vs 1.3 self.last3_tag = "release/1.0" self.current_tag_sha = self._random_sha() self.beta_tag_sha = self._random_sha() self.current_tag_commit_sha = self._random_sha() self.current_tag_commit_date = datetime.utcnow() self.last_tag_sha = self._random_sha() self.last_tag_commit_sha = self._random_sha() self.last_tag_commit_date = datetime.utcnow() - timedelta(days=1) self.last2_tag_sha = self._random_sha() self.gh = get_github_api("TestUser", "TestPass") self.init_github() self.mock_util = MockUtil("TestOwner", "TestRepo") def _create_generator(self, current_tag, last_tag=None): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, current_tag, last_tag=last_tag, ) return generator def _mock_current_tag(self): api_url = "{}/git/tags/{}".format(self.repo_api_url, self.current_tag_sha) expected_response = self._get_expected_tag( self.current_tag, self.current_tag_commit_sha, self.current_tag_sha, self.current_tag_commit_date, ) responses.add(method=responses.GET, url=api_url, json=expected_response) return expected_response def _mock_current_tag_commit(self): api_url = "{}/git/commits/{}".format(self.repo_api_url, self.current_tag_commit_sha) expected_response = { "author": { "name": "John Doe", "email": "*****@*****.**", "date": datetime.strftime(self.current_tag_commit_date, date_format), }, "committer": None, "message": "", "parents": [], "sha": self.current_tag_commit_sha, "tree": { "sha": "", "url": "" }, "url": "", "verification": None, } responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_current_tag_ref(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.current_tag) expected_response_current_tag_ref = self._get_expected_tag_ref( self.current_tag, self.current_tag_sha) responses.add(method=responses.GET, url=api_url, json=expected_response_current_tag_ref) def _mock_invalid_tag(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.invalid_tag) expected_response = { "message": "Not Found", "documentation_url": "https://developer.github.com/v3", } responses.add( method=responses.GET, url=api_url, json=expected_response, status=http.client.NOT_FOUND, ) def _mock_last_tag(self): api_url = "{}/git/tags/{}".format(self.repo_api_url, self.last_tag_sha) expected_response = self._get_expected_tag( self.last_tag, self.last_tag_commit_sha, self.last_tag_sha, self.last_tag_commit_date, ) responses.add(method=responses.GET, url=api_url, json=expected_response) return expected_response def _mock_last_tag_commit(self): api_url = "{}/git/commits/{}".format(self.repo_api_url, self.last_tag_commit_sha) expected_response = { "author": { "name": "John Doe", "date": datetime.strftime(self.last_tag_commit_date, date_format), }, "committer": None, "message": "", "parents": [], "sha": self.last_tag_commit_sha, "tree": { "sha": "", "url": "" }, "url": "", "verification": None, } responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_last_tag_ref(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.last_tag) expected_response_last_tag_ref = self._get_expected_tag_ref( self.last_tag, self.last_tag_sha) responses.add(method=responses.GET, url=api_url, json=expected_response_last_tag_ref) def _mock_list_pull_requests_one_in_range(self): api_url = "{}/pulls".format(self.repo_api_url) expected_response = [ self._get_expected_pull_request( 1, 101, "pull 1", datetime.utcnow() - timedelta(seconds=60)), self._get_expected_pull_request( 2, 102, "pull 2", datetime.utcnow() - timedelta(days=4)), self._get_expected_pull_request( 3, 103, "pull 3", datetime.utcnow() - timedelta(days=5)), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_pull_requests_multiple_in_range(self): api_url = "{}/pulls".format(self.repo_api_url) expected_response = [ self._get_expected_pull_request( 1, 101, "pull 1", datetime.utcnow() - timedelta(seconds=60)), self._get_expected_pull_request( 2, 102, "pull 2", datetime.utcnow() - timedelta(seconds=90)), self._get_expected_pull_request( 3, 103, "pull 3", datetime.utcnow() - timedelta(seconds=120)), self._get_expected_pull_request( 4, 104, "pull 4", datetime.utcnow() - timedelta(days=4)), self._get_expected_pull_request( 5, 105, "pull 5", datetime.utcnow() - timedelta(days=5)), self._get_expected_pull_request(6, 106, "pull 6", None), self._get_expected_pull_request( 7, 107, "pull 7", datetime.utcnow() - timedelta(seconds=180), merge_commit_sha=self.last_tag_commit_sha, ), self._get_expected_pull_request( 8, 108, "pull 8", datetime.utcnow(), merge_commit_sha=self.current_tag_commit_sha, ), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_tags_multiple(self): api_url = "{}/tags".format(self.repo_api_url) expected_response = [ self._get_expected_repo_tag(self.current_tag, self.current_tag_sha), self._get_expected_repo_tag(self.beta_tag, self.beta_tag_sha), self._get_expected_repo_tag(self.last_tag, self.last_tag_sha), self._get_expected_repo_tag(self.last2_tag, self.last2_tag_sha), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_tags_single(self): api_url = "{}/tags".format(self.repo_api_url) expected_response = [ self._get_expected_repo_tag(self.current_tag, self.current_tag_sha) ] responses.add(method=responses.GET, url=api_url, json=expected_response) @responses.activate def test_invalid_current_tag(self): self.mock_util.mock_get_repo() self._mock_invalid_tag() generator = self._create_generator(self.invalid_tag) provider = GithubChangeNotesProvider(generator, self.invalid_tag) with self.assertRaises(GithubApiNotFoundError): provider.current_tag_info @responses.activate def test_current_tag_is_lightweight(self): self.mock_util.mock_get_repo() tag = "release/lightweight" generator = self._create_generator(tag) provider = GithubChangeNotesProvider(generator, tag) api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, tag) responses.add( method=responses.GET, url=api_url, json={ "object": { "type": "commit", "url": "", "sha": "" }, "url": "", "ref": "tags/{}".format(tag), }, ) with self.assertRaises(GithubApiError): provider.current_tag_info @responses.activate def test_current_tag_without_last(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() expected_current_tag = self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() expected_last_tag = self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_tags_multiple() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) current_tag = provider.current_tag_info["tag"] last_tag = provider.last_tag_info["tag"] self.assertEqual(current_tag.tag, expected_current_tag["tag"]) self.assertEqual(last_tag.tag, expected_last_tag["tag"]) @responses.activate def test_current_tag_without_last_no_last_found(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_list_tags_single() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) self.assertEqual(provider.last_tag, None) self.assertEqual(provider.last_tag_info, None) @responses.activate def test_no_pull_requests_in_repo(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = "{}/pulls".format(self.repo_api_url) responses.add(method=responses.GET, url=api_url, json=[], content_type="application/json") generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_no_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = "{}/pulls".format(self.repo_api_url) expected_pull_request_1 = self._get_expected_pull_request( pull_id=1, issue_number=101, body="pull 1", merged_date=datetime.utcnow() - timedelta(days=2), ) expected_response_list_pull_requests = [expected_pull_request_1] responses.add(method=responses.GET, url=api_url, json=expected_response_list_pull_requests) generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_one_pull_request_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_one_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = ["pull 1"] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_multiple_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_multiple_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = [] pr_body_list = ["pull 1", "pull 2", "pull 3", "pull 8"] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_pull_requests_with_no_last_tag(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_multiple_in_range() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) provider._get_last_tag = mock.Mock(return_value=None) provider_list = list(provider()) pr_body_list = [] pr_body_list = [ "pull 1", "pull 2", "pull 3", "pull 4", "pull 5", "pull 7", "pull 8", ] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_get_version_from_tag(self): self.mock_util.mock_get_repo() tag = "beta/1.0-Beta_1" generator = self._create_generator(tag) provider = GithubChangeNotesProvider(generator, tag) self.assertEqual("1.0-Beta_1", provider._get_version_from_tag(tag)) with self.assertRaises(ValueError): provider._get_version_from_tag("bogus")
class TestPublishingGithubReleaseNotesGenerator(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.github_info = { "github_owner": "TestOwner", "github_repo": "TestRepo", "github_username": "******", "github_password": "******", "master_branch": "master", } self.gh = get_github_api("TestUser", "TestPass") self.mock_util = MockUtil("TestOwner", "TestRepo") @responses.activate def test_publish_update_unicode(self): tag = "prod/1.4" note = u"“Unicode quotes”" expected_release_body = u"# Changes\r\n\r\n{}".format(note) # mock GitHub API responses self.mock_util.mock_get_repo() # create generator instance generator = self._create_generator(tag) # inject content into Changes parser generator.parsers[1].content.append(note) # render content content = generator.render() # verify self.assertEqual(len(responses.calls._calls), 1) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_no_body(self): tag = "prod/1.4" expected_release_body = "# Changes\r\n\r\nfoo" # mock GitHub API responses self.mock_util.mock_get_repo() # create generator generator = self._create_generator(tag) # inject content into Changes parser generator.parsers[1].content.append("foo") # render content content = generator.render() # verify self.assertEqual(len(responses.calls._calls), 1) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before(self): tag = "prod/1.4" expected_release_body = "foo\r\n# Changes\r\n\r\nbaz" # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases(tag=tag, body="foo\n# Changes\nbar") # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append("baz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_after(self): tag = "prod/1.4" expected_release_body = "# Changes\r\n\r\nbaz\r\n\r\n# Foo\r\nfoo" # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases(tag=tag, body="# Changes\nbar\n# Foo\nfoo") # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append("baz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before_and_after(self): tag = "prod/1.4" expected_release_body = "foo\r\n# Changes\r\n\r\nbaz\r\n\r\n# Foo\r\nfoo" # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body="foo\n# Changes\nbar\n# Foo\nfoo") # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append("baz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_between(self): tag = "prod/1.4" expected_release_body = ("# Critical Changes\r\n\r\nfaz\r\n\r\n" "# Foo\r\nfoo\r\n# Changes\r\n\r\nfiz") # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body="# Critical Changes\nbar\n# Foo\nfoo\n# Changes\nbiz") # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[0].content.append("faz") generator.parsers[1].content.append("fiz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before_after_and_between(self): tag = "prod/1.4" expected_release_body = ( "goo\r\n# Critical Changes\r\n\r\nfaz\r\n\r\n" "# Foo\r\nfoo\r\n# Changes\r\n\r\nfiz\r\n\r\n# Zoo\r\nzoo") # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body=("goo\n# Critical Changes\nbar\n" "# Foo\nfoo\n# Changes\nbiz\n# Zoo\nzoo"), ) # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[0].content.append("faz") generator.parsers[1].content.append("fiz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_missing(self): tag = "prod/1.4" expected_release_body = "foo\r\n# Changes\r\n\r\nbaz\r\n" # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases(tag=tag, body="foo") # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append("baz") # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) def _create_generator(self, current_tag, last_tag=None): generator = GithubReleaseNotesGenerator(self.gh, self.github_info.copy(), PARSER_CONFIG, current_tag, last_tag) return generator @mock.patch( "cumulusci.tasks.release_notes.generator.BaseReleaseNotesGenerator.__call__" ) @responses.activate def test_call(self, base_generator): self.mock_util.mock_get_repo() generator = self._create_generator("prod/1.0") generator.do_publish = True release = mock.Mock() generator._get_release = mock.Mock(return_value=release) generator._update_release_content = mock.Mock( return_value=mock.sentinel.content) result = generator() self.assertIs(mock.sentinel.content, result) base_generator.assert_called_once() release.edit.assert_called_once() @responses.activate def test_call__no_release(self): self.mock_util.mock_get_repo() generator = self._create_generator("prod/1.0") generator._get_release = mock.Mock(return_value=None) with self.assertRaises(CumulusCIException): result = generator()
class TestPublishingGithubReleaseNotesGenerator(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.github_info = { 'github_owner': 'TestOwner', 'github_repo': 'TestRepo', 'github_username': '******', 'github_password': '******', 'master_branch': 'master', } self.gh = get_github_api('TestUser', 'TestPass') self.mock_util = MockUtil('TestOwner', 'TestRepo') @responses.activate def test_publish_update_unicode(self): tag = 'prod/1.4' note = u'“Unicode quotes”' expected_release_body = u'# Changes\r\n\r\n{}'.format(note) # mock GitHub API responses self.mock_util.mock_get_repo() # create generator instance generator = self._create_generator(tag) # inject content into Changes parser generator.parsers[1].content.append(note) # render content content = generator.render() # verify self.assertEqual(len(responses.calls._calls), 1) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_no_body(self): tag = 'prod/1.4' expected_release_body = '# Changes\r\n\r\nfoo' # mock GitHub API responses self.mock_util.mock_get_repo() # create generator generator = self._create_generator(tag) # inject content into Changes parser generator.parsers[1].content.append('foo') # render content content = generator.render() # verify self.assertEqual(len(responses.calls._calls), 1) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before(self): tag = 'prod/1.4' expected_release_body = 'foo\r\n# Changes\r\n\r\nbaz' # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases(tag=tag, body='foo\n# Changes\nbar') # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append('baz') # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_after(self): tag = 'prod/1.4' expected_release_body = '# Changes\r\n\r\nbaz\r\n\r\n# Foo\r\nfoo' # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body='# Changes\nbar\n# Foo\nfoo', ) # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append('baz') # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before_and_after(self): tag = 'prod/1.4' expected_release_body = ( 'foo\r\n# Changes\r\n\r\nbaz\r\n\r\n# Foo\r\nfoo' ) # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body='foo\n# Changes\nbar\n# Foo\nfoo', ) # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[1].content.append('baz') # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_between(self): tag = 'prod/1.4' expected_release_body = ( '# Critical Changes\r\n\r\nfaz\r\n\r\n' '# Foo\r\nfoo\r\n# Changes\r\n\r\nfiz' ) # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body='# Critical Changes\nbar\n# Foo\nfoo\n# Changes\nbiz', ) # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[0].content.append('faz') generator.parsers[1].content.append('fiz') # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) @responses.activate def test_publish_update_content_before_after_and_between(self): tag = 'prod/1.4' expected_release_body = ( 'goo\r\n# Critical Changes\r\n\r\nfaz\r\n\r\n' '# Foo\r\nfoo\r\n# Changes\r\n\r\nfiz\r\n\r\n# Zoo\r\nzoo' ) # mock GitHub API responses self.mock_util.mock_get_repo() self.mock_util.mock_list_releases( tag=tag, body=( 'goo\n# Critical Changes\nbar\n' '# Foo\nfoo\n# Changes\nbiz\n# Zoo\nzoo' ), ) # create generator generator = self._create_generator(tag) # inject content into parser generator.parsers[0].content.append('faz') generator.parsers[1].content.append('fiz') # render and update content content = generator.render() release = generator._get_release() content = generator._update_release_content(release, content) # verify self.assertEqual(len(responses.calls._calls), 3) self.assertEqual(content, expected_release_body) def _create_generator(self, current_tag, last_tag=None): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, current_tag, last_tag, ) return generator
class TestCommentingGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api('TestUser', 'TestPass') self.mock_util = MockUtil('TestOwner', 'TestRepo') self.title = 'Issues' self.issue_number_without_comments = 1 self.issue_number_with_beta_comment = 2 self.issue_number_without_beta_comment = 3 self.issue_number_with_prod_comment = 4 self.issue_number_without_prod_comment = 5 self.pr_number = 6 self.pr_url = 'http://example.com/pulls/{}'.format(self.pr_number) self.tag_prod = 'prod/1.2' self.tag_beta = 'beta/1.2-Beta_3' self.tag_not_prod_or_beta = 'foo' self.version_number_prod = '1.1' self.version_number_beta = '1.2 (Beta 3)' def _create_generator(self, tag): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, tag, publish=True, ) return generator @responses.activate def test_render_issue_without_comments(self): issue_number = self.issue_number_without_comments tag = self.tag_not_prod_or_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = '{}/issues/{}'.format( self.repo_api_url, issue_number, ) expected_issue = self._get_expected_issue(issue_number) responses.add( method=responses.GET, url=api_url, json=expected_issue, ) # Mock the comments list api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) responses.add( method=responses.GET, url=api_url, body=[], content_type='application/json', ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': issue_number, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( issue_number, expected_issue['title'], False, ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 3) @responses.activate def test_render_issue_with_beta_comment(self): issue_number = self.issue_number_with_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = '{}/issues/{}'.format( self.repo_api_url, issue_number, ) expected_issue = self._get_expected_issue(issue_number) responses.add( method=responses.GET, url=api_url, json=expected_issue, ) # Mock the comments list api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT['beta'], ) expected_comments = [ expected_comment_1, ] responses.add( method=responses.GET, url=api_url, json=expected_comments, ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': issue_number, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( issue_number, expected_issue['title'], False, ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 4) @responses.activate def test_render_issue_without_beta_comment(self): issue_number = self.issue_number_without_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() # Mock the issue api_url = '{}/issues/{}'.format( self.repo_api_url, issue_number, ) expected_issue = self._get_expected_issue(issue_number) responses.add( method=responses.GET, url=api_url, json=expected_issue, ) # Mock the comments list api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( 'Some other comment', ) expected_comments = [ expected_comment_1, ] responses.add( method=responses.GET, url=api_url, body=[], content_type='application/json', ) # Mock the comment post response api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( '{} {}'.format( GithubIssuesParser.ISSUE_COMMENT['beta'], self.version_number_beta, ) ) responses.add( method=responses.POST, url=api_url, json=expected_comment_1, ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': issue_number, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( issue_number, expected_issue['title'], False, ) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 5) @responses.activate def test_render_issue_with_prod_comment(self): issue_number = self.issue_number_with_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = '{}/issues/{}'.format( self.repo_api_url, issue_number, ) expected_issue = self._get_expected_issue(issue_number) responses.add( method=responses.GET, url=api_url, json=expected_issue, ) # Mock the comments list api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT['prod'], ) expected_comments = [ expected_comment_1, ] responses.add( method=responses.GET, url=api_url, json=expected_comments, ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': issue_number, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( issue_number, expected_issue['title'], False, ) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 3) @responses.activate def test_render_issue_without_prod_comment(self): issue_number = self.issue_number_without_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = '{}/issues/{}'.format( self.repo_api_url, issue_number, ) expected_issue = self._get_expected_issue(issue_number) responses.add( method=responses.GET, url=api_url, json=expected_issue, ) # Mock the comments list api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( 'Some other comment', ) expected_comments = [ expected_comment_1, ] responses.add( method=responses.GET, url=api_url, body=[], content_type='application/json', ) # Mock the comment post response api_url = '{}/issues/{}/comments'.format( self.repo_api_url, issue_number, ) expected_comment_1 = self._get_expected_issue_comment( '{} {}'.format( GithubIssuesParser.ISSUE_COMMENT['prod'], self.version_number_prod, ) ) responses.add( method=responses.POST, url=api_url, json=expected_comment_1, ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': issue_number, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( issue_number, expected_issue['title'], False, ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 3) def _create_expected_render(self, issue_number, issue_title, link_pr): render = '# {}\r\n\r\n#{}: {}'.format( self.title, issue_number, issue_title, ) if link_pr: render += ' [[PR{}]({})]'.format(self.pr_number, self.pr_url) return render
class TestGithubReleaseNotesGenerator(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.current_tag = "prod/1.4" self.last_tag = "prod/1.3" self.github_info = { "github_owner": "TestOwner", "github_repo": "TestRepo", "github_username": "******", "github_password": "******", } self.gh = get_github_api("TestUser", "TestPass") self.mock_util = MockUtil("TestOwner", "TestRepo") @responses.activate def test_init_without_last_tag(self): github_info = self.github_info.copy() self.mock_util.mock_get_repo() generator = GithubReleaseNotesGenerator(self.gh, github_info, PARSER_CONFIG, self.current_tag) self.assertEqual(generator.github_info, github_info) self.assertEqual(generator.current_tag, self.current_tag) self.assertEqual(generator.last_tag, None) self.assertEqual(generator.change_notes.current_tag, self.current_tag) self.assertEqual(generator.change_notes._last_tag, None) @responses.activate def test_init_with_last_tag(self): github_info = self.github_info.copy() self.mock_util.mock_get_repo() generator = GithubReleaseNotesGenerator(self.gh, github_info, PARSER_CONFIG, self.current_tag, self.last_tag) self.assertEqual(generator.github_info, github_info) self.assertEqual(generator.current_tag, self.current_tag) self.assertEqual(generator.last_tag, self.last_tag) self.assertEqual(generator.change_notes.current_tag, self.current_tag) self.assertEqual(generator.change_notes._last_tag, self.last_tag) @responses.activate def test_mark_down_link_to_pr(self): self.mock_util.mock_get_repo() self.mock_util.mock_pull_request(1, body="# Changes\r\n\r\nfoo", title="Title 1") generator = self._create_generator() pr = generator.get_repo().pull_request(1) actual_link = markdown_link_to_pr(pr) expected_link = "{} [[PR{}]({})]".format(pr.title, pr.number, pr.html_url) self.assertEquals(expected_link, actual_link) @responses.activate def test_render_empty_pr_section(self): self.mock_util.mock_get_repo() self.mock_util.mock_pull_request(1, body="# Changes\r\n\r\nfoo") self.mock_util.mock_pull_request(2, body="# Changes\r\n\r\nbar") generator = self._create_generator() repo = generator.get_repo() pr1 = repo.pull_request(1) pr2 = repo.pull_request(2) generator.empty_change_notes.extend([pr1, pr2]) content = render_empty_pr_section(generator.empty_change_notes) self.assertEquals(3, len(content)) self.assertEquals("\n# Pull requests with no release notes", content[0]) self.assertEquals( "\n* {} [[PR{}]({})]".format(pr1.title, pr1.number, pr1.html_url), content[1], ) self.assertEquals( "\n* {} [[PR{}]({})]".format(pr2.title, pr2.number, pr2.html_url), content[2], ) @responses.activate def test_update_content_with_empty_release_body(self): self.mock_util.mock_get_repo() self.mock_util.mock_pull_request(88, body="Just a small note.") self.mock_util.mock_pull_request(89, body="") generator = self._create_generator() repo = generator.get_repo() pr1 = repo.pull_request(88) pr2 = repo.pull_request(89) generator.include_empty_pull_requests = True generator.empty_change_notes = [pr1, pr2] release = mock.Mock(body=None) content = generator._update_release_content(release, "new content") split_content = content.split("\r\n") self.assertEquals(4, len(split_content)) self.assertEquals("new content", split_content[0]) self.assertEquals("\n# Pull requests with no release notes", split_content[1]) self.assertEquals( "\n* Pull Request #{0} [[PR{0}]({1})]".format( pr1.number, pr1.html_url), split_content[2], ) self.assertEquals( "\n* Pull Request #{0} [[PR{0}]({1})]".format( pr2.number, pr2.html_url), split_content[3], ) @responses.activate def test_detect_empty_change_note(self): self.mock_util.mock_get_repo() self.mock_util.mock_pull_request(1, body="# Changes\r\n\r\nfoo") self.mock_util.mock_pull_request(2, body="Nothing under headers we track") self.mock_util.mock_pull_request(3, body="") generator = self._create_generator() repo = generator.get_repo() pr1 = repo.pull_request(1) pr2 = repo.pull_request(2) pr3 = repo.pull_request(3) generator._parse_change_note(pr1) generator._parse_change_note(pr2) generator._parse_change_note(pr3) # PR1 is "non-empty" second two are "empty" self.assertEquals(2, len(generator.empty_change_notes)) self.assertEquals(2, generator.empty_change_notes[0].number) self.assertEquals(3, generator.empty_change_notes[1].number) def _create_generator(self): generator = GithubReleaseNotesGenerator(self.gh, self.github_info.copy(), PARSER_CONFIG, self.current_tag) return generator
class TestGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api('TestUser', 'TestPass') self.title = 'Issues' # Set up the mock release_tag lookup response self.issue_number_valid = 123 self.issue_number_invalid = 456 self.pr_number = 789 self.pr_url = 'https://github.com/{}/{}/pulls/{}'.format( 'TestOwner', 'TestRepo', self.pr_number, ) self.mock_util = MockUtil('TestOwner', 'TestRepo') @responses.activate def test_issue_numbers(self): self.mock_util.mock_get_repo() change_note = '# {}\r\nFixes #2, Closed #3 and Resolve #5'.format( self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = 'https://github.com/TestOwner/TestRepo/pulls/{}'.format(self.pr_number) expected_content = self._create_expected_content([2, 3, 5], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_issue_numbers_and_other_numbers(self): self.mock_util.mock_get_repo() change_note = '# {}\r\nFixes #2 but not #5'.format( self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = 'https://github.com/TestOwner/TestRepo/pulls/{}'.format(self.pr_number) expected_content = self._create_expected_content([2], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_no_issue_numbers(self): pr_number = 1 self.mock_util.mock_get_repo() change_note = '# {}\r\n#2 and #3 are fixed by this change'.format( self.title) self.mock_util.mock_pull_request(pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) self.assertEqual(parser.content, []) @responses.activate def test_render_issue_number_valid(self): api_url = '{}/issues/{}'.format( self.repo_api_url, self.issue_number_valid) expected_response = self._get_expected_issue(self.issue_number_valid) self.mock_util.mock_get_repo() responses.add( method=responses.GET, url=api_url, json=expected_response, ) generator = self._create_generator() parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': self.issue_number_valid, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] expected_render = self._create_expected_render( self.issue_number_valid, expected_response['title'], False, ) self.assertEqual(parser.render(), expected_render) @responses.activate def test_render_issue_number_invalid(self): api_url = '{}/issues/{}'.format( self.repo_api_url, self.issue_number_invalid) expected_response = self._get_expected_not_found() self.mock_util.mock_get_repo() responses.add( method=responses.GET, url=api_url, json=expected_response, status=httplib.NOT_FOUND, ) generator = self._create_generator() parser = GithubIssuesParser(generator, self.title) parser.content = [{ 'issue_number': self.issue_number_invalid, 'pr_number': self.pr_number, 'pr_url': self.pr_url, }] with self.assertRaises(GithubApiNotFoundError): parser.render() def _create_expected_content(self, issue_numbers, pr_url): y = [] for n in issue_numbers: y.append({ 'issue_number': n, 'pr_number': self.pr_number, 'pr_url': pr_url, }) return y def _create_expected_render(self, issue_number, issue_title, link_pr): render = '# {}\r\n\r\n#{}: {}'.format( self.title, issue_number, issue_title, ) if link_pr: render += ' [[PR{}]({})]'.format(self.pr_number, self.pr_url) return render def _create_generator(self): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, 'prod/1.1', ) return generator
class TestGithubChangeNotesProvider(unittest.TestCase, GithubApiTestMixin): def setUp(self): # Set up the mock release_tag lookup response self.repo_api_url = 'https://api.github.com/repos/TestOwner/TestRepo' # Tag that does not exist self.invalid_tag = 'release/1.4' # The current production release self.current_tag = 'release/1.3' # The previous production release with no change notes vs 1.3 self.last_tag = 'release/1.2' # The second previous production release with one change note vs 1.3 self.last2_tag = 'release/1.1' # The third previous production release with three change notes vs 1.3 self.last3_tag = 'release/1.0' self.current_tag_sha = self._random_sha() self.current_tag_commit_sha = self._random_sha() self.current_tag_commit_date = datetime.utcnow() self.last_tag_sha = self._random_sha() self.last_tag_commit_sha = self._random_sha() self.last_tag_commit_date = datetime.utcnow() - timedelta(days=1) self.last2_tag_sha = self._random_sha() self.gh = login('TestUser', 'TestPass') self.init_github() self.mock_util = MockUtil('TestOwner', 'TestRepo') def _create_generator(self, current_tag, last_tag=None): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, current_tag, last_tag=last_tag ) return generator def _mock_current_tag(self): api_url = '{}/git/tags/{}'.format(self.repo_api_url, self.current_tag_sha) expected_response = self._get_expected_tag( self.current_tag, self.current_tag_sha, self.current_tag_commit_sha, self.current_tag_commit_date, ) responses.add( method=responses.GET, url=api_url, json=expected_response, ) return expected_response def _mock_current_tag_commit(self): api_url = '{}/commits/{}'.format(self.repo_api_url, self.current_tag_commit_sha) expected_response = { 'commit': { 'url': '{}/git/commits/{}'.format( self.repo_api_url, self.current_tag_commit_sha, ), 'author': { 'name': 'John Doe', 'email': '*****@*****.**', 'date': datetime.strftime(self.current_tag_commit_date, date_format), }, }, 'sha': self.current_tag_commit_sha, } responses.add( method=responses.GET, url=api_url, json=expected_response, ) def _mock_current_tag_ref(self): api_url = '{}/git/refs/tags/{}'.format( self.repo_api_url, self.current_tag) expected_response_current_tag_ref = self._get_expected_tag_ref( self.current_tag, self.current_tag_sha) responses.add( method=responses.GET, url=api_url, json=expected_response_current_tag_ref, ) def _mock_invalid_tag(self): api_url = '{}/git/refs/tags/{}'.format( self.repo_api_url, self.invalid_tag) expected_response = { 'message': 'Not Found', 'documentation_url': 'https://developer.github.com/v3' } responses.add( method=responses.GET, url=api_url, json=expected_response, status=httplib.NOT_FOUND, ) def _mock_last_tag(self): api_url = '{}/git/tags/{}'.format(self.repo_api_url, self.last_tag_sha) expected_response = self._get_expected_tag( self.last_tag, self.last_tag_sha, self.last_tag_commit_sha, self.last_tag_commit_date, ) responses.add( method=responses.GET, url=api_url, json=expected_response, ) return expected_response def _mock_last_tag_commit(self): api_url = '{}/commits/{}'.format(self.repo_api_url, self.last_tag_commit_sha) expected_response = { 'commit': { 'author': { 'name': 'John Doe', 'date': datetime.strftime(self.last_tag_commit_date, date_format), }, }, 'sha': self.last_tag_commit_sha, } responses.add( method=responses.GET, url=api_url, json=expected_response, ) def _mock_last_tag_ref(self): api_url = '{}/git/refs/tags/{}'.format( self.repo_api_url, self.last_tag) expected_response_last_tag_ref = self._get_expected_tag_ref( self.last_tag, self.last_tag_sha) responses.add( method=responses.GET, url=api_url, json=expected_response_last_tag_ref, ) def _mock_list_pull_requests_one_in_range(self): api_url = '{}/pulls'.format(self.repo_api_url) expected_response = [ self._get_expected_pull_request(1, 101, 'pull 1', datetime.utcnow() - timedelta(seconds=60)), self._get_expected_pull_request(2, 102, 'pull 2', datetime.utcnow() - timedelta(days=4)), self._get_expected_pull_request(3, 103, 'pull 3', datetime.utcnow() - timedelta(days=5)), ] responses.add( method=responses.GET, url=api_url, json=expected_response, ) def _mock_list_pull_requests_multiple_in_range(self): api_url = '{}/pulls'.format(self.repo_api_url) expected_response = [ self._get_expected_pull_request(1, 101, 'pull 1', datetime.utcnow() - timedelta(seconds=60)), self._get_expected_pull_request(2, 102, 'pull 2', datetime.utcnow() - timedelta(seconds=90)), self._get_expected_pull_request(3, 103, 'pull 3', datetime.utcnow() - timedelta(seconds=120)), self._get_expected_pull_request(4, 104, 'pull 4', datetime.utcnow() - timedelta(days=4)), self._get_expected_pull_request(5, 105, 'pull 5', datetime.utcnow() - timedelta(days=5)), ] responses.add( method=responses.GET, url=api_url, json=expected_response, ) def _mock_list_tags_multiple(self): api_url = '{}/tags'.format(self.repo_api_url) expected_response = [ self._get_expected_tag_ref(self.current_tag, self.current_tag_sha), self._get_expected_tag_ref(self.last_tag, self.last_tag_sha), self._get_expected_tag_ref(self.last2_tag, self.last2_tag_sha), ] responses.add( method=responses.GET, url=api_url, json=expected_response, ) def _mock_list_tags_single(self): api_url = '{}/tags'.format(self.repo_api_url) expected_response = [ self._get_expected_tag_ref(self.current_tag, self.current_tag_sha), ] responses.add( method=responses.GET, url=api_url, json=expected_response, ) @responses.activate def test_invalid_current_tag(self): self.mock_util.mock_get_repo() self._mock_invalid_tag() generator = self._create_generator(self.invalid_tag) provider = GithubChangeNotesProvider(generator, self.invalid_tag) with self.assertRaises(GithubApiNotFoundError): provider.current_tag_info @responses.activate def test_current_tag_without_last(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() expected_current_tag = self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() expected_last_tag = self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_tags_multiple() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) current_tag = provider.current_tag_info['tag'] last_tag = provider.last_tag_info['tag'] self.assertEqual(current_tag.tag, expected_current_tag['tag']) self.assertEqual(last_tag.tag, expected_last_tag['tag']) @responses.activate def test_current_tag_without_last_no_last_found(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_list_tags_single() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) self.assertEqual(provider.last_tag, None) self.assertEqual(provider.last_tag_info, None) @responses.activate def test_no_pull_requests_in_repo(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = '{}/pulls'.format(self.repo_api_url) expected_response_list_pull_requests = [] responses.add( method=responses.GET, url=api_url, body=expected_response_list_pull_requests, content_type='application/json', ) generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider( generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_no_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = '{}/pulls'.format(self.repo_api_url) expected_pull_request_1 = self._get_expected_pull_request( pull_id=1, issue_number=101, body='pull 1', merged_date=datetime.utcnow() - timedelta(days=2), ) expected_response_list_pull_requests = [ expected_pull_request_1, ] responses.add( method=responses.GET, url=api_url, json=expected_response_list_pull_requests, ) generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider( generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_one_pull_request_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_one_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider( generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = ['pull 1'] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_multiple_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_multiple_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider( generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = [] for n in range(1, 4): pr_body_list.append('pull {}'.format(n)) self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body)
class TestGithubChangeNotesProvider(unittest.TestCase, GithubApiTestMixin): def setUp(self): # Set up the mock release_tag lookup response self.repo_api_url = "https://api.github.com/repos/TestOwner/TestRepo" # Tag that does not exist self.invalid_tag = "release/1.4" # The current production release self.current_tag = "release/1.3" # The previous beta release self.beta_tag = "beta/1.3-Beta_1" # The previous production release with no change notes vs 1.3 self.last_tag = "release/1.2" # The second previous production release with one change note vs 1.3 self.last2_tag = "release/1.1" # The third previous production release with three change notes vs 1.3 self.last3_tag = "release/1.0" self.current_tag_sha = self._random_sha() self.beta_tag_sha = self._random_sha() self.current_tag_commit_sha = self._random_sha() self.current_tag_commit_date = datetime.utcnow() self.last_tag_sha = self._random_sha() self.last_tag_commit_sha = self._random_sha() self.last_tag_commit_date = datetime.utcnow() - timedelta(days=1) self.last2_tag_sha = self._random_sha() self.gh = get_github_api("TestUser", "TestPass") self.init_github() self.mock_util = MockUtil("TestOwner", "TestRepo") def _create_generator(self, current_tag, last_tag=None): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, current_tag, last_tag=last_tag, ) return generator def _mock_current_tag(self): api_url = "{}/git/tags/{}".format(self.repo_api_url, self.current_tag_sha) expected_response = self._get_expected_tag( self.current_tag, self.current_tag_commit_sha, self.current_tag_sha, self.current_tag_commit_date, ) responses.add(method=responses.GET, url=api_url, json=expected_response) return expected_response def _mock_current_tag_commit(self): api_url = "{}/git/commits/{}".format( self.repo_api_url, self.current_tag_commit_sha ) expected_response = { "author": { "name": "John Doe", "email": "*****@*****.**", "date": datetime.strftime(self.current_tag_commit_date, date_format), }, "committer": None, "message": "", "parents": [], "sha": self.current_tag_commit_sha, "tree": {"sha": "", "url": ""}, "url": "", "verification": None, } responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_current_tag_ref(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.current_tag) expected_response_current_tag_ref = self._get_expected_tag_ref( self.current_tag, self.current_tag_sha ) responses.add( method=responses.GET, url=api_url, json=expected_response_current_tag_ref ) def _mock_invalid_tag(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.invalid_tag) expected_response = { "message": "Not Found", "documentation_url": "https://developer.github.com/v3", } responses.add( method=responses.GET, url=api_url, json=expected_response, status=http.client.NOT_FOUND, ) def _mock_last_tag(self): api_url = "{}/git/tags/{}".format(self.repo_api_url, self.last_tag_sha) expected_response = self._get_expected_tag( self.last_tag, self.last_tag_commit_sha, self.last_tag_sha, self.last_tag_commit_date, ) responses.add(method=responses.GET, url=api_url, json=expected_response) return expected_response def _mock_last_tag_commit(self): api_url = "{}/git/commits/{}".format( self.repo_api_url, self.last_tag_commit_sha ) expected_response = { "author": { "name": "John Doe", "date": datetime.strftime(self.last_tag_commit_date, date_format), }, "committer": None, "message": "", "parents": [], "sha": self.last_tag_commit_sha, "tree": {"sha": "", "url": ""}, "url": "", "verification": None, } responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_last_tag_ref(self): api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, self.last_tag) expected_response_last_tag_ref = self._get_expected_tag_ref( self.last_tag, self.last_tag_sha ) responses.add( method=responses.GET, url=api_url, json=expected_response_last_tag_ref ) def _mock_list_pull_requests_one_in_range(self): api_url = "{}/pulls".format(self.repo_api_url) expected_response = [ self._get_expected_pull_request( 1, 101, "pull 1", datetime.utcnow() - timedelta(seconds=60) ), self._get_expected_pull_request( 2, 102, "pull 2", datetime.utcnow() - timedelta(days=4) ), self._get_expected_pull_request( 3, 103, "pull 3", datetime.utcnow() - timedelta(days=5) ), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_pull_requests_multiple_in_range(self): api_url = "{}/pulls".format(self.repo_api_url) expected_response = [ self._get_expected_pull_request( 1, 101, "pull 1", datetime.utcnow() - timedelta(seconds=60) ), self._get_expected_pull_request( 2, 102, "pull 2", datetime.utcnow() - timedelta(seconds=90) ), self._get_expected_pull_request( 3, 103, "pull 3", datetime.utcnow() - timedelta(seconds=120) ), self._get_expected_pull_request( 4, 104, "pull 4", datetime.utcnow() - timedelta(days=4) ), self._get_expected_pull_request( 5, 105, "pull 5", datetime.utcnow() - timedelta(days=5) ), self._get_expected_pull_request(6, 106, "pull 6", None), self._get_expected_pull_request( 7, 107, "pull 7", datetime.utcnow() - timedelta(seconds=180), merge_commit_sha=self.last_tag_commit_sha, ), self._get_expected_pull_request( 8, 108, "pull 8", datetime.utcnow(), merge_commit_sha=self.current_tag_commit_sha, ), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_tags_multiple(self): api_url = "{}/tags".format(self.repo_api_url) expected_response = [ self._get_expected_repo_tag(self.current_tag, self.current_tag_sha), self._get_expected_repo_tag(self.beta_tag, self.beta_tag_sha), self._get_expected_repo_tag(self.last_tag, self.last_tag_sha), self._get_expected_repo_tag(self.last2_tag, self.last2_tag_sha), ] responses.add(method=responses.GET, url=api_url, json=expected_response) def _mock_list_tags_single(self): api_url = "{}/tags".format(self.repo_api_url) expected_response = [ self._get_expected_repo_tag(self.current_tag, self.current_tag_sha) ] responses.add(method=responses.GET, url=api_url, json=expected_response) @responses.activate def test_invalid_current_tag(self): self.mock_util.mock_get_repo() self._mock_invalid_tag() generator = self._create_generator(self.invalid_tag) provider = GithubChangeNotesProvider(generator, self.invalid_tag) with self.assertRaises(GithubApiNotFoundError): provider.current_tag_info @responses.activate def test_current_tag_is_lightweight(self): self.mock_util.mock_get_repo() tag = "release/lightweight" generator = self._create_generator(tag) provider = GithubChangeNotesProvider(generator, tag) api_url = "{}/git/refs/tags/{}".format(self.repo_api_url, tag) responses.add( method=responses.GET, url=api_url, json={ "object": {"type": "commit", "url": "", "sha": ""}, "url": "", "ref": "tags/{}".format(tag), }, ) with self.assertRaises(GithubApiError): provider.current_tag_info @responses.activate def test_current_tag_without_last(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() expected_current_tag = self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() expected_last_tag = self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_tags_multiple() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) current_tag = provider.current_tag_info["tag"] last_tag = provider.last_tag_info["tag"] self.assertEqual(current_tag.tag, expected_current_tag["tag"]) self.assertEqual(last_tag.tag, expected_last_tag["tag"]) @responses.activate def test_current_tag_without_last_no_last_found(self): self.mock_util.mock_get_repo() self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_list_tags_single() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) self.assertEqual(provider.last_tag, None) self.assertEqual(provider.last_tag_info, None) @responses.activate def test_no_pull_requests_in_repo(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = "{}/pulls".format(self.repo_api_url) responses.add( method=responses.GET, url=api_url, json=[], content_type="application/json" ) generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_no_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() # Mock the list all pull requests call api_url = "{}/pulls".format(self.repo_api_url) expected_pull_request_1 = self._get_expected_pull_request( pull_id=1, issue_number=101, body="pull 1", merged_date=datetime.utcnow() - timedelta(days=2), ) expected_response_list_pull_requests = [expected_pull_request_1] responses.add( method=responses.GET, url=api_url, json=expected_response_list_pull_requests ) generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) self.assertEqual(list(provider()), []) @responses.activate def test_one_pull_request_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_one_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = ["pull 1"] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_multiple_pull_requests_in_range(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_multiple_in_range() generator = self._create_generator(self.current_tag, self.last_tag) provider = GithubChangeNotesProvider(generator, self.current_tag, self.last_tag) provider_list = list(provider()) pr_body_list = [] pr_body_list = ["pull 1", "pull 2", "pull 3", "pull 8"] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_pull_requests_with_no_last_tag(self): self.mock_util.mock_get_repo() # Mock the tag calls self._mock_current_tag_ref() self._mock_current_tag() self._mock_current_tag_commit() self._mock_last_tag_ref() self._mock_last_tag() self._mock_last_tag_commit() self._mock_list_pull_requests_multiple_in_range() generator = self._create_generator(self.current_tag) provider = GithubChangeNotesProvider(generator, self.current_tag) provider._get_last_tag = mock.Mock(return_value=None) provider_list = list(provider()) pr_body_list = [] pr_body_list = [ "pull 1", "pull 2", "pull 3", "pull 4", "pull 5", "pull 7", "pull 8", ] self.assertEqual(len(provider_list), len(pr_body_list)) for pr, pr_body in zip(provider_list, pr_body_list): self.assertEqual(pr.body, pr_body) @responses.activate def test_get_version_from_tag(self): self.mock_util.mock_get_repo() tag = "beta/1.0-Beta_1" generator = self._create_generator(tag) provider = GithubChangeNotesProvider(generator, tag) self.assertEqual("1.0-Beta_1", provider._get_version_from_tag(tag)) with self.assertRaises(ValueError): provider._get_version_from_tag("bogus")
class TestCommentingGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api("TestUser", "TestPass") self.mock_util = MockUtil("TestOwner", "TestRepo") self.title = "Issues" self.issue_number_without_comments = 1 self.issue_number_with_beta_comment = 2 self.issue_number_without_beta_comment = 3 self.issue_number_with_prod_comment = 4 self.issue_number_without_prod_comment = 5 self.pr_number = 6 self.pr_url = "https://github.com/TestOwner/TestRepo/pulls/{}".format( self.pr_number ) self.tag_prod = "release/1.2" self.tag_beta = "beta/1.2-Beta_3" self.tag_not_prod_or_beta = "foo" self.version_number_prod = "1.1" self.version_number_beta = "1.2 (Beta 3)" def _create_generator(self, tag): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, tag, publish=True ) return generator @responses.activate def test_render_issue_without_comments(self): issue_number = self.issue_number_without_comments tag = self.tag_not_prod_or_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) responses.add( method=responses.GET, url=api_url, json=[], content_type="application/json" ) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( issue_number, expected_issue["title"], False ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 2) @responses.activate def test_render_issue_with_beta_comment(self): issue_number = self.issue_number_with_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() self.mock_util.mock_post_comment(issue_number) # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT["beta"] ) expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, json=expected_comments) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( issue_number, expected_issue["title"], False ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 3) @responses.activate def test_render_issue_without_beta_comment(self): issue_number = self.issue_number_without_beta_comment tag = self.tag_beta self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment("Some other comment") responses.add( method=responses.GET, url=api_url, json=[], content_type="application/json" ) # Mock the comment post response api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( "{} {}".format( GithubIssuesParser.ISSUE_COMMENT["beta"], self.version_number_beta ) ) responses.add(method=responses.POST, url=api_url, json=expected_comment_1) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( issue_number, expected_issue["title"], False ) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 4) @responses.activate def test_render_issue_with_prod_comment(self): issue_number = self.issue_number_with_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( GithubIssuesParser.ISSUE_COMMENT["prod"] ) expected_comments = [expected_comment_1] responses.add(method=responses.GET, url=api_url, json=expected_comments) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( issue_number, expected_issue["title"], False ) self.assertEqual(parser.render(), expected_render) self.assertEqual(len(responses.calls._calls), 3) @responses.activate def test_render_issue_without_prod_comment(self): issue_number = self.issue_number_without_prod_comment tag = self.tag_prod self.mock_util.mock_get_repo() # Mock the issue api_url = "{}/issues/{}".format(self.repo_api_url, issue_number) expected_issue = self._get_expected_issue(issue_number) responses.add(method=responses.GET, url=api_url, json=expected_issue) # Mock the comments list api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment("Some other comment") responses.add( method=responses.GET, url=api_url, json=[], content_type="application/json" ) # Mock the comment post response api_url = "{}/issues/{}/comments".format(self.repo_api_url, issue_number) expected_comment_1 = self._get_expected_issue_comment( "{} {}".format( GithubIssuesParser.ISSUE_COMMENT["prod"], self.version_number_prod ) ) responses.add(method=responses.POST, url=api_url, json=expected_comment_1) generator = self._create_generator(tag) parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": issue_number, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( issue_number, expected_issue["title"], False ) render = parser.render() self.assertEqual(render, expected_render) self.assertEqual(len(responses.calls._calls), 4) def _create_expected_render(self, issue_number, issue_title, link_pr): render = "# {}\r\n\r\n#{}: {}".format(self.title, issue_number, issue_title) if link_pr: render += " [[PR{}]({})]".format(self.pr_number, self.pr_url) return render
class TestGithubIssuesParser(unittest.TestCase, GithubApiTestMixin): def setUp(self): self.init_github() self.gh = get_github_api("TestUser", "TestPass") self.title = "Issues" # Set up the mock release_tag lookup response self.issue_number_valid = 123 self.issue_number_invalid = 456 self.pr_number = 789 self.pr_url = "https://github.com/{}/{}/pulls/{}".format( "TestOwner", "TestRepo", self.pr_number ) self.mock_util = MockUtil("TestOwner", "TestRepo") @responses.activate def test_issue_numbers(self): self.mock_util.mock_get_repo() change_note = "# {}\r\nFixes #2, Closed #3 and Resolve #5".format(self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = "https://github.com/TestOwner/TestRepo/pulls/{}".format(self.pr_number) expected_content = self._create_expected_content([2, 3, 5], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_issue_numbers_and_other_numbers(self): self.mock_util.mock_get_repo() change_note = "# {}\r\nFixes #2 but not #5".format(self.title) self.mock_util.mock_pull_request(self.pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(self.pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) pr_url = "https://github.com/TestOwner/TestRepo/pulls/{}".format(self.pr_number) expected_content = self._create_expected_content([2], pr_url) self.assertEqual(parser.content, expected_content) @responses.activate def test_no_issue_numbers(self): pr_number = 1 self.mock_util.mock_get_repo() change_note = "# {}\r\n#2 and #3 are fixed by this change".format(self.title) self.mock_util.mock_pull_request(pr_number, body=change_note) generator = self._create_generator() repo = generator.get_repo() pull_request = repo.pull_request(pr_number) parser = GithubIssuesParser(generator, self.title) parser.parse(pull_request) self.assertEqual(parser.content, []) @responses.activate def test_render_issue_number_valid(self): api_url = "{}/issues/{}".format(self.repo_api_url, self.issue_number_valid) expected_response = self._get_expected_issue(self.issue_number_valid) self.mock_util.mock_get_repo() responses.add(method=responses.GET, url=api_url, json=expected_response) generator = self._create_generator() generator.link_pr = True parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": self.issue_number_valid, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] expected_render = self._create_expected_render( self.issue_number_valid, expected_response["title"], True ) self.assertEqual(parser.render(), expected_render) @responses.activate def test_render_issue_number_invalid(self): api_url = "{}/issues/{}".format(self.repo_api_url, self.issue_number_invalid) expected_response = self._get_expected_not_found() self.mock_util.mock_get_repo() responses.add( method=responses.GET, url=api_url, json=expected_response, status=http.client.NOT_FOUND, ) generator = self._create_generator() parser = GithubIssuesParser(generator, self.title) parser.content = [ { "issue_number": self.issue_number_invalid, "pr_number": self.pr_number, "pr_url": self.pr_url, } ] with self.assertRaises(GithubApiNotFoundError): parser.render() def test_init__issues_disabled(self): generator = mock.Mock(has_issues=False) with self.assertRaises(GithubIssuesError): GithubIssuesParser(generator, self.title) def _create_expected_content(self, issue_numbers, pr_url): y = [] for n in issue_numbers: y.append({"issue_number": n, "pr_number": self.pr_number, "pr_url": pr_url}) return y def _create_expected_render(self, issue_number, issue_title, link_pr): render = "# {}\r\n\r\n#{}: {}".format(self.title, issue_number, issue_title) if link_pr: render += " [[PR{}]({})]".format(self.pr_number, self.pr_url) return render def _create_generator(self): generator = GithubReleaseNotesGenerator( self.gh, self.github_info.copy(), PARSER_CONFIG, "release/1.1" ) return generator