Пример #1
0
    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")
Пример #2
0
 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')
Пример #3
0
 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')
Пример #4
0
 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")
Пример #5
0
 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")
Пример #6
0
 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")
Пример #7
0
 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')
    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")
Пример #9
0
 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)"
Пример #10
0
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)
Пример #11
0
 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)'
Пример #12
0
 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")
Пример #13
0
    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')
Пример #14
0
 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)"
Пример #15
0
 def mock_util(self):
     return MockUtil("TestOwner", "TestRepo")
Пример #16
0
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
Пример #17
0
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
Пример #18
0
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 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")
Пример #20
0
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()
Пример #21
0
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)
Пример #22
0
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
Пример #23
0
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
Пример #24
0
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
Пример #25
0
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
Пример #26
0
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
Пример #27
0
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