Example #1
0
def pull(user, repo, number):
    token = session['token']
    commits = github.get_pull_request_commits(token, user, repo, number)
    pr = github.get_pull_request(token, user, repo, number)
    comments = github.get_pull_request_comments(token, user, repo, number)

    commit_to_comments = defaultdict(int)
    for comment in comments['diff_level']:
        commit_to_comments[comment['original_commit_id']] += 1

    commits.reverse()
    # Add an entry for the base commit.
    commits.append({
        'sha': pr['base']['sha'],
        'commit': {
            'message': '(%s)' % pr['base']['ref'],
            'author': {'date': ''}
        },
        'author': {'login': ''}
    })

    for commit in commits:
        commit['comment_count'] = commit_to_comments[commit['sha']]

    return render_template('pull_request.html', commits=commits, user=user, repo=repo, pull_request=pr, comments=comments)
Example #2
0
def get_release_pr(github_access_token, org, repo):
    """
    Look up the pull request information for a release, or return None if it doesn't exist

    Args:
        github_access_token (str): The github access token
        org (str): The github organization (eg mitodl)
        repo (str): The github repository (eg micromasters)

    Returns:
        ReleasePR: The information about the release pull request, or None if there is no release PR in progress
    """
    pr = get_pull_request(github_access_token, org, repo, 'release-candidate')
    if pr is None:
        return None

    title = pr['title']
    match = re.match(r'^Release (?P<version>\d+\.\d+\.\d+)$', title)
    if not match:
        raise ReleaseException("Release PR title has an unexpected format")
    version = match.group('version')

    return ReleasePR(
        version=version,
        body=pr['body'],
        url=pr['html_url'],
    )
Example #3
0
def check_for_updates():
    owner = request.form['owner']
    repo = request.form['repo']
    pull_number = request.form['pull_number']
    updated_at = request.form['updated_at']
    token = session['token']

    pr = github.get_pull_request(token, owner, repo, pull_number,
                                 bust_cache=True)

    if not pr:
        return "Error"

    if pr['updated_at'] <= updated_at:
        return "OK"

    # Invalidate associated RPCs: commit list, comments
    github.expire_cache_for_pull_request_children(owner, repo, pull_number)
    return "Update"
Example #4
0
def post_comment():
    owner = request.form['owner']
    repo = request.form['repo']
    pull_number = request.form['pull_number']
    path = request.form['path']
    commit_id = request.form['commit_id']
    line_number = int(request.form['line_number'])
    body = request.form['body']

    if not owner:
        return "Incomplete post_comment request, missing owner"
    if not repo:
        return "Incomplete post_comment request, missing repo"
    if not pull_number:
        return "Incomplete post_comment request, missing pull_number"
    if not path:
        return "Incomplete post_comment request, missing path"
    if not commit_id:
        return "Incomplete post_comment request, missing commit_id"
    if not line_number:
        return "Incomplete post_comment request, missing line_number"
    if not body:
        return "Incomplete post_comment request, missing body"

    token = session['token']
    if not token:
        return "You must be oauthed to post a comment."

    pr = github.get_pull_request(token, owner, repo, pull_number)
    base_sha = pr['base']['sha']

    diff_position = github_comments.lineNumberToDiffPosition(token, owner, repo, base_sha, path, commit_id, line_number, False)  # False = on_left (for now!)
    if not diff_position:
        return "Unable to get diff position for %s:%s @%s" % (path, line_number, commit_id)

    sys.stderr.write('diff_position=%s\n' % diff_position)

    response = github.post_comment(token, owner, repo, pull_number, commit_id, path, diff_position, body)
    if response:
        github_comments.add_line_number_to_comment(token, owner, repo, base_sha, response)

    return jsonify(response)
Example #5
0
def gh_merge_do(owner, repo, pr_id):
    import github
    user = github.user_from_oauth(bottle.request.oauth_token)
    pr = github.get_pull_request(owner, repo, pr_id)
    if 'login' not in user:
        raise bottle.HTTPError(403, 'Could not identify user')
    if 'user' not in pr:
        raise bottle.HTTPError(403, 'Could not identify PR')
    if user['login'] != pr['user']['login']:
        raise bottle.HTTPError(403, 'Merge requester is not the PR author')
    if pr['merged']:
        raise bottle.HTTPError(403, 'PR is already merged')
    if not pr['mergeable']:
        raise bottle.HTTPError(403, 'PR cannot be merged. Please rebase')
    if not github.is_pull_request_buildable(pr):
        raise bottle.HTTPError(403, 'PR status not green. Wait or fix errors')
    if not github.is_pull_request_self_mergeable(pr):
        raise bottle.HTTPError(403, 'Nobody allowed you to merge this PR')
    github.merge_pr(pr)
    bottle.redirect(pr['html_url'])
