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
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()
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()
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)
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()
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()