Beispiel #1
0
 def create_pr_data(self):
     c1, c1_data, c2, c2_data = self.create_commit_data()
     pr = PullRequestEvent.PullRequestEvent()
     pr.pr_number = 1
     pr.action = PullRequestEvent.PullRequestEvent.OPENED
     pr.build_user = self.build_user
     pr.title = 'PR 1'
     pr.html_url = 'url'
     pr.full_text = ''
     pr.base_commit = c1_data
     pr.head_commit = c2_data
     pr.trigger_user = c2.user().name
     return c1_data, c2_data, pr
Beispiel #2
0
 def create_pr_data(self, pr_num=1, changed_files=[]):
     c1 = utils.create_commit(sha='1', branch=self.branch, user=self.owner)
     c2 = utils.create_commit(sha='%s' % pr_num*1000, branch=self.branch, user=self.owner)
     c1_data = GitCommitData.GitCommitData(self.owner.name, c1.repo().name, c1.branch.name, c1.sha, '', c1.server())
     c2_data = GitCommitData.GitCommitData(self.owner.name, c2.repo().name, c2.branch.name, c2.sha, '', c2.server())
     pr = PullRequestEvent.PullRequestEvent()
     pr.pr_number = pr_num
     pr.action = PullRequestEvent.PullRequestEvent.OPENED
     pr.build_user = self.build_user
     pr.title = 'PR %s' % pr_num
     pr.html_url = 'url'
     pr.full_text = ''
     pr.base_commit = c1_data
     pr.head_commit = c2_data
     pr.changed_files = changed_files
     self.set_counts()
     pr.save()
Beispiel #3
0
def process_pull_request(user, data):
    pr_event = PullRequestEvent.PullRequestEvent()
    pr_data = data['pullrequest']

    action = pr_data['state']

    pr_event.pr_number = int(pr_data['id'])

    if action == 'OPEN':
        pr_event.action = PullRequestEvent.PullRequestEvent.OPENED
    elif action == 'MERGED' or action == 'DECLINED':
        pr_event.action = PullRequestEvent.PullRequestEvent.CLOSED
    else:
        raise BitBucketException("Pull request #%s contained unknown action." %
                                 pr_event.pr_number)

    api = user.api()
    pr_event.build_user = user
    html_url = pr_data['links']['html']['href']
    pr_event.title = pr_data['title']
    pr_event.html_url = html_url
    pr_event.trigger_user = pr_data['author']['username']

    base_data = pr_data['destination']
    repo_data = base_data['repository']
    owner = repo_data['full_name'].split('/')[0]
    ssh_url = '[email protected]:{}/{}.git'.format(owner, repo_data['name'])
    pr_event.comments_url = api._pr_comment_api_url(owner, repo_data['name'],
                                                    pr_event.pr_number)

    pr_event.base_commit = GitCommitData.GitCommitData(
        owner, repo_data['name'], base_data['branch']['name'],
        base_data['commit']['hash'], ssh_url, user.server)
    head_data = pr_data['source']
    repo_data = head_data['repository']
    owner = repo_data['full_name'].split('/')[0]
    ssh_url = '[email protected]:{}/{}.git'.format(owner, repo_data['name'])
    pr_event.head_commit = GitCommitData.GitCommitData(
        owner, repo_data['name'], head_data['branch']['name'],
        head_data['commit']['hash'], ssh_url, user.server)

    pr_event.full_text = data
    pr_event.save()
