Exemplo n.º 1
0
def change_authors(pull_request, commits):
    '''
    Changes may have multiple authors in some cases, if multiple people created
    commits.  We order the authors according to the number of commits they
    created.

    Sometimes there is not a github user associated with a commit; in these
    cases, we fall back to the PR author.
    '''
    commits_per_author = defaultdict(lambda: 0)
    authors = {}
    num_commits_with_no_author = 0
    for commit in commits:
        if commit.author:
            author = commit.author
            commits_per_author[author.id] += 1
            authors[author.id] = author
        else:
            num_commits_with_no_author += 1
    if num_commits_with_no_author > 0:
        msg = '{} commits had no author in {}'
        print_warning(msg.format(num_commits_with_no_author, pull_request.html_url))
    author_commits = list(commits_per_author.items())
    sorted_author_commits = sorted(author_commits, key=lambda ac: ac[1], reverse=True)
    authors = [authors[aid] for (aid, c) in sorted_author_commits]

    if len(authors) > 0:
        return authors
    else:
        msg = 'No commits have an author for {}, using pull request author instead'
        print_warning(msg.format(pull_request.html_url))
        return [pull_request.user]
Exemplo n.º 2
0
def change_approvals(system, pull_request):
    '''
    Sometimes it makes sense to have third-parties who may not have access to
    GitHub perform reviews.  When this occurs, the pull request is tagged with
    the `external-review` label.  It is assumed that the person doing the
    review is mentioned in the body of the review.  In this case, their may be
    no explicit approvals, but also no warnings will be logged.

    If there are no github review with the "approval" status, then we fall back to using
    github reviews with the "comment" status.
    '''
    external_review = 'external-review' in [
        l.name for l in pull_request.labels
    ]

    if ('reviews_required' in system):
        reviews_required = system['reviews_required']
    else:
        reviews_required = True

    if external_review or not reviews_required:
        return []

    github_reviews = [r for r in pull_request.get_reviews()]
    approvals = [
        build_approval(r) for r in github_reviews if r.state == 'APPROVED'
    ]

    if approvals:
        return approvals

    # Responses to review comments (oddly) show up in github as reviews; we
    # apply some extra filtering here to attempt to remove these.
    github_comments = [
        r for r in github_reviews
        if r.state == 'COMMENTED' and r.user != pull_request.user
    ]

    if github_comments:
        msg = 'No "approved" github reviews for pull request {}, using last "comment" instead'
        print_warning(msg.format(pull_request.html_url))
        return [build_approval(github_comments[-1])]
    else:

        msg = 'No reviews for pull request {}'
        print_warning(msg.format(pull_request.html_url))
        return []
Exemplo n.º 3
0
def extract_change_requests(pull_request, commits):
    '''
    Deduce which change request a given "change" (i.e., pull request) applies
    to. Look through the commits in each pull request, and keep track of all of
    the issues that these commits reference.
    '''
    change_requests = set()
    for commit in commits:
        commit_issue_numbers = extract_issue_numbers_from_commit_message(commit.commit.message)
        change_requests.update(commit_issue_numbers)
    body_issue_numbers = extract_issue_numbers_from_commit_message(pull_request.body)
    change_requests.update(body_issue_numbers)
    if len(change_requests) == 0:
        branch_name = pull_request.head.ref
        msg = 'Unable to associate pull request (branch {}) with a change request; {}'
        print_warning(msg.format(branch_name, pull_request.html_url))
    return list(change_requests)
Exemplo n.º 4
0
def build_change(system, pull_request):
    commits = pull_request.get_commits()
    approvals = change_approvals(system, pull_request)
    authors = change_authors(pull_request, commits)

    if authors[0] in approvals:
        msg = 'Primary author {} is also a reviewer for pull request {}'
        print_warning(msg.format(authors[0], pull_request.html_url))

    return OrderedDict([
        ('id', str(pull_request.number)),
        ('content', change_body(pull_request.body)),
        ('approvals', approvals),
        ('authors', authors),
        ('change_requests', extract_change_requests(pull_request, commits)),
        ('url', pull_request.html_url),
    ])
Exemplo n.º 5
0
def attach_changes(changes, change_requests):
    '''
    We want to store the connection between change requests and changes with
    the change requests, because when we generate the templates, we display
    each change, and within it, we display each change request.

    But, in GitHub, the connection is stored with the changes.

    This function mutates the changes and change requests, moving the
    connection from the former to the latter.
    '''
    change_request_id_to_changes = defaultdict(lambda: [])
    for change in changes:
        for change_request_id in change['change_requests']:
            change_request_id_to_changes[change_request_id].append(change['id'])
        del change['change_requests']
    for change_request in change_requests:
        if change_request['id'] in change_request_id_to_changes:
            change_request['change_ids'] = change_request_id_to_changes[change_request['id']]
        elif not change_request['is_problem_report']:
            msg = 'No changes implemented for change request {}'
            print_warning(msg.format(change_request['url']))
Exemplo n.º 6
0
def check_user(user):
    if user.login not in seen_users:
        seen_users.add(user.login)
        if user.name is None:
            msg = 'GitHub User {id} {login} does not have a name; using {login} in place of a name'
            print_warning(msg.format(id=user.id, login=user.login))
Exemplo n.º 7
0
def check_user(user):
    if user.login not in seen_users:
        seen_users.add(user.login)
        if user.name is None:
            msg = 'GitHub User {} {} does not have a name'
            print_warning(msg.format(user.id, user.login))