Example #6
0
def gh_merge_do(owner, repo, pr_id):
    import github

    user = github.user_from_oauth(bottle.request.oauth_token)
    pr = github.get_pull_request(owner, repo, pr_id)
    if "login" not in user:
        raise bottle.HTTPError(403, "Could not identify user")
    if "user" not in pr:
        raise bottle.HTTPError(403, "Could not identify PR")
    if user["login"] != pr["user"]["login"]:
        raise bottle.HTTPError(403, "Merge requester is not the PR author")
    if pr["merged"]:
        raise bottle.HTTPError(403, "PR is already merged")
    if not pr["mergeable"]:
        raise bottle.HTTPError(403, "PR cannot be merged. Please rebase")
    if not github.is_pull_request_buildable(pr):
        raise bottle.HTTPError(403, "PR status not green. Wait or fix errors")
    if not github.is_pull_request_self_mergeable(pr):
        raise bottle.HTTPError(403, "Nobody allowed you to merge this PR")
    github.merge_pr(pr)
    bottle.redirect(pr["html_url"])
Example #7
0
def save_draft_comment():
    owner = request.form['owner']
    repo = request.form['repo']
    path = request.form['path']
    pull_number = request.form['pull_number']
    commit_id = request.form['commit_id']
    line_number = int(request.form['line_number'])
    in_reply_to = request.args.get('in_reply_to')
    comment = {
      'owner': owner,
      'repo': repo,
      'pull_number': pull_number,
      'path': path,
      'original_commit_id': commit_id,
      'body': request.form['body']
    }
    if in_reply_to:
      comment['in_reply_to'] = in_reply_to

    comment_id = request.form.get('id')
    if comment_id:
        comment['id'] = comment_id

    token = session['token']
    pr = github.get_pull_request(token, owner, repo, pull_number)
    base_sha = pr['base']['sha']

    position, hunk = github_comments.lineNumberToDiffPositionAndHunk(token, owner, repo, base_sha, path, commit_id, line_number, False)
    if not position:
        return "Unable to get diff position for %s:%s @%s" % (path, line_number, commit_id)

    comment['original_position'] = position
    comment['diff_hunk'] = hunk

    result = db.add_draft_comment(session['login'], comment)
    result = db.githubify_comment(result)
    # This is a bit roundabout, but more reliable!
    github_comments.add_line_number_to_comment(token, owner, repo, base_sha,
                                               result)
    return jsonify(result)
Example #8
0
def file_diff(user, repo, number):
    path = request.args.get('path', '')
    sha1 = request.args.get('sha1', '')
    sha2 = request.args.get('sha2', '')
    if not (path and sha1 and sha2):
        return "Incomplete request (need path, sha1, sha2)"

    # TODO(danvk): consolidate this code with the pull route
    token = session['token']
    commits = github.get_pull_request_commits(token, user, repo, number)
    pr = github.get_pull_request(token, user, repo, number)
    comments = github.get_pull_request_comments(token, user, repo, number)

    open('/tmp/commits.txt', 'wb').write(json.dumps(commits, indent=2))

    commit_to_comments = defaultdict(int)
    for comment in comments['diff_level']:
        commit_to_comments[comment['original_commit_id']] += 1

    commits.reverse()
    # Add an entry for the base commit.
    commits.append({
        'sha': pr['base']['sha'],
        'commit': {
            'message': '(%s)' % pr['base']['ref'],
            'author': {'date': ''}
        },
        'author': {'login': ''}
    })


    # github excludes the first four header lines of "git diff"
    diff_info = github.get_diff_info(token, user, repo, sha1, sha2)
    unified_diff = github.get_file_diff(token, user, repo, path, sha1, sha2)
    if not unified_diff or not diff_info:
        return "Unable to get diff for %s..%s" % (sha1, sha2)

    github_diff = '\n'.join(unified_diff.split('\n')[4:])

    # TODO(danvk): only annotate comments on this file.
    github_comments.add_line_numbers_to_comments(token, user, repo, pr['base']['sha'], comments['diff_level'])

    differing_files = [f['filename'] for f in diff_info['files']]
    before = github.get_file_at_ref(token, user, repo, path, sha1)
    after = github.get_file_at_ref(token, user, repo, path, sha2)

    def diff_url(path):
        return (url_for('file_diff', user=user, repo=repo, number=number) +
                '?path=' + urllib.quote(path) +
                '&sha1=' + urllib.quote(sha1) + '&sha2=' + urllib.quote(sha2))

    linked_files = [{'path':p, 'link': diff_url(p)} for p in differing_files]

    if path in differing_files:
        file_idx = differing_files.index(path)
        prev_file = linked_files[file_idx - 1] if file_idx > 0 else None
        next_file = linked_files[file_idx + 1] if file_idx < len(linked_files) - 1 else None
    else:
        # The current file is not part of this diff.
        # Just do something sensible.
        prev_file = None
        next_file = linked_files[0] if len(linked_files) > 0 else None
    
    pull_request_url = url_for('pull', user=user, repo=repo, number=number)

    return render_template('file_diff.html', commits=commits, user=user, repo=repo, pull_request=pr, comments=comments, path=path, sha1=sha1, sha2=sha2, before_contents=before, after_contents=after, differing_files=linked_files, prev_file=prev_file, next_file=next_file, github_diff=github_diff, pull_request_url=pull_request_url)