Beispiel #4
0
def view_pr(request, pr_id):
    """
    Show the details of a PR
    Input:
      request: django.http.HttpRequest
      pr_id: pk of models.PullRequest
    Return:
      django.http.HttpResponse based object
    """
    pr = get_object_or_404(models.PullRequest.objects.select_related('repository__user'), pk=pr_id)
    ev = pr.events.select_related('build_user', 'base__branch__repository__user__server').latest()
    allowed = Permissions.is_collaborator(request.session, ev.build_user, ev.base.repo())
    current_alt = []
    alt_choices = []
    default_choices = []
    if allowed:
        alt_recipes = (models.Recipe.objects
                .filter(repository=pr.repository,
                    build_user=ev.build_user,
                    current=True,
                    active=True,
                    cause=models.Recipe.CAUSE_PULL_REQUEST_ALT,)
                .order_by("display_name"))

        default_recipes = (models.Recipe.objects
                .filter(repository=pr.repository,
                    build_user=ev.build_user,
                    current=True,
                    active=True,
                    cause=models.Recipe.CAUSE_PULL_REQUEST,)
                .order_by("display_name"))

        push_recipes = (models.Recipe.objects
                .filter(repository=pr.repository,
                    build_user=ev.build_user,
                    current=True,
                    active=True,
                    cause=models.Recipe.CAUSE_PUSH,)
                .order_by("display_name"))

        default_recipes = [r for r in default_recipes.all()]
        current_alt = [ r.pk for r in pr.alternate_recipes.all() ]
        current_default = [j.recipe.filename for j in pr.events.latest("created").jobs.all() ]
        push_map = {r.filename: r.branch for r in push_recipes.all()}
        alt_choices = []
        for r in alt_recipes:
            alt_choices.append({"recipe": r,
                "selected": r.pk in current_alt,
                "push_branch": push_map.get(r.filename),
                })

        default_choices = []
        for r in default_recipes:
            default_choices.append({"recipe": r,
                "pk": r.pk,
                "disabled": r.filename in current_default,
                "push_branch": push_map.get(r.filename),
                })

        if alt_choices and request.method == "POST":
            form_choices = [ (r.pk, r.display_name) for r in alt_recipes ]
            form = forms.AlternateRecipesForm(request.POST)
            form.fields["recipes"].choices = form_choices
            form_default_choices = []
            for r in default_choices:
                if not r["disabled"]:
                    form_default_choices.append((r["pk"], r["recipe"].display_name))
            form.fields["default_recipes"].choices = form_default_choices
            if form.is_valid():
                pr.alternate_recipes.clear()
                for pk in form.cleaned_data["recipes"]:
                    alt = models.Recipe.objects.get(pk=pk)
                    pr.alternate_recipes.add(alt)
                # do some saves to update the timestamp so that the javascript updater gets activated
                pr.save()
                pr.events.latest('created').save()
                messages.info(request, "Success")
                pr_event = PullRequestEvent.PullRequestEvent()
                selected_default_recipes = []
                if form.cleaned_data["default_recipes"]:
                    q = models.Recipe.objects.filter(pk__in=form.cleaned_data["default_recipes"])
                    selected_default_recipes = [r for r in q]
                pr_event.create_pr_alternates(pr, default_recipes=selected_default_recipes)
                # update the choices so the new form is correct
                current_alt = [ r.pk for r in pr.alternate_recipes.all() ]
                alt_choices = [ {"recipe": r, "selected": r.pk in current_alt} for r in alt_recipes ]
            else:
                messages.warning(request, "Invalid form")
                logger.warning("Invalid form")
                for field, errors in form.errors.items():
                    logger.warning("Form error in field: %s: %s" % (field, errors))

    events = EventsStatus.events_with_head(pr.events)
    evs_info = EventsStatus.multiline_events_info(events, events_url=True)
    context = { "pr": pr,
        "events": evs_info,
        "allowed": allowed,
        "update_interval": settings.EVENT_PAGE_UPDATE_INTERVAL,
        "alt_choices": alt_choices,
        "default_choices": default_choices,
        }
    return render(request, 'ci/pr.html', context)
Beispiel #5
0
def process_pull_request(user, data):
    """
    Process the data from a Pull request.
    Input:
      user: models.GitUser: the build user that created the hook.
      auth: OAuth2Session: session started for the build user
      data: dict: data sent by the webook
    Return:
      models.Event if successful, else None
    """

    git_api = user.api()
    pr_event = PullRequestEvent.PullRequestEvent()

    attributes = data['object_attributes']
    action = attributes['state']

    pr_event.pr_number = int(attributes['iid'])

    if action == 'opened' or action == 'synchronize':
        pr_event.action = PullRequestEvent.PullRequestEvent.OPENED
    elif action == 'closed' or action == 'merged':
        # The PR is closed which means that the source branch might not exist
        # anymore so we won't be able to fill out the full PullRequestEvent
        # (since we need additional API calls to get all the information we need).
        # So just close this manually.
        close_pr(attributes['target']['path_with_namespace'].split('/')[0],
                 attributes['target']['name'], pr_event.pr_number, user.server)
        return None
    elif action == 'reopened':
        pr_event.action = PullRequestEvent.PullRequestEvent.REOPENED
    else:
        raise GitLabException("Pull request %s contained unknown action." %
                              pr_event.pr_number)

    target_id = attributes['target_project_id']
    target = attributes['target']
    source_id = attributes['source_project_id']
    source = attributes['source']
    pr_event.title = attributes['title']

    server_config = user.server.server_config()
    for prefix in server_config.get("pr_wip_prefix", []):
        if pr_event.title.startswith(prefix):
            # We don't want to test when the PR is marked as a work in progress
            logger.info('Ignoring work in progress PR: {}'.format(
                pr_event.title))
            return None

    pr_event.trigger_user = data['user']['username']
    pr_event.build_user = user
    pr_event.comments_url = git_api._comment_api_url(target_id,
                                                     attributes['iid'])
    full_path = '{}/{}'.format(target['path_with_namespace'].split('/')[0],
                               target['name'])
    pr_event.html_url = git_api._pr_html_url(full_path, attributes['iid'])

    url = git_api._branch_by_id_url(source_id, attributes['source_branch'])
    response = git_api.get(url)
    if not response or git_api._bad_response:
        msg = "CIVET encountered an error retrieving branch `%s:%s`.\n\n" % \
                (source['path_with_namespace'], attributes['source_branch'])
        msg += "This is typically caused by `%s` not having access to the repository.\n\n" % user.name
        msg += "Please grant `Developer` access to `%s` and try again.\n\n" % user.name
        git_api.pr_comment(pr_event.comments_url, msg)
        raise GitLabException(msg)
    else:
        source_branch = response.json()

    url = git_api._branch_by_id_url(target_id, attributes['target_branch'])
    target_branch = git_api.get(url).json()

    access_level = git_api._get_project_access_level(
        source['path_with_namespace'])
    if access_level not in ["Developer", "Master", "Owner"]:
        msg = "CIVET does not have proper access to the source repository `%s`.\n\n" % \
                (source['path_with_namespace'])
        msg += "This can result in CIVET not being able to tell GitLab that CI is in progress.\n\n"
        msg += "`%s` currently has `%s` access.\n\n" % (user.name,
                                                        access_level)
        msg += "Please grant `Developer` access to `%s` and try again.\n\n" % user.name
        logger.warning(msg)
        git_api.pr_comment(pr_event.comments_url, msg)

    pr_event.base_commit = GitCommitData.GitCommitData(
        target['path_with_namespace'].split('/')[0],
        target['name'],
        attributes['target_branch'],
        target_branch['commit']['id'],
        target['ssh_url'],
        user.server,
    )

    pr_event.head_commit = GitCommitData.GitCommitData(
        source['path_with_namespace'].split('/')[0],
        source['name'],
        attributes['source_branch'],
        source_branch['commit']['id'],
        source['ssh_url'],
        user.server,
    )

    if pr_event.head_commit.exists(
    ) and pr_event.action != PullRequestEvent.PullRequestEvent.REOPENED:
        e = "PR {} on {}/{}: got an update but ignoring as it has the same commit {}/{}:{}".format(
            pr_event.pr_number, pr_event.base_commit.owner,
            pr_event.base_commit.repo, pr_event.head_commit.owner,
            pr_event.head_commit.ref, pr_event.head_commit.sha)
        logger.info(e)
        return None
    pr_event.full_text = [data, target_branch, source_branch]
    pr_event.changed_files = git_api._get_pr_changed_files(
        pr_event.base_commit.owner, pr_event.base_commit.repo,
        attributes['iid'])
    pr_event.save()
