Beispiel #1
0
def mark_pull_request_build_failed(pr, build_number, failure_message, config):
    """The given pull request failed to build.

    Comment on the pull request to alert the devs of this issue.

    """
    github_info = GithubInfo(
        config['github.owner'],
        config['github.project'],
        config['github.username'],
        config['github.token'],
    )
    jenkins_info = JenkinsInfo(
        config['jenkins.merge.url'],
        config['jenkins.merge.job'],
        config['jenkins.merge.token'],
    )

    pull_request = get_pull_request(pr, github_info)
    build_url = generate_build_url(build_number, jenkins_info)
    try:
        comment = pull_request_build_failed(pull_request, build_url,
                                            failure_message, github_info)
        return comment['url']
    except GithubError as exc:
        return 'Failed to add comment: {0}'.format(exc)
Beispiel #2
0
def do_merge_pull_request(pr, build_number, config):
    """The given pull build passed and needs to be merged.

    """
    github_info = GithubInfo(
        config['github.owner'],
        config['github.project'],
        config['github.username'],
        config['github.token'],
    )
    jenkins_info = JenkinsInfo(
        config['jenkins.merge.url'],
        config['jenkins.merge.job'],
        config['jenkins.merge.token'],
    )

    build_url = generate_build_url(build_number, jenkins_info)
    try:
        result = merge_pull_request(pr, build_url, github_info)
        if result['merged']:
            return result['message']
        else:
            raise GithubError('Failed to merge: {0}'.format(result['message']))
    except GithubError as exc:
        return 'Failed to add comment: {0}'.format(exc)
    def test_pull_request_build_failed(self):
        """Adds a comment to the pull request about the failure."""
        new_comment = load_data('github-new-issue-comment.json')
        pulls = load_data('github-open-pulls.json', load_json=True)
        pull_request = pulls[0]

        responses.add(
            responses.POST,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=new_comment,
            status=201,
            content_type='application/json'
        )

        info = GithubInfo('CanonicalJS', 'juju-gui', 'jujugui', '1234')

        result = pull_request_build_failed(
            pull_request,
            'http://jenkins.com/job/gui/12',
            'Failure message',
            info
        )

        self.assertTrue('body' in result)
    def test_merge_pull_request_fails(self):
        merge_response = load_data('github-merge-failed.json')
        pulls = load_data('github-open-pulls.json', load_json=True)
        pull_request = pulls[0]

        responses.add(
            responses.GET,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls/4',
            body=json.dumps(pull_request),
            status=200,
            content_type='application/json'
        )

        responses.add(
            responses.PUT,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls/4/merge',
            body=merge_response,
            status=405,
            content_type='application/json'
        )

        info = GithubInfo('CanonicalJS', 'juju-gui', 'jujugui', None)
        result = merge_pull_request(
            4,
            'http://jenkins.com/job/gui/12',
            info
        )

        self.assertEqual(False, result['merged'])
        self.assertEqual("Failure reason", result['message'])
    def test_merge_pull_request_fail_unplanned(self):
        """Still throws exception on expected request failure."""
        pulls = load_data('github-open-pulls.json', load_json=True)
        pull_request = pulls[0]

        responses.add(
            responses.GET,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls/4',
            body=json.dumps(pull_request),
            status=200,
            content_type='application/json'
        )
        responses.add(
            responses.PUT,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls/4/merge',
            body='Not Found',
            status=404,
            content_type='application/json'
        )

        info = GithubInfo('CanonicalJS', 'juju-gui', 'jujugui', None)

        self.assertRaises(
            GithubError,
            merge_pull_request,
            4,
            'http://jenkins.com/job/gui/12',
            info
        )
    def test_mergeable_pull_requests(self):
        pulls = load_data('github-open-pulls.json')
        orgs = load_data('github-user-orgs.json')
        comments = load_data('github-pull-request-comments.json')

        responses.add(
            responses.GET,
            'https://api.github.com/users/mitechie/orgs',
            body=orgs,
            status=200,
            content_type='application/json'
        )
        responses.add(
            responses.GET,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls',
            body=pulls,
            status=200,
            content_type='application/json'
        )
        responses.add(
            responses.GET,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=comments,
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('CanonicalJS', 'juju-gui', 'jujugui', None)
        mergeable = mergeable_pull_requests('$$merge$$', info)

        self.assertEqual(1, len(mergeable))
        self.assertEqual(5, mergeable[0]['number'])
    def test_no_mergeable_pull_requests(self):
        pulls = load_data('github-open-pulls.json')

        responses.add(
            responses.GET,
            'https://api.github.com/repos/juju/project/pulls',
            body=pulls,
            status=200,
            content_type='application/json'
        )

        comments = load_data(
            'github-pull-request-comments.json',
            load_json=True)
        # Remove the first comment since it's the trigger one.
        comments.pop(0)

        responses.add(
            responses.GET,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=json.dumps(comments),
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'project', 'jujugui', None)
        mergeable = mergeable_pull_requests('$$merge$$', info)

        self.assertEqual(0, len(mergeable))
    def test_build_url_helper_with_auth(self):
        """Should build a url given a path and a GithubInfo Tuple"""
        info = GithubInfo('juju', 'gui', 'jujugui', '1234')
        path = "/repos/{owner}/{project}/pulls"

        url = github._build_url(path, info)

        self.assertEqual(
            'https://api.github.com/repos/juju/gui/pulls?access_token=1234',
            url)
    def test_open_pull_requests_error(self):
        """Verify a non-200 throws an error"""
        responses.add(
            responses.GET,
            'https://api.github.com/repos/juju/nope/pulls',
            body='{"error": "not found"}',
            status=404,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'nope', 'jujugui', '1234')
        self.assertRaises(GithubError, github.get_open_pull_requests, info)
    def test_user_is_in_org(self):
        user_orgs = load_data('github-user-orgs.json')
        responses.add(
            responses.GET,
            'https://api.github.com/users/jujugui/orgs',
            body=user_orgs,
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'gui', 'jujugui', '1234')
        in_org = github.user_is_in_org('jujugui', 'CanonicalJS', info)

        self.assertTrue(in_org)
Beispiel #11
0
def kick_mergeable_pull_requests(config):
    """Check github for pull requests that include the merge command.

    If the merge command is found, the -merge job in jenkins is kicked to
    start running.

    :return kicked: The list of pull requests that were kicked.

    """
    github_info = GithubInfo(
        config['github.owner'],
        config['github.project'],
        config['github.username'],
        config['github.token'],
    )

    mergable = mergeable_pull_requests(
        config['jenkins.merge.trigger'],
        github_info,
    )

    kicked = []
    if mergable:
        jenkins_info = JenkinsInfo(
            config['jenkins.merge.url'],
            config['jenkins.merge.job'],
            config['jenkins.merge.token'],
        )

        for pr in mergable:
            try:
                kick_jenkins_merge(pr['number'], pr['head']['sha'],
                                   jenkins_info)
                kicked.append('Kicking pull request: {} at sha {}'.format(
                    pr['number'], pr['head']['sha']))

                # Notify the pull request that we've scheduled a build for it.
                jenkins_url = generate_job_url(jenkins_info)
                pull_request_kicked(pr, jenkins_url, github_info)

            except JenkinsError as exc:
                kicked.append(
                    'Failed to kick {0}. Failure message: {1}'.format(
                        pr['number'], exc))

    return kicked
    def test_pull_request_kicked(self):
        new_comment = load_data('github-new-issue-comment.json')
        pulls = load_data('github-open-pulls.json', load_json=True)
        pull_request = pulls[0]

        responses.add(
            responses.POST,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=new_comment,
            status=201,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'project', 'jujugui', None)
        resp = pull_request_kicked(pull_request, 'http://jenkins/job/1', info)
        comment = resp['body']
        self.assertIn(github.MERGE_SCHEDULED, comment)
    def test_not_mergable_if_already_merging(self):
        pulls = load_data('github-open-pulls.json')
        orgs = load_data('github-user-orgs.json')
        comments = load_data(
            'github-pull-request-comments.json', load_json=True)

        # Add the currently merging comment to the list of the pull request to
        # verify it does not mark this as a mergable pull request then.
        merging_comment = load_data(
            'github-new-issue-comment.json', load_json=True)
        comments.append(merging_comment)

        responses.add(
            responses.GET,
            'https://api.github.com/users/mitechie/orgs',
            body=orgs,
            status=200,
            content_type='application/json'
        )
        responses.add(
            responses.GET,
            'https://api.github.com/repos/CanonicalJS/juju-gui/pulls',
            body=pulls,
            status=200,
            content_type='application/json'
        )
        responses.add(
            responses.GET,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=json.dumps(comments),
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('CanonicalJS', 'juju-gui', 'jujugui', None)
        mergeable = mergeable_pull_requests('$$merge$$', info)

        self.assertEqual(0, len(mergeable))
    def test_open_pull_requests(self):
        """Verify we can parse the list."""
        resp_json = load_data('github-open-pulls.json')

        responses.add(
            responses.GET,
            'https://api.github.com/repos/juju/project/pulls',
            body=resp_json,
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'project', 'jujugui', None)
        open_requests = get_open_pull_requests(info)

        self.assertEqual(1, len(open_requests))
        self.assertTrue(
            open_requests[0]['_links']['comments']['href'].endswith(
                '/repos/CanonicalJS/juju-gui/issues/5/comments',
            )
        )
    def test_not_mergeable_if_not_in_org(self):
        pulls = load_data('github-open-pulls.json')
        orgs = load_data('github-user-orgs.json', load_json=True)
        comments = load_data('github-pull-request-comments.json')

        # Remove the CanonicalJS group so that the user fails to be in the
        #org.
        orgs.pop(0)

        responses.add(
            responses.GET,
            'https://api.github.com/users/mitechie/orgs',
            body=json.dumps(orgs),
            status=200,
            content_type='application/json'
        )

        responses.add(
            responses.GET,
            'https://api.github.com/repos/juju/project/pulls',
            body=pulls,
            status=200,
            content_type='application/json'
        )

        responses.add(
            responses.GET,
            (
                u'https://api.github.com/repos/CanonicalJS/juju-gui/issues/5/'
                u'comments'
            ),
            body=comments,
            status=200,
            content_type='application/json'
        )

        info = GithubInfo('juju', 'project', 'jujugui', None)
        mergeable = mergeable_pull_requests('$$merge$$', info)

        self.assertEqual(0, len(mergeable))