Beispiel #6
0
def process_pull_request(user, data):
    pr_event = PullRequestEvent.PullRequestEvent()
    pr_data = data['pull_request']

    action = data['action']

    pr_event.pr_number = int(data['number'])

    state = pr_data['state']
    if action == 'opened' or action == 'synchronize' or (action == "edited" and state == "open"):
        pr_event.action = PullRequestEvent.PullRequestEvent.OPENED
    elif action == 'closed':
        pr_event.action = PullRequestEvent.PullRequestEvent.CLOSED
    elif action == 'reopened':
        pr_event.action = PullRequestEvent.PullRequestEvent.REOPENED
    elif action in ['labeled', 'unlabeled', 'assigned', 'unassigned', 'review_requested', 'review_request_removed', 'edited']:
        # actions that we don't support. "edited" is not supported if the PR is closed.
        logger.info('Ignoring github action "{}" on PR: #{}: {}'.format(action, data['number'], pr_data['title']))
        return None
    else:
        raise GitException("Pull request %s contained unknown action: %s" % (pr_event.pr_number, action))


    pr_event.trigger_user = pr_data['user']['login']
    pr_event.build_user = user
    pr_event.comments_url = pr_data['comments_url']
    pr_event.review_comments_url = pr_data['review_comments_url']
    pr_event.title = pr_data['title']

    server_config = user.server.server_config()
    for prefix in server_config.get("pr_wip_prefix", []):
        if pr_event.title.startswith(prefix):
            # We don't want to test when the PR is marked as a work in progress
            logger.info('Ignoring work in progress PR: {}'.format(pr_event.title))
            return None

    pr_event.html_url = pr_data['html_url']

    base_data = pr_data['base']
    pr_event.base_commit = GitCommitData.GitCommitData(
        base_data['repo']['owner']['login'],
        base_data['repo']['name'],
        base_data['ref'],
        base_data['sha'],
        base_data['repo']['ssh_url'],
        user.server
        )
    head_data = pr_data['head']
    pr_event.head_commit = GitCommitData.GitCommitData(
        head_data['repo']['owner']['login'],
        head_data['repo']['name'],
        head_data['ref'],
        head_data['sha'],
        head_data['repo']['ssh_url'],
        user.server
        )

    gapi = user.api()
    if action == 'synchronize':
        # synchronize is used when updating due to a new push in the branch that the PR is tracking
        gapi._remove_pr_todo_labels(pr_event.base_commit.owner, pr_event.base_commit.repo, pr_event.pr_number)

    pr_event.full_text = data
    pr_event.changed_files = gapi._get_pr_changed_files(
            pr_event.base_commit.owner,
            pr_event.base_commit.repo,
            pr_event.pr_number,
            )
    pr_event.save()