##// END OF EJS Templates
fix(caching): fixed problems with Cache query for users....
fix(caching): fixed problems with Cache query for users. The old way of querying caused the user get query to be always cached, and returning old results even in 2fa forms. The new limited query doesn't cache the user object resolving issues

File last commit:

r5211:5e903185 default
r5365:ae8a165b default
Show More
repo_pull_requests.py
1878 lines | 78.1 KiB | text/x-python | PythonLexer
copyrights: updated for 2023
r5088 # Copyright (C) 2011-2023 RhodeCode GmbH
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
pull-requests: migrated code from pylons to pyramid
r1974 import collections
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
pull-requests: migrated code from pylons to pyramid
r1974 import formencode
apps: cleanup imports
r2080 import formencode.htmlfill
pull-requests: migrated code from pylons to pyramid
r1974 import peppercorn
from pyramid.httpexceptions import (
comment-history: fixes/ui changes...
r4408 HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest, HTTPConflict)
application: not use config.scan(), and replace all @add_view decorator into a explicit add_view call for faster app start.
r4610
pull-requests: migrated code from pylons to pyramid
r1974 from pyramid.renderers import render
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
from rhodecode.apps._base import RepoAppView, DataGridAppView
pull-requests: migrated code from pylons to pyramid
r1974
from rhodecode.lib import helpers as h, diffs, codeblocks, channelstream
from rhodecode.lib.base import vcs_operation_context
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 from rhodecode.lib.diffs import load_cached_diff, cache_diff, diff_cache_exist
comment-history: fixes/ui changes...
r4408 from rhodecode.lib.exceptions import CommentVersionMismatch
json: fixed calls to json after orjson implementation
r4974 from rhodecode.lib import ext_json
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 from rhodecode.lib.auth import (
pull-requests: security double check permissions on injected forms of source and target repositories.
r2177 LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator,
NotAnonymous, CSRFRequired)
core: multiple fixes to unicode vs str usage...
r5065 from rhodecode.lib.utils2 import str2bool, safe_str, safe_int, aslist, retry
observers: code cleanups and fixed tests.
r4519 from rhodecode.lib.vcs.backends.base import (
EmptyCommit, UpdateFailureReason, unicode_to_reference)
pull-requests: fix way how pull-request calculates common ancestors....
r4346 from rhodecode.lib.vcs.exceptions import (
CommitDoesNotExistError, RepositoryRequirementError, EmptyRepositoryError)
pull-requests: migrated code from pylons to pyramid
r1974 from rhodecode.model.changeset_status import ChangesetStatusModel
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 from rhodecode.model.comment import CommentsModel
pull-requests: fix way how pull-request calculates common ancestors....
r4346 from rhodecode.model.db import (
comments: introduce new draft comments....
r4540 func, false, or_, PullRequest, ChangesetComment, ChangesetStatus, Repository,
reviewers: added observers as another way to define reviewers....
r4500 PullRequestReviewers)
pull-requests: migrated code from pylons to pyramid
r1974 from rhodecode.model.forms import PullRequestForm
from rhodecode.model.meta import Session
pull-requests: prepare the migration of pull request to pyramid....
r1813 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
pull-requests: migrated code from pylons to pyramid
r1974 from rhodecode.model.scm import ScmModel
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
log = logging.getLogger(__name__)
class RepoPullRequestsView(RepoAppView, DataGridAppView):
def load_default_context(self):
pull-requests: prepare the migration of pull request to pyramid....
r1813 c = self._get_local_tmpl_context(include_app_defaults=True)
c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
pull-requests: make the renderer stored and saved for each pull requests....
r2903 # backward compat., we use for OLD PRs a plain renderer
c.renderer = 'plain'
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 return c
def _get_pull_requests_list(
self, repo_name, source, filter_type, opened_by, statuses):
draw, start, limit = self._extract_chunk(self.request)
search_q, order_by, order_dir = self._extract_ordering(self.request)
core: use new style pyramid partial renderer where possible.
r1897 _render = self.request.get_partial_renderer(
partial-renderer: use package resource format for templates....
r2313 'rhodecode:templates/data_table/_dt_elements.mako')
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
# pagination
if filter_type == 'awaiting_review':
pull_requests = PullRequestModel().get_awaiting_review(
pull-requests: added awaiting my review filter for users pull-requests....
r4690 repo_name,
search_q=search_q, statuses=statuses,
offset=start, length=limit, order_by=order_by, order_dir=order_dir)
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 pull_requests_total_count = PullRequestModel().count_awaiting_review(
pull-requests: added awaiting my review filter for users pull-requests....
r4690 repo_name,
search_q=search_q, statuses=statuses)
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 elif filter_type == 'awaiting_my_review':
pull_requests = PullRequestModel().get_awaiting_my_review(
pull-requests: added awaiting my review filter for users pull-requests....
r4690 repo_name, self._rhodecode_user.user_id,
search_q=search_q, statuses=statuses,
offset=start, length=limit, order_by=order_by, order_dir=order_dir)
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 pull_requests_total_count = PullRequestModel().count_awaiting_my_review(
pull-requests: added awaiting my review filter for users pull-requests....
r4690 repo_name, self._rhodecode_user.user_id,
search_q=search_q, statuses=statuses)
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 else:
pull_requests = PullRequestModel().get_all(
pull-requests: added quick filter to grid view.
r4055 repo_name, search_q=search_q, source=source, opened_by=opened_by,
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 statuses=statuses, offset=start, length=limit,
order_by=order_by, order_dir=order_dir)
pull_requests_total_count = PullRequestModel().count_all(
pull-requests: added quick filter to grid view.
r4055 repo_name, search_q=search_q, source=source, statuses=statuses,
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 opened_by=opened_by)
data = []
comments_model = CommentsModel()
for pr in pull_requests:
pull-requests: use count only for comments related to display grids on my account and repo view.
r4506 comments_count = comments_model.get_all_comments(
comments: counts exclude now draft comments, they shouldn't be visible.
r4553 self.db_repo.repo_id, pull_request=pr,
include_drafts=False, count_only=True)
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
pull-requests: added awaiting my review filter for users pull-requests....
r4690 review_statuses = pr.reviewers_statuses(user=self._rhodecode_db_user)
my_review_status = ChangesetStatus.STATUS_NOT_REVIEWED
if review_statuses and review_statuses[4]:
_review_obj, _user, _reasons, _mandatory, statuses = review_statuses
my_review_status = statuses[0][1].status
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 data.append({
'name': _render('pullrequest_name',
pull-requests: loosen strict view of pull-requests that state is changing...
r4103 pr.pull_request_id, pr.pull_request_state,
pull-requests: make my account and repo pr table more consistent.
r4512 pr.work_in_progress, pr.target_repo.repo_name,
short=True),
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 'name_raw': pr.pull_request_id,
'status': _render('pullrequest_status',
pr.calculated_review_status()),
pull-requests: added awaiting my review filter for users pull-requests....
r4690 'my_status': _render('pullrequest_status',
my_review_status),
dan
pull-requests: add indication of state change in list of pull-requests and actually show them in the list.
r3816 'title': _render('pullrequest_title', pr.title, pr.description),
pull-requests: added commit flow into pr listing tables
r5170 'pr_flow': _render('pullrequest_commit_flow', pr),
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 'description': h.escape(pr.description),
'updated_on': _render('pullrequest_updated_on',
pull-requests: show pr version in the my-account and repo pr listing grids.
r4557 h.datetime_to_time(pr.updated_on),
pr.versions_count),
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 'updated_on_raw': h.datetime_to_time(pr.updated_on),
'created_on': _render('pullrequest_updated_on',
h.datetime_to_time(pr.created_on)),
'created_on_raw': h.datetime_to_time(pr.created_on),
dan
pull-requests: add indication of state change in list of pull-requests and actually show them in the list.
r3816 'state': pr.pull_request_state,
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 'author': _render('pullrequest_author',
pr.author.full_contact, ),
'author_raw': pr.author.full_name,
pull-requests: use count only for comments related to display grids on my account and repo view.
r4506 'comments': _render('pullrequest_comments', comments_count),
'comments_raw': comments_count,
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766 'closed': pr.is_closed(),
})
data = ({
'draw': draw,
'data': data,
'recordsTotal': pull_requests_total_count,
'recordsFiltered': pull_requests_total_count,
})
return data
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pull_request_list(self):
c = self.load_default_context()
req_get = self.request.GET
c.source = str2bool(req_get.get('source'))
c.closed = str2bool(req_get.get('closed'))
c.my = str2bool(req_get.get('my'))
c.awaiting_review = str2bool(req_get.get('awaiting_review'))
c.awaiting_my_review = str2bool(req_get.get('awaiting_my_review'))
c.active = 'open'
if c.my:
c.active = 'my'
if c.closed:
c.active = 'closed'
if c.awaiting_review and not c.source:
c.active = 'awaiting'
if c.source and not c.awaiting_review:
c.active = 'source'
if c.awaiting_my_review:
c.active = 'awaiting_my'
return self._get_template_context(c)
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pull_request_list_data(self):
pylons: fixed code and test suite after removal of pylons.
r2358 self.load_default_context()
pull-requests: moved the listing of pull requests for repo into pyramid....
r1766
# additional filters
req_get = self.request.GET
source = str2bool(req_get.get('source'))
closed = str2bool(req_get.get('closed'))
my = str2bool(req_get.get('my'))
awaiting_review = str2bool(req_get.get('awaiting_review'))
awaiting_my_review = str2bool(req_get.get('awaiting_my_review'))
filter_type = 'awaiting_review' if awaiting_review \
else 'awaiting_my_review' if awaiting_my_review \
else None
opened_by = None
if my:
opened_by = [self._rhodecode_user.user_id]
statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
if closed:
statuses = [PullRequest.STATUS_CLOSED]
data = self._get_pull_requests_list(
repo_name=self.db_repo_name, source=source,
filter_type=filter_type, opened_by=opened_by, statuses=statuses)
return data
pull-requests: prepare the migration of pull request to pyramid....
r1813
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 def _is_diff_cache_enabled(self, target_repo):
caching_enabled = self._get_general_setting(
target_repo, 'rhodecode_diff_cache')
log.debug('Diff caching enabled: %s', caching_enabled)
return caching_enabled
pull-requests: prepare the migration of pull request to pyramid....
r1813 def _get_diffset(self, source_repo_name, source_repo,
pull-requests: fix way how pull-request calculates common ancestors....
r4346 ancestor_commit,
pull-requests: prepare the migration of pull request to pyramid....
r1813 source_ref_id, target_ref_id,
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 target_commit, source_commit, diff_limit, file_limit,
pull-requests: use proper diff calculation for versioning of PRs.
r4426 fulldiff, hide_whitespace_changes, diff_context, use_ancestor=True):
pull-requests: prepare the migration of pull request to pyramid....
r1813
diffs: fixed diff rendering when a common ancestor was a different commit than the source of changes.
r4593 target_commit_final = target_commit
source_commit_final = source_commit
pull-requests: use proper diff calculation for versioning of PRs.
r4426 if use_ancestor:
# we might want to not use it for versions
target_ref_id = ancestor_commit.raw_id
diffs: fixed diff rendering when a common ancestor was a different commit than the source of changes.
r4593 target_commit_final = ancestor_commit
pull-requests: use proper diff calculation for versioning of PRs.
r4426
pull-requests: prepare the migration of pull request to pyramid....
r1813 vcs_diff = PullRequestModel().get_diff(
dan
diffs: introducing diff menu for whitespace toggle and context changes
r3134 source_repo, source_ref_id, target_ref_id,
hide_whitespace_changes, diff_context)
pull-requests: prepare the migration of pull request to pyramid....
r1813
apps: various fixes and improvements for python3
r5072 diff_processor = diffs.DiffProcessor(vcs_diff, diff_format='newdiff', diff_limit=diff_limit,
pull-requests: prepare the migration of pull request to pyramid....
r1813 file_limit=file_limit, show_full_diff=fulldiff)
_parsed = diff_processor.prepare()
diffset = codeblocks.DiffSet(
repo_name=self.db_repo_name,
source_repo_name=source_repo_name,
diffs: fixed diff rendering when a common ancestor was a different commit than the source of changes.
r4593 source_node_getter=codeblocks.diffset_node_getter(target_commit_final),
target_node_getter=codeblocks.diffset_node_getter(source_commit_final),
pull-requests: prepare the migration of pull request to pyramid....
r1813 )
path-permissions: Initial support for path-based permissions
r2618 diffset = self.path_filter.render_patchset_filtered(
diffs: fixed diff rendering when a common ancestor was a different commit than the source of changes.
r4593 diffset, _parsed, target_ref_id, source_ref_id)
pull-requests: prepare the migration of pull request to pyramid....
r1813
return diffset
pull-requests: allow to show range diff in pr view
r3124 def _get_range_diffset(self, source_scm, source_repo,
commit1, commit2, diff_limit, file_limit,
dan
diffs: introducing diff menu for whitespace toggle and context changes
r3134 fulldiff, hide_whitespace_changes, diff_context):
pull-requests: allow to show range diff in pr view
r3124 vcs_diff = source_scm.get_diff(
commit1, commit2,
dan
diffs: introducing diff menu for whitespace toggle and context changes
r3134 ignore_whitespace=hide_whitespace_changes,
context=diff_context)
pull-requests: allow to show range diff in pr view
r3124
apps: various fixes and improvements for python3
r5072 diff_processor = diffs.DiffProcessor(vcs_diff, diff_format='newdiff',
diff_limit=diff_limit,
file_limit=file_limit, show_full_diff=fulldiff)
pull-requests: allow to show range diff in pr view
r3124
_parsed = diff_processor.prepare()
diffset = codeblocks.DiffSet(
repo_name=source_repo.repo_name,
source_node_getter=codeblocks.diffset_node_getter(commit1),
target_node_getter=codeblocks.diffset_node_getter(commit2))
diffset = self.path_filter.render_patchset_filtered(
diffset, _parsed, commit1.raw_id, commit2.raw_id)
return diffset
comments: introduce new draft comments....
r4540 def register_comments_vars(self, c, pull_request, versions, include_drafts=True):
pull-requests: overhaul of the UX by adding new sidebar...
r4482 comments_model = CommentsModel()
# GENERAL COMMENTS with versions #
q = comments_model._all_general_comments_of_pull_request(pull_request)
q = q.order_by(ChangesetComment.comment_id.asc())
comments: introduce new draft comments....
r4540 if not include_drafts:
q = q.filter(ChangesetComment.draft == false())
pull-requests: overhaul of the UX by adding new sidebar...
r4482 general_comments = q
# pick comments we want to render at current version
c.comment_versions = comments_model.aggregate_comments(
general_comments, versions, c.at_version_num)
# INLINE COMMENTS with versions #
q = comments_model._all_inline_comments_of_pull_request(pull_request)
q = q.order_by(ChangesetComment.comment_id.asc())
comments: introduce new draft comments....
r4540 if not include_drafts:
q = q.filter(ChangesetComment.draft == false())
pull-requests: overhaul of the UX by adding new sidebar...
r4482 inline_comments = q
c.inline_versions = comments_model.aggregate_comments(
inline_comments, versions, c.at_version_num, inline=True)
# Comments inline+general
if c.at_version:
c.inline_comments_flat = c.inline_versions[c.at_version_num]['display']
c.comments = c.comment_versions[c.at_version_num]['display']
else:
c.inline_comments_flat = c.inline_versions[c.at_version_num]['until']
c.comments = c.comment_versions[c.at_version_num]['until']
return general_comments, inline_comments
pull-requests: prepare the migration of pull request to pyramid....
r1813 @LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pull_request_show(self):
pull-requests: introduce operation state for pull requests to prevent from...
r3371 _ = self.request.translate
c = self.load_default_context()
pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull_request_id = pull_request.pull_request_id
pull-requests: migrated code from pylons to pyramid
r1974
pull-requests: loosen strict view of pull-requests that state is changing...
r4103 c.state_progressing = pull_request.is_state_changing()
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505 c.pr_broadcast_channel = channelstream.pr_channel(pull_request)
pull-requests: prepare the migration of pull request to pyramid....
r1813
pull-requests: allow super-admins to force change state of locked PRs....
r4233 _new_state = {
'created': PullRequest.STATE_CREATED,
}.get(self.request.GET.get('force_state'))
pull-requests: allow forced state change to repo admins too.
r4710 can_force_state = c.is_super_admin or HasRepoPermissionAny('repository.admin')(c.repo_name)
pull-requests: fix way how pull-request calculates common ancestors....
r4346
pull-requests: allow forced state change to repo admins too.
r4710 if can_force_state and _new_state:
pull-requests: allow super-admins to force change state of locked PRs....
r4233 with pull_request.set_state(PullRequest.STATE_UPDATING, final_state=_new_state):
h.flash(
_('Pull Request state was force changed to `{}`').format(_new_state),
category='success')
Session().commit()
raise HTTPFound(h.route_path(
'pullrequest_show', repo_name=self.db_repo_name,
pull_request_id=pull_request_id))
pull-requests: prepare the migration of pull request to pyramid....
r1813 version = self.request.GET.get('version')
from_version = self.request.GET.get('from_version') or version
merge_checks = self.request.GET.get('merge_checks')
c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
pull-requests: overhaul of the UX by adding new sidebar...
r4482 force_refresh = str2bool(self.request.GET.get('force_refresh'))
c.range_diff_on = self.request.GET.get('range-diff') == "1"
dan
diffs: introducing diff menu for whitespace toggle and context changes
r3134
# fetch global flags of ignore ws or context lines
diff_context = diffs.get_diff_context(self.request)
hide_whitespace_changes = diffs.get_diff_whitespace_flag(self.request)
pull-requests: prepare the migration of pull request to pyramid....
r1813 (pull_request_latest,
pull_request_at_ver,
pull_request_display_obj,
pull-requests: moved get_pr_version into PullRequestModel.
r2393 at_version) = PullRequestModel().get_pr_version(
pull-requests: prepare the migration of pull request to pyramid....
r1813 pull_request_id, version=version)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
pull-requests: prepare the migration of pull request to pyramid....
r1813 pr_closed = pull_request_latest.is_closed()
if pr_closed and (version or from_version):
fix(pull-requests): fixes for rendering comments
r5211 # not allow browsing versions for closed PR
pull-requests: prepare the migration of pull request to pyramid....
r1813 raise HTTPFound(h.route_path(
'pullrequest_show', repo_name=self.db_repo_name,
pull_request_id=pull_request_id))
versions = pull_request_display_obj.versions()
pull-requests: expose commit versions in the pull-request commit list. Fixes #5642
r4615
c.commit_versions = PullRequestModel().pr_commits_versions(versions)
pull-requests: allow to show range diff in pr view
r3124 # used to store per-commit range diffs
c.changes = collections.OrderedDict()
pull-requests: prepare the migration of pull request to pyramid....
r1813
c.at_version = at_version
c.at_version_num = (at_version
pull-requests: overhaul of the UX by adding new sidebar...
r4482 if at_version and at_version != PullRequest.LATEST_VER
pull-requests: prepare the migration of pull request to pyramid....
r1813 else None)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
c.at_version_index = ChangesetComment.get_index_from_version(
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.at_version_num, versions)
(prev_pull_request_latest,
prev_pull_request_at_ver,
prev_pull_request_display_obj,
pull-requests: moved get_pr_version into PullRequestModel.
r2393 prev_at_version) = PullRequestModel().get_pr_version(
pull-requests: prepare the migration of pull request to pyramid....
r1813 pull_request_id, version=from_version)
c.from_version = prev_at_version
c.from_version_num = (prev_at_version
pull-requests: overhaul of the UX by adding new sidebar...
r4482 if prev_at_version and prev_at_version != PullRequest.LATEST_VER
pull-requests: prepare the migration of pull request to pyramid....
r1813 else None)
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c.from_version_index = ChangesetComment.get_index_from_version(
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.from_version_num, versions)
# define if we're in COMPARE mode or VIEW at version mode
compare = at_version != prev_at_version
# pull_requests repo_name we opened it against
fix(pull-requests): fixes for rendering comments
r5211 # i.e., target_repo must match
pull-requests: prepare the migration of pull request to pyramid....
r1813 if self.db_repo_name != pull_request_at_ver.target_repo.repo_name:
pull-requests: log a mismatch of name changed during a display of a PR....
r4472 log.warning('Mismatch between the current repo: %s, and target %s',
self.db_repo_name, pull_request_at_ver.target_repo.repo_name)
pull-requests: prepare the migration of pull request to pyramid....
r1813 raise HTTPNotFound()
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c.shadow_clone_url = PullRequestModel().get_shadow_clone_url(pull_request_at_ver)
pull-requests: prepare the migration of pull request to pyramid....
r1813
c.pull_request = pull_request_display_obj
pull-requests: make the renderer stored and saved for each pull requests....
r2903 c.renderer = pull_request_at_ver.description_renderer or c.renderer
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.pull_request_latest = pull_request_latest
pull-requests: overhaul of the UX by adding new sidebar...
r4482 # inject latest version
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
c.versions = versions + [latest_ver]
if compare or (at_version and not at_version == PullRequest.LATEST_VER):
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.allowed_to_change_status = False
c.allowed_to_update = False
c.allowed_to_merge = False
c.allowed_to_delete = False
c.allowed_to_comment = False
c.allowed_to_close = False
else:
can_change_status = PullRequestModel().check_user_change_status(
pull_request_at_ver, self._rhodecode_user)
c.allowed_to_change_status = can_change_status and not pr_closed
c.allowed_to_update = PullRequestModel().check_user_update(
pull_request_latest, self._rhodecode_user) and not pr_closed
c.allowed_to_merge = PullRequestModel().check_user_merge(
pull_request_latest, self._rhodecode_user) and not pr_closed
c.allowed_to_delete = PullRequestModel().check_user_delete(
pull_request_latest, self._rhodecode_user) and not pr_closed
c.allowed_to_comment = not pr_closed
c.allowed_to_close = c.allowed_to_merge and not pr_closed
c.forbid_adding_reviewers = False
if pull_request_latest.reviewer_data and \
'rules' in pull_request_latest.reviewer_data:
rules = pull_request_latest.reviewer_data['rules'] or {}
try:
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c.forbid_adding_reviewers = rules.get('forbid_adding_reviewers')
pull-requests: prepare the migration of pull request to pyramid....
r1813 except Exception:
pass
# check merge capabilities
_merge_check = MergeCheck.validate(
pull-requests: add merge validation to prevent merges to protected branches.
r2981 pull_request_latest, auth_user=self._rhodecode_user,
shadow-repos: use numeric repo id for creation of shadow repos....
r2810 translator=self.request.translate,
force_shadow_repo_refresh=force_refresh)
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.pr_merge_errors = _merge_check.error_details
c.pr_merge_possible = not _merge_check.failed
c.pr_merge_message = _merge_check.merge_msg
dan
pull-requests: add information about changes in source repositories in pull-request show page....
r4317 c.pr_merge_source_commit = _merge_check.source_commit
c.pr_merge_target_commit = _merge_check.target_commit
pull-requests: prepare the migration of pull request to pyramid....
r1813
pull-requests: trigger merge simulation during PR creation. Fixes #5396
r2168 c.pr_merge_info = MergeCheck.get_merge_conditions(
pull_request_latest, translator=self.request.translate)
pull-requests: use merge info to show how Pull requests will be merged....
r2053
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.pull_request_review_status = _merge_check.review_status
if merge_checks:
self.request.override_renderer = \
'rhodecode:templates/pullrequests/pullrequest_merge_checks.mako'
return self._get_template_context(c)
reviewers: added observers as another way to define reviewers....
r4500 c.reviewers_count = pull_request.reviewers_count
c.observers_count = pull_request.observers_count
pull-requests: prepare the migration of pull request to pyramid....
r1813
# reviewers and statuses
json: fixed calls to json after orjson implementation
r4974 c.pull_request_default_reviewers_data_json = ext_json.str_json(pull_request.reviewer_data)
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c.pull_request_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
reviewers: added observers as another way to define reviewers....
r4500 c.pull_request_set_observers_data_json = collections.OrderedDict({'observers': []})
pull-requests: prepare the migration of pull request to pyramid....
r1813
fix(pull-requests): fixes for rendering comments
r5211 # reviewers
pull-requests: overhaul of the UX by adding new sidebar...
r4482 for review_obj, member, reasons, mandatory, status in pull_request_at_ver.reviewers_statuses():
member_reviewer = h.reviewer_as_json(
member, reasons=reasons, mandatory=mandatory,
reviewers: added observers as another way to define reviewers....
r4500 role=review_obj.role,
pull-requests: overhaul of the UX by adding new sidebar...
r4482 user_group=review_obj.rule_user_group_data()
)
pull-requests: prepare the migration of pull request to pyramid....
r1813
pull-requests: overhaul of the UX by adding new sidebar...
r4482 current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED
member_reviewer['review_status'] = current_review_status
member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status)
member_reviewer['allowed_to_update'] = c.allowed_to_update
c.pull_request_set_reviewers_data_json['reviewers'].append(member_reviewer)
pull-requests: prepare the migration of pull request to pyramid....
r1813
json: fixed calls to json after orjson implementation
r4974 c.pull_request_set_reviewers_data_json = ext_json.str_json(c.pull_request_set_reviewers_data_json)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
fix(pull-requests): fixes for rendering comments
r5211 # observers
reviewers: added observers as another way to define reviewers....
r4500 for observer_obj, member in pull_request_at_ver.observers():
member_observer = h.reviewer_as_json(
member, reasons=[], mandatory=False,
role=observer_obj.role,
user_group=observer_obj.rule_user_group_data()
)
member_observer['allowed_to_update'] = c.allowed_to_update
c.pull_request_set_observers_data_json['observers'].append(member_observer)
json: fixed calls to json after orjson implementation
r4974 c.pull_request_set_observers_data_json = ext_json.str_json(c.pull_request_set_observers_data_json)
reviewers: added observers as another way to define reviewers....
r4500
pull-requests: overhaul of the UX by adding new sidebar...
r4482 general_comments, inline_comments = \
self.register_comments_vars(c, pull_request_latest, versions)
pull-requests: prepare the migration of pull request to pyramid....
r1813
comments: re-implemented diff and comments/todos in pull-requests.
r3884 # TODOs
c.unresolved_comments = CommentsModel() \
pull-requests: overhaul of the UX by adding new sidebar...
r4482 .get_pull_request_unresolved_todos(pull_request_latest)
comments: re-implemented diff and comments/todos in pull-requests.
r3884 c.resolved_comments = CommentsModel() \
pull-requests: overhaul of the UX by adding new sidebar...
r4482 .get_pull_request_resolved_todos(pull_request_latest)
pull-requests: prepare the migration of pull request to pyramid....
r1813
drafts: sidebar functionality
r4562 # Drafts
c.draft_comments = CommentsModel().get_pull_request_drafts(
self._rhodecode_db_user.user_id,
pull_request_latest)
pull-requests: prepare the migration of pull request to pyramid....
r1813 # if we use version, then do not show later comments
# than current version
display_inline_comments = collections.defaultdict(
lambda: collections.defaultdict(list))
for co in inline_comments:
if c.at_version_num:
# pick comments that are at least UPTO given version, so we
# don't render comments for higher version
should_render = co.pull_request_version_id and \
co.pull_request_version_id <= c.at_version_num
else:
# showing all, for 'latest'
should_render = True
if should_render:
display_inline_comments[co.f_path][co.line_no].append(co)
# load diff data into template context, if we use compare mode then
# diff is calculated based on changes between versions of PR
source_repo = pull_request_at_ver.source_repo
source_ref_id = pull_request_at_ver.source_ref_parts.commit_id
target_repo = pull_request_at_ver.target_repo
target_ref_id = pull_request_at_ver.target_ref_parts.commit_id
if compare:
# in compare switch the diff base to latest commit from prev version
target_ref_id = prev_pull_request_display_obj.revisions[0]
# despite opening commits for bookmarks/branches/tags, we always
# convert this to rev to prevent changes after bookmark or branch change
c.source_ref_type = 'rev'
c.source_ref = source_ref_id
c.target_ref_type = 'rev'
c.target_ref = target_ref_id
c.source_repo = source_repo
c.target_repo = target_repo
c.commit_ranges = []
source_commit = EmptyCommit()
target_commit = EmptyCommit()
c.missing_requirements = False
source_scm = source_repo.scm_instance()
target_scm = target_repo.scm_instance()
shadow-repos: check if path to shadow repo existing before trying to call SCM object....
r2797 shadow_scm = None
pull-requests: prepare the migration of pull request to pyramid....
r1813 try:
shadow-repos: check if path to shadow repo existing before trying to call SCM object....
r2797 shadow_scm = pull_request_latest.get_shadow_repo()
pull-requests: prepare the migration of pull request to pyramid....
r1813 except Exception:
log.debug('Failed to get shadow repo', exc_info=True)
shadow-repos: check if path to shadow repo existing before trying to call SCM object....
r2797 # try first the existing source_repo, and then shadow
# repo if we can obtain one
pull-requests: fixed source of changes to be using shadow repos if it exists....
r4128 commits_source_repo = source_scm
if shadow_scm:
commits_source_repo = shadow_scm
pull-requests: prepare the migration of pull request to pyramid....
r1813
c.commits_source_repo = commits_source_repo
c.ancestor = None # set it to None, to hide it from PR view
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 # empty version means latest, so we keep this to prevent
# double caching
pull-requests: overhaul of the UX by adding new sidebar...
r4482 version_normalized = version or PullRequest.LATEST_VER
from_version_normalized = from_version or PullRequest.LATEST_VER
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685
pull-requests: allow to show range diff in pr view
r3124 cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(target_repo)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 cache_file_path = diff_cache_exist(
cache_path, 'pull_request', pull_request_id, version_normalized,
dan
diffs: introducing diff menu for whitespace toggle and context changes
r3134 from_version_normalized, source_ref_id, target_ref_id,
hide_whitespace_changes, diff_context, c.fulldiff)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685
caching_enabled = self._is_diff_cache_enabled(c.target_repo)
pull-requests: allow to show range diff in pr view
r3124 force_recache = self.get_recache_flag()
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685
cached_diff = None
if caching_enabled:
cached_diff = load_cached_diff(cache_file_path)
pull-requests: prepare the migration of pull request to pyramid....
r1813
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 has_proper_commit_cache = (
cached_diff and cached_diff.get('commits')
and len(cached_diff.get('commits', [])) == 5
and cached_diff.get('commits')[0]
and cached_diff.get('commits')[3])
pull-requests: allow to show range diff in pr view
r3124
if not force_recache and not c.range_diff_on and has_proper_commit_cache:
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 diff_commit_cache = \
(ancestor_commit, commit_cache, missing_requirements,
source_commit, target_commit) = cached_diff['commits']
else:
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299 # NOTE(marcink): we reach potentially unreachable errors when a PR has
# merge errors resulting in potentially hidden commits in the shadow repo.
maybe_unreachable = _merge_check.MERGE_CHECK in _merge_check.error_details \
and _merge_check.merge_response
maybe_unreachable = maybe_unreachable \
and _merge_check.merge_response.metadata.get('unresolved_files')
log.debug("Using unreachable commits due to MERGE_CHECK in merge simulation")
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 diff_commit_cache = \
(ancestor_commit, commit_cache, missing_requirements,
source_commit, target_commit) = self.get_commits(
commits_source_repo,
pull_request_at_ver,
source_commit,
source_ref_id,
source_scm,
target_commit,
target_ref_id,
pull-requests: fix way how pull-request calculates common ancestors....
r4346 target_scm,
fix(pull-requests): fixes for rendering comments
r5211 maybe_unreachable=maybe_unreachable)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685
# register our commit range
for comm in commit_cache.values():
c.commit_ranges.append(comm)
c.missing_requirements = missing_requirements
c.ancestor_commit = ancestor_commit
pull-requests: prepare the migration of pull request to pyramid....
r1813 c.statuses = source_repo.statuses(
[x.raw_id for x in c.commit_ranges])
# auto collapse if we have more than limit
collapse_limit = diffs.DiffProcessor._collapse_commits_over
c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
c.compare_mode = compare
# diff_limit is the old behavior, will cut off the whole diff
# if the limit is applied otherwise will just hide the
# big files from the front-end
diff_limit = c.visual.cut_off_limit_diff
file_limit = c.visual.cut_off_limit_file
c.missing_commits = False
if (c.missing_requirements
or isinstance(source_commit, EmptyCommit)
or source_commit == target_commit):
c.missing_commits = True
else:
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 c.inline_comments = display_inline_comments
pull-requests: prepare the migration of pull request to pyramid....
r1813
pull-requests: use proper diff calculation for versioning of PRs.
r4426 use_ancestor = True
if from_version_normalized != version_normalized:
use_ancestor = False
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 has_proper_diff_cache = cached_diff and cached_diff.get('commits')
if not force_recache and has_proper_diff_cache:
c.diffset = cached_diff['diff']
else:
commits: detect missing commits on diffsets from new PR ancestor logic....
r4400 try:
c.diffset = self._get_diffset(
c.source_repo.repo_name, commits_source_repo,
c.ancestor_commit,
source_ref_id, target_ref_id,
target_commit, source_commit,
diff_limit, file_limit, c.fulldiff,
release: Merge default into stable for release preparation
r4456 hide_whitespace_changes, diff_context,
use_ancestor=use_ancestor
pull-requests: overhaul of the UX by adding new sidebar...
r4482 )
pull-requests: allow to show range diff in pr view
r3124
# save cached diff
if caching_enabled:
commits: detect missing commits on diffsets from new PR ancestor logic....
r4400 cache_diff(cache_file_path, c.diffset, diff_commit_cache)
except CommitDoesNotExistError:
log.exception('Failed to generate diffset')
c.missing_commits = True
if not c.missing_commits:
c.limited_diff = c.diffset.limited_diff
# calculate removed files that are bound to comments
comment_deleted_files = [
fname for fname in display_inline_comments
if fname not in c.diffset.file_stats]
c.deleted_files_comments = collections.defaultdict(dict)
for fname, per_line_comments in display_inline_comments.items():
if fname in comment_deleted_files:
c.deleted_files_comments[fname]['stats'] = 0
c.deleted_files_comments[fname]['comments'] = list()
for lno, comments in per_line_comments.items():
c.deleted_files_comments[fname]['comments'].extend(comments)
# maybe calculate the range diff
if c.range_diff_on:
# TODO(marcink): set whitespace/context
context_lcl = 3
ign_whitespace_lcl = False
pull-requests: allow to show range diff in pr view
r3124
commits: detect missing commits on diffsets from new PR ancestor logic....
r4400 for commit in c.commit_ranges:
commit2 = commit
commit1 = commit.first_parent
range_diff_cache_file_path = diff_cache_exist(
cache_path, 'diff', commit.raw_id,
ign_whitespace_lcl, context_lcl, c.fulldiff)
cached_diff = None
if caching_enabled:
cached_diff = load_cached_diff(range_diff_cache_file_path)
has_proper_diff_cache = cached_diff and cached_diff.get('diff')
if not force_recache and has_proper_diff_cache:
diffset = cached_diff['diff']
else:
diffset = self._get_range_diffset(
commits_source_repo, source_repo,
commit1, commit2, diff_limit, file_limit,
c.fulldiff, ign_whitespace_lcl, context_lcl
)
# save cached diff
if caching_enabled:
cache_diff(range_diff_cache_file_path, diffset, None)
c.changes[commit.raw_id] = diffset
pull-requests: prepare the migration of pull request to pyramid....
r1813
# this is a hack to properly display links, when creating PR, the
# compare view and others uses different notation, and
# compare_commits.mako renders links based on the target_repo.
# We need to swap that here to generate it properly on the html side
c.target_repo = c.source_repo
c.commit_statuses = ChangesetStatus.STATUSES
c.show_version_changes = not pr_closed
if c.show_version_changes:
cur_obj = pull_request_at_ver
prev_obj = prev_pull_request_at_ver
old_commit_ids = prev_obj.revisions
new_commit_ids = cur_obj.revisions
commit_changes = PullRequestModel()._calculate_commit_id_changes(
old_commit_ids, new_commit_ids)
c.commit_changes_summary = commit_changes
# calculate the diff for commits between versions
c.commit_changes = []
pull-requests: fix way how pull-request calculates common ancestors....
r4346
def mark(cs, fw):
python3: fixed various code issues...
r4973 return list(h.itertools.zip_longest([], cs, fillvalue=fw))
pull-requests: fix way how pull-request calculates common ancestors....
r4346
pull-requests: prepare the migration of pull request to pyramid....
r1813 for c_type, raw_id in mark(commit_changes.added, 'a') \
+ mark(commit_changes.removed, 'r') \
+ mark(commit_changes.common, 'c'):
if raw_id in commit_cache:
commit = commit_cache[raw_id]
else:
try:
commit = commits_source_repo.get_commit(raw_id)
except CommitDoesNotExistError:
fix(pull-requests): fixes for rendering comments
r5211 # in case we fail getting the commit, still use a dummy commit
pull-requests: prepare the migration of pull request to pyramid....
r1813 # for display in commit diff
commit = h.AttributeDict(
{'raw_id': raw_id,
'message': 'EMPTY or MISSING COMMIT'})
c.commit_changes.append([c_type, commit])
# current user review statuses for each version
c.review_versions = {}
pull-requests: only allow actual reviewers to leave status/votes....
r4513 is_reviewer = PullRequestModel().is_user_reviewer(
pull_request, self._rhodecode_user)
if is_reviewer:
pull-requests: prepare the migration of pull request to pyramid....
r1813 for co in general_comments:
if co.author.user_id == self._rhodecode_user.user_id:
status = co.status_change
if status:
_ver_pr = status[0].comment.pull_request_version_id
c.review_versions[_ver_pr] = status[0]
return self._get_template_context(c)
pull-requests: migrated code from pylons to pyramid
r1974
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 def get_commits(
self, commits_source_repo, pull_request_at_ver, source_commit,
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299 source_ref_id, source_scm, target_commit, target_ref_id, target_scm,
maybe_unreachable=False):
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 commit_cache = collections.OrderedDict()
missing_requirements = False
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 try:
vcs: optimized pre-load attributes for better caching.
r3850 pre_load = ["author", "date", "message", "branch", "parents"]
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299
pull_request_commits = pull_request_at_ver.revisions
log.debug('Loading %s commits from %s',
len(pull_request_commits), commits_source_repo)
for rev in pull_request_commits:
comm = commits_source_repo.get_commit(commit_id=rev, pre_load=pre_load,
maybe_unreachable=maybe_unreachable)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 commit_cache[comm.raw_id] = comm
# Order here matters, we first need to get target, and then
# the source
target_commit = commits_source_repo.get_commit(
commit_id=safe_str(target_ref_id))
source_commit = commits_source_repo.get_commit(
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299 commit_id=safe_str(source_ref_id), maybe_unreachable=True)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 except CommitDoesNotExistError:
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299 log.warning('Failed to get commit from `{}` repo'.format(
commits_source_repo), exc_info=True)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 except RepositoryRequirementError:
pull-requests: fixed case for GIT repositories when a merge check failed due to merge conflicts the pull request wrongly reported missing commits....
r4299 log.warning('Failed to get all required data from repo', exc_info=True)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 missing_requirements = True
pull-requests: fix way how pull-request calculates common ancestors....
r4346
pr_ancestor_id = pull_request_at_ver.common_ancestor_id
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 try:
pull-requests: fix way how pull-request calculates common ancestors....
r4346 ancestor_commit = source_scm.get_commit(pr_ancestor_id)
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 except Exception:
ancestor_commit = None
pull-requests: fix way how pull-request calculates common ancestors....
r4346
Bartłomiej Wołyńczyk
caching: add option to cache diffs for commits and pull requests....
r2685 return ancestor_commit, commit_cache, missing_requirements, source_commit, target_commit
pull-requests: migrated code from pylons to pyramid
r1974 def assure_not_empty_repo(self):
_ = self.request.translate
try:
self.db_repo.scm_instance().get_commit()
except EmptyRepositoryError:
h.flash(h.literal(_('There are no commits yet')),
category='warning')
raise HTTPFound(
h.route_path('repo_summary', repo_name=self.db_repo.repo_name))
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pull_request_new(self):
_ = self.request.translate
c = self.load_default_context()
self.assure_not_empty_repo()
source_repo = self.db_repo
commit_id = self.request.GET.get('commit')
branch_ref = self.request.GET.get('branch')
bookmark_ref = self.request.GET.get('bookmark')
try:
source_repo_data = PullRequestModel().generate_repo_data(
source_repo, commit_id=commit_id,
pull-requests: prevent from errors in generating a title in repositories which have...
r2494 branch=branch_ref, bookmark=bookmark_ref,
translator=self.request.translate)
pull-requests: migrated code from pylons to pyramid
r1974 except CommitDoesNotExistError as e:
log.exception(e)
h.flash(_('Commit does not exist'), 'error')
raise HTTPFound(
h.route_path('pullrequest_new', repo_name=source_repo.repo_name))
default_target_repo = source_repo
forks: don't expose fork link if we don't have permission to read it, and also don't pre-select in pull request.
r3367 if source_repo.parent and c.has_origin_repo_read_perm:
pull-requests: migrated code from pylons to pyramid
r1974 parent_vcs_obj = source_repo.parent.scm_instance()
if parent_vcs_obj and not parent_vcs_obj.is_empty():
# change default if we have a parent repo
default_target_repo = source_repo.parent
target_repo_data = PullRequestModel().generate_repo_data(
pull-requests: trigger merge simulation during PR creation. Fixes #5396
r2168 default_target_repo, translator=self.request.translate)
pull-requests: migrated code from pylons to pyramid
r1974
selected_source_ref = source_repo_data['refs']['selected_ref']
pull-requests: prevent from errors in generating a title in repositories which have...
r2494 title_source_ref = ''
if selected_source_ref:
title_source_ref = selected_source_ref.split(':', 2)[1]
pull-requests: migrated code from pylons to pyramid
r1974 c.default_title = PullRequestModel().generate_pullrequest_title(
source=source_repo.repo_name,
source_ref=title_source_ref,
target=default_target_repo.repo_name
)
c.default_repo_data = {
'source_repo_name': source_repo.repo_name,
json: fixed calls to json after orjson implementation
r4974 'source_refs_json': ext_json.str_json(source_repo_data),
pull-requests: migrated code from pylons to pyramid
r1974 'target_repo_name': default_target_repo.repo_name,
json: fixed calls to json after orjson implementation
r4974 'target_refs_json': ext_json.str_json(target_repo_data),
pull-requests: migrated code from pylons to pyramid
r1974 }
c.default_source_ref = selected_source_ref
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pull_request_repo_refs(self):
pylons: fixed code and test suite after removal of pylons.
r2358 self.load_default_context()
pull-requests: migrated code from pylons to pyramid
r1974 target_repo_name = self.request.matchdict['target_repo_name']
repo = Repository.get_by_repo_name(target_repo_name)
if not repo:
raise HTTPNotFound()
pull-requests: security, check for permissions on exposure of repo-refs
r2251
target_perm = HasRepoPermissionAny(
'repository.read', 'repository.write', 'repository.admin')(
target_repo_name)
if not target_perm:
raise HTTPNotFound()
pull-requests: security, prevent from injecting comments to other pull requests users...
r2181 return PullRequestModel().generate_repo_data(
repo, translator=self.request.translate)
pull-requests: migrated code from pylons to pyramid
r1974
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 def pullrequest_repo_targets(self):
pull-requests: migrated code from pylons to pyramid
r1974 _ = self.request.translate
filter_query = self.request.GET.get('query')
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 # get the parents
parent_target_repos = []
if self.db_repo.parent:
parents_query = Repository.query() \
.order_by(func.length(Repository.repo_name)) \
.filter(Repository.fork_id == self.db_repo.parent.repo_id)
if filter_query:
apps: modernize for python3
r5093 ilike_expression = f'%{safe_str(filter_query)}%'
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 parents_query = parents_query.filter(
Repository.repo_name.ilike(ilike_expression))
parents = parents_query.limit(20).all()
for parent in parents:
parent_vcs_obj = parent.scm_instance()
if parent_vcs_obj and not parent_vcs_obj.is_empty():
parent_target_repos.append(parent)
# get other forks, and repo itself
pull-requests: migrated code from pylons to pyramid
r1974 query = Repository.query() \
.order_by(func.length(Repository.repo_name)) \
.filter(
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 or_(Repository.repo_id == self.db_repo.repo_id, # repo itself
Repository.fork_id == self.db_repo.repo_id) # forks of this repo
) \
.filter(~Repository.repo_id.in_([x.repo_id for x in parent_target_repos]))
pull-requests: migrated code from pylons to pyramid
r1974
if filter_query:
apps: modernize for python3
r5093 ilike_expression = f'%{safe_str(filter_query)}%'
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 query = query.filter(Repository.repo_name.ilike(ilike_expression))
pull-requests: migrated code from pylons to pyramid
r1974
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 limit = max(20 - len(parent_target_repos), 5) # not less then 5
target_repos = query.limit(limit).all()
pull-requests: migrated code from pylons to pyramid
r1974
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 all_target_repos = target_repos + parent_target_repos
pull-requests: migrated code from pylons to pyramid
r1974
repos = []
forks: don't expose fork link if we don't have permission to read it, and also don't pre-select in pull request.
r3367 # This checks permissions to the repositories
pull-requests: allow having repo targets all forks and parent forks of target....
r3330 for obj in ScmModel().get_repos(all_target_repos):
pull-requests: migrated code from pylons to pyramid
r1974 repos.append({
'id': obj['name'],
'text': obj['name'],
'type': 'repo',
repo-switcher: new unified search box for filtering/accessing users, repos and repo groups....
r2774 'repo_id': obj['dbrepo']['repo_id'],
'repo_type': obj['dbrepo']['repo_type'],
'private': obj['dbrepo']['private'],
pull-requests: migrated code from pylons to pyramid
r1974 })
data = {
'more': False,
'results': [{
'text': _('Repositories'),
'children': repos
}] if repos else []
}
return data
comments: multiple changes on comments navigation/display logic...
r4543 @classmethod
def get_comment_ids(cls, post_data):
return filter(lambda e: e > 0, map(safe_int, aslist(post_data.get('comments'), ',')))
comments: fix existing ids discovery
r4501
pull-requests: migrated code from pylons to pyramid
r1974 @LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
pull-requests: overhaul of the UX by adding new sidebar...
r4482 def pullrequest_comments(self):
self.load_default_context()
pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull_request_id = pull_request.pull_request_id
version = self.request.GET.get('version')
_render = self.request.get_partial_renderer(
commits/pr pages various fixes....
r4485 'rhodecode:templates/base/sidebar.mako')
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c = _render.get_call_context()
(pull_request_latest,
pull_request_at_ver,
pull_request_display_obj,
at_version) = PullRequestModel().get_pr_version(
pull_request_id, version=version)
versions = pull_request_display_obj.versions()
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
c.versions = versions + [latest_ver]
c.at_version = at_version
c.at_version_num = (at_version
if at_version and at_version != PullRequest.LATEST_VER
else None)
comments: introduce new draft comments....
r4540 self.register_comments_vars(c, pull_request_latest, versions, include_drafts=False)
pull-requests: overhaul of the UX by adding new sidebar...
r4482 all_comments = c.inline_comments_flat + c.comments
commits/pr pages various fixes....
r4485
comments: multiple changes on comments navigation/display logic...
r4543 existing_ids = self.get_comment_ids(self.request.POST)
commits/pr pages various fixes....
r4485 return _render('comments_table', all_comments, len(all_comments),
existing_ids=existing_ids)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def pullrequest_todos(self):
self.load_default_context()
pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull_request_id = pull_request.pull_request_id
version = self.request.GET.get('version')
_render = self.request.get_partial_renderer(
commits/pr pages various fixes....
r4485 'rhodecode:templates/base/sidebar.mako')
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c = _render.get_call_context()
(pull_request_latest,
pull_request_at_ver,
pull_request_display_obj,
at_version) = PullRequestModel().get_pr_version(
pull_request_id, version=version)
versions = pull_request_display_obj.versions()
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
c.versions = versions + [latest_ver]
c.at_version = at_version
c.at_version_num = (at_version
if at_version and at_version != PullRequest.LATEST_VER
else None)
c.unresolved_comments = CommentsModel() \
comments: introduce new draft comments....
r4540 .get_pull_request_unresolved_todos(pull_request, include_drafts=False)
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c.resolved_comments = CommentsModel() \
comments: introduce new draft comments....
r4540 .get_pull_request_resolved_todos(pull_request, include_drafts=False)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
all_comments = c.unresolved_comments + c.resolved_comments
comments: multiple changes on comments navigation/display logic...
r4543 existing_ids = self.get_comment_ids(self.request.POST)
commits/pr pages various fixes....
r4485 return _render('comments_table', all_comments, len(c.unresolved_comments),
todo_comments=True, existing_ids=existing_ids)
pull-requests: overhaul of the UX by adding new sidebar...
r4482
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
drafts: sidebar functionality
r4562 def pullrequest_drafts(self):
self.load_default_context()
pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull_request_id = pull_request.pull_request_id
version = self.request.GET.get('version')
_render = self.request.get_partial_renderer(
'rhodecode:templates/base/sidebar.mako')
c = _render.get_call_context()
(pull_request_latest,
pull_request_at_ver,
pull_request_display_obj,
at_version) = PullRequestModel().get_pr_version(
pull_request_id, version=version)
versions = pull_request_display_obj.versions()
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
c.versions = versions + [latest_ver]
c.at_version = at_version
c.at_version_num = (at_version
if at_version and at_version != PullRequest.LATEST_VER
else None)
c.draft_comments = CommentsModel() \
.get_pull_request_drafts(self._rhodecode_db_user.user_id, pull_request)
all_comments = c.draft_comments
existing_ids = self.get_comment_ids(self.request.POST)
return _render('comments_table', all_comments, len(all_comments),
existing_ids=existing_ids, draft_comments=True)
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
pull-requests: migrated code from pylons to pyramid
r1974 @CSRFRequired()
def pull_request_create(self):
_ = self.request.translate
self.assure_not_empty_repo()
pylons: fixed code and test suite after removal of pylons.
r2358 self.load_default_context()
pull-requests: migrated code from pylons to pyramid
r1974
controls = peppercorn.parse(self.request.POST.items())
try:
pylons: remove pylons as dependency...
r2351 form = PullRequestForm(
self.request.translate, self.db_repo.repo_id)()
_form = form.to_python(controls)
pull-requests: migrated code from pylons to pyramid
r1974 except formencode.Invalid as errors:
if errors.error_dict.get('revisions'):
core: multiple fixes to unicode vs str usage...
r5065 msg = 'Revisions: {}'.format(errors.error_dict['revisions'])
pull-requests: migrated code from pylons to pyramid
r1974 elif errors.error_dict.get('pullrequest_title'):
pull-requests: use proper validation of pull request title to prevent from bad errors.
r2479 msg = errors.error_dict.get('pullrequest_title')
pull-requests: migrated code from pylons to pyramid
r1974 else:
msg = _('Error creating pull request: {}').format(errors)
log.exception(msg)
h.flash(msg, 'error')
# would rather just go back to form ...
raise HTTPFound(
h.route_path('pullrequest_new', repo_name=self.db_repo_name))
source_repo = _form['source_repo']
source_ref = _form['source_ref']
target_repo = _form['target_repo']
target_ref = _form['target_ref']
commit_ids = _form['revisions'][::-1]
pull-requests: fix way how pull-request calculates common ancestors....
r4346 common_ancestor_id = _form['common_ancestor']
pull-requests: migrated code from pylons to pyramid
r1974
# find the ancestor for this pr
source_db_repo = Repository.get_by_repo_name(_form['source_repo'])
target_db_repo = Repository.get_by_repo_name(_form['target_repo'])
pull-requests: introduce operation state for pull requests to prevent from...
r3371 if not (source_db_repo or target_db_repo):
h.flash(_('source_repo or target repo not found'), category='error')
raise HTTPFound(
h.route_path('pullrequest_new', repo_name=self.db_repo_name))
pull-requests: security double check permissions on injected forms of source and target repositories.
r2177 # re-check permissions again here
# source_repo we must have read permissions
source_perm = HasRepoPermissionAny(
pull-requests: introduce operation state for pull requests to prevent from...
r3371 'repository.read', 'repository.write', 'repository.admin')(
source_db_repo.repo_name)
pull-requests: security double check permissions on injected forms of source and target repositories.
r2177 if not source_perm:
msg = _('Not Enough permissions to source repo `{}`.'.format(
source_db_repo.repo_name))
h.flash(msg, category='error')
# copy the args back to redirect
org_query = self.request.GET.mixed()
raise HTTPFound(
h.route_path('pullrequest_new', repo_name=self.db_repo_name,
_query=org_query))
pull-requests: loosen permissions on creation of PR....
r2235 # target repo we must have read permissions, and also later on
pull-requests: security double check permissions on injected forms of source and target repositories.
r2177 # we want to check branch permissions here
target_perm = HasRepoPermissionAny(
pull-requests: introduce operation state for pull requests to prevent from...
r3371 'repository.read', 'repository.write', 'repository.admin')(
target_db_repo.repo_name)
pull-requests: security double check permissions on injected forms of source and target repositories.
r2177 if not target_perm:
msg = _('Not Enough permissions to target repo `{}`.'.format(
target_db_repo.repo_name))
h.flash(msg, category='error')
# copy the args back to redirect
org_query = self.request.GET.mixed()
raise HTTPFound(
h.route_path('pullrequest_new', repo_name=self.db_repo_name,
_query=org_query))
pull-requests: migrated code from pylons to pyramid
r1974 source_scm = source_db_repo.scm_instance()
target_scm = target_db_repo.scm_instance()
observers: code cleanups and fixed tests.
r4519 source_ref_obj = unicode_to_reference(source_ref)
target_ref_obj = unicode_to_reference(target_ref)
source_commit = source_scm.get_commit(source_ref_obj.commit_id)
target_commit = target_scm.get_commit(target_ref_obj.commit_id)
pull-requests: migrated code from pylons to pyramid
r1974
ancestor = source_scm.get_common_ancestor(
source_commit.raw_id, target_commit.raw_id, target_scm)
pull-requests: refactor model for code readability.
r2872 # recalculate target ref based on ancestor
observers: code cleanups and fixed tests.
r4519 target_ref = ':'.join((target_ref_obj.type, target_ref_obj.name, ancestor))
pull-requests: migrated code from pylons to pyramid
r1974
reviewers: added observers as another way to define reviewers....
r4500 get_default_reviewers_data, validate_default_reviewers, validate_observers = \
pull-requests: refactor model for code readability.
r2872 PullRequestModel().get_reviewer_functions()
# recalculate reviewers logic, to make sure we can validate this
reviewer_rules = get_default_reviewers_data(
pull-requests: limit the ammount of data saved in default reviewers data for better memory usage...
r4509 self._rhodecode_db_user,
source_db_repo,
observers: code cleanups and fixed tests.
r4519 source_ref_obj,
pull-requests: limit the ammount of data saved in default reviewers data for better memory usage...
r4509 target_db_repo,
observers: code cleanups and fixed tests.
r4519 target_ref_obj,
pull-requests: limit the ammount of data saved in default reviewers data for better memory usage...
r4509 include_diff_info=False)
pull-requests: refactor model for code readability.
r2872
reviewers: added observers as another way to define reviewers....
r4500 reviewers = validate_default_reviewers(_form['review_members'], reviewer_rules)
observers = validate_observers(_form['observer_members'], reviewer_rules)
pull-requests: refactor model for code readability.
r2872
pull-requests: migrated code from pylons to pyramid
r1974 pullrequest_title = _form['pullrequest_title']
observers: code cleanups and fixed tests.
r4519 title_source_ref = source_ref_obj.name
pull-requests: migrated code from pylons to pyramid
r1974 if not pullrequest_title:
pullrequest_title = PullRequestModel().generate_pullrequest_title(
source=source_repo,
source_ref=title_source_ref,
target=target_repo
)
description = _form['pullrequest_desc']
pull-requests: make the renderer stored and saved for each pull requests....
r2903 description_renderer = _form['description_renderer']
pull-requests: migrated code from pylons to pyramid
r1974
try:
pull_request = PullRequestModel().create(
pull-requests: refactor model for code readability.
r2872 created_by=self._rhodecode_user.user_id,
source_repo=source_repo,
source_ref=source_ref,
target_repo=target_repo,
target_ref=target_ref,
revisions=commit_ids,
pull-requests: fix way how pull-request calculates common ancestors....
r4346 common_ancestor_id=common_ancestor_id,
pull-requests: refactor model for code readability.
r2872 reviewers=reviewers,
reviewers: added observers as another way to define reviewers....
r4500 observers=observers,
pull-requests: refactor model for code readability.
r2872 title=pullrequest_title,
description=description,
pull-requests: make the renderer stored and saved for each pull requests....
r2903 description_renderer=description_renderer,
pull-requests: refactor model for code readability.
r2872 reviewer_data=reviewer_rules,
audit-logs: use auth_user in few places to track action IP.
r2788 auth_user=self._rhodecode_user
pull-requests: migrated code from pylons to pyramid
r1974 )
Session().commit()
pull-requests: trigger merge simulation during PR creation. Fixes #5396
r2168
pull-requests: migrated code from pylons to pyramid
r1974 h.flash(_('Successfully opened new pull request'),
category='success')
pull-requests: in case of an error redirect to the same url as source....
r2052 except Exception:
pull-requests: migrated code from pylons to pyramid
r1974 msg = _('Error occurred during creation of this pull request.')
log.exception(msg)
h.flash(msg, category='error')
pull-requests: in case of an error redirect to the same url as source....
r2052
# copy the args back to redirect
org_query = self.request.GET.mixed()
pull-requests: migrated code from pylons to pyramid
r1974 raise HTTPFound(
pull-requests: in case of an error redirect to the same url as source....
r2052 h.route_path('pullrequest_new', repo_name=self.db_repo_name,
_query=org_query))
pull-requests: migrated code from pylons to pyramid
r1974
raise HTTPFound(
h.route_path('pullrequest_show', repo_name=target_repo,
pull_request_id=pull_request.pull_request_id))
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_update(self):
pull-request: code cleanup...
r1979 pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull-requests: forbid doing any changes on closed pull-requests....
r2383 _ = self.request.translate
pull-requests: migrated code from pylons to pyramid
r1974
pull-requests: overhaul of the UX by adding new sidebar...
r4482 c = self.load_default_context()
pull-requests: moved force refresh to update commits button....
r4101 redirect_url = None
pull-requests: updated use lower retry, and cleanup some code
r4711 # we do this check as first, because we want to know ASAP in the flow that
# pr is updating currently
is_state_changing = pull_request.is_state_changing()
pull-requests: forbid doing any changes on closed pull-requests....
r2383
if pull_request.is_closed():
log.debug('update: forbidden because pull request is closed')
apps: modernize for python3
r5093 msg = _('Cannot update closed pull requests.')
pull-requests: forbid doing any changes on closed pull-requests....
r2383 h.flash(msg, category='error')
pull-requests: moved force refresh to update commits button....
r4101 return {'response': True,
'redirect_url': redirect_url}
pull-requests: migrated code from pylons to pyramid
r1974
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505 c.pr_broadcast_channel = channelstream.pr_channel(pull_request)
pull-requests: introduce operation state for pull requests to prevent from...
r3371
pull-requests: migrated code from pylons to pyramid
r1974 # only owner or admin can update it
allowed_to_update = PullRequestModel().check_user_update(
pull_request, self._rhodecode_user)
reviewers: added observers as another way to define reviewers....
r4500
pull-requests: migrated code from pylons to pyramid
r1974 if allowed_to_update:
controls = peppercorn.parse(self.request.POST.items())
pull-requests: updated use lower retry, and cleanup some code
r4711 force_refresh = str2bool(self.request.POST.get('force_refresh', 'false'))
do_update_commits = str2bool(self.request.POST.get('update_commits', 'false'))
pull-requests: migrated code from pylons to pyramid
r1974
if 'review_members' in controls:
self._update_reviewers(
reviewers: added observers as another way to define reviewers....
r4500 c,
pull-request: code cleanup...
r1979 pull_request, controls['review_members'],
reviewers: added observers as another way to define reviewers....
r4500 pull_request.reviewer_data,
PullRequestReviewers.ROLE_REVIEWER)
elif 'observer_members' in controls:
self._update_reviewers(
c,
pull_request, controls['observer_members'],
pull_request.reviewer_data,
PullRequestReviewers.ROLE_OBSERVER)
pull-requests: updated use lower retry, and cleanup some code
r4711 elif do_update_commits:
pull-requests: loosen strict view of pull-requests that state is changing...
r4103 if is_state_changing:
log.debug('commits update: forbidden because pull request is in state %s',
pull_request.pull_request_state)
apps: modernize for python3
r5093 msg = _('Cannot update pull requests commits in state other than `{}`. '
'Current state is: `{}`').format(
pull-requests: loosen strict view of pull-requests that state is changing...
r4103 PullRequest.STATE_CREATED, pull_request.pull_request_state)
h.flash(msg, category='error')
return {'response': True,
'redirect_url': redirect_url}
pull-requests: overhaul of the UX by adding new sidebar...
r4482 self._update_commits(c, pull_request)
pull-requests: moved force refresh to update commits button....
r4101 if force_refresh:
redirect_url = h.route_path(
'pullrequest_show', repo_name=self.db_repo_name,
pull_request_id=pull_request.pull_request_id,
_query={"force_refresh": 1})
pull-requests: migrated code from pylons to pyramid
r1974 elif str2bool(self.request.POST.get('edit_pull_request', 'false')):
self._edit_pull_request(pull_request)
else:
reviewers: added observers as another way to define reviewers....
r4500 log.error('Unhandled update data.')
pull-requests: migrated code from pylons to pyramid
r1974 raise HTTPBadRequest()
pull-requests: moved force refresh to update commits button....
r4101
return {'response': True,
'redirect_url': redirect_url}
pull-requests: migrated code from pylons to pyramid
r1974 raise HTTPForbidden()
def _edit_pull_request(self, pull_request):
reviewers: added observers as another way to define reviewers....
r4500 """
Edit title and description
"""
pull-requests: migrated code from pylons to pyramid
r1974 _ = self.request.translate
pull-requests: make the renderer stored and saved for each pull requests....
r2903
pull-requests: migrated code from pylons to pyramid
r1974 try:
PullRequestModel().edit(
pull-requests: make the renderer stored and saved for each pull requests....
r2903 pull_request,
self.request.POST.get('title'),
self.request.POST.get('description'),
self.request.POST.get('description_renderer'),
self._rhodecode_user)
pull-requests: migrated code from pylons to pyramid
r1974 except ValueError:
apps: modernize for python3
r5093 msg = _('Cannot update closed pull requests.')
pull-requests: migrated code from pylons to pyramid
r1974 h.flash(msg, category='error')
return
else:
Session().commit()
apps: modernize for python3
r5093 msg = _('Pull request title & description updated.')
pull-requests: migrated code from pylons to pyramid
r1974 h.flash(msg, category='success')
return
pull-requests: overhaul of the UX by adding new sidebar...
r4482 def _update_commits(self, c, pull_request):
pull-requests: migrated code from pylons to pyramid
r1974 _ = self.request.translate
pull-requests: updated use lower retry, and cleanup some code
r4711 log.debug('pull-request: running update commits actions')
pull-requests: introduce operation state for pull requests to prevent from...
r3371
pull-requests: updated use lower retry, and cleanup some code
r4711 @retry(exception=Exception, n_tries=3, delay=2)
pull-requests: added retry mechanism for updating pull requests.
r4696 def commits_update():
return PullRequestModel().update_commits(
pull_request, self._rhodecode_db_user)
pull-requests: introduce operation state for pull requests to prevent from...
r3371 with pull_request.set_state(PullRequest.STATE_UPDATING):
pull-requests: added retry mechanism for updating pull requests.
r4696 resp = commits_update() # retry x3
pull-requests: migrated code from pylons to pyramid
r1974
if resp.executed:
if resp.target_changed and resp.source_changed:
changed = 'target and source repositories'
elif resp.target_changed and not resp.source_changed:
changed = 'target repository'
elif not resp.target_changed and resp.source_changed:
changed = 'source repository'
else:
changed = 'nothing'
apps: modernize for python3
r5093 msg = _('Pull request updated to "{source_commit_id}" with '
'{count_added} added, {count_removed} removed commits. '
'Source of changes: {change_source}.')
pull-requests: migrated code from pylons to pyramid
r1974 msg = msg.format(
source_commit_id=pull_request.source_ref_parts.commit_id,
count_added=len(resp.changes.added),
count_removed=len(resp.changes.removed),
change_source=changed)
h.flash(msg, category='success')
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505 channelstream.pr_update_channelstream_push(
self.request, c.pr_broadcast_channel, self._rhodecode_user, msg)
pull-requests: migrated code from pylons to pyramid
r1974 else:
msg = PullRequestModel.UPDATE_STATUS_MESSAGES[resp.reason]
warning_reasons = [
UpdateFailureReason.NO_CHANGE,
UpdateFailureReason.WRONG_REF_TYPE,
]
category = 'warning' if resp.reason in warning_reasons else 'error'
h.flash(msg, category=category)
reviewers: added observers as another way to define reviewers....
r4500 def _update_reviewers(self, c, pull_request, review_members, reviewer_rules, role):
_ = self.request.translate
get_default_reviewers_data, validate_default_reviewers, validate_observers = \
PullRequestModel().get_reviewer_functions()
if role == PullRequestReviewers.ROLE_REVIEWER:
try:
reviewers = validate_default_reviewers(review_members, reviewer_rules)
except ValueError as e:
apps: modernize for python3
r5093 log.error(f'Reviewers Validation: {e}')
reviewers: added observers as another way to define reviewers....
r4500 h.flash(e, category='error')
return
old_calculated_status = pull_request.calculated_review_status()
PullRequestModel().update_reviewers(
observers: code cleanups and fixed tests.
r4519 pull_request, reviewers, self._rhodecode_db_user)
reviewers: added observers as another way to define reviewers....
r4500
Session().commit()
msg = _('Pull request reviewers updated.')
h.flash(msg, category='success')
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505 channelstream.pr_update_channelstream_push(
self.request, c.pr_broadcast_channel, self._rhodecode_user, msg)
reviewers: added observers as another way to define reviewers....
r4500
# trigger status changed if change in reviewers changes the status
calculated_status = pull_request.calculated_review_status()
if old_calculated_status != calculated_status:
PullRequestModel().trigger_pull_request_hook(
pull_request, self._rhodecode_user, 'review_status_change',
data={'status': calculated_status})
elif role == PullRequestReviewers.ROLE_OBSERVER:
try:
observers = validate_observers(review_members, reviewer_rules)
except ValueError as e:
apps: modernize for python3
r5093 log.error(f'Observers Validation: {e}')
reviewers: added observers as another way to define reviewers....
r4500 h.flash(e, category='error')
return
PullRequestModel().update_observers(
observers: code cleanups and fixed tests.
r4519 pull_request, observers, self._rhodecode_db_user)
reviewers: added observers as another way to define reviewers....
r4500
Session().commit()
msg = _('Pull request observers updated.')
h.flash(msg, category='success')
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505 channelstream.pr_update_channelstream_push(
self.request, c.pr_broadcast_channel, self._rhodecode_user, msg)
reviewers: added observers as another way to define reviewers....
r4500
pull-requests: migrated code from pylons to pyramid
r1974 @LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_merge(self):
"""
Merge will perform a server-side merge of the specified
pull request, if the pull request is approved and mergeable.
After successful merging, the pull request is automatically
closed, with a relevant comment.
"""
pull-request: code cleanup...
r1979 pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull-requests: introduce operation state for pull requests to prevent from...
r3371 _ = self.request.translate
pull-requests: loosen strict view of pull-requests that state is changing...
r4103 if pull_request.is_state_changing():
pull-requests: introduce operation state for pull requests to prevent from...
r3371 log.debug('show: forbidden because pull request is in state %s',
pull_request.pull_request_state)
apps: modernize for python3
r5093 msg = _('Cannot merge pull requests in state other than `{}`. '
'Current state is: `{}`').format(PullRequest.STATE_CREATED,
pull-requests: introduce operation state for pull requests to prevent from...
r3371 pull_request.pull_request_state)
h.flash(msg, category='error')
raise HTTPFound(
h.route_path('pullrequest_show',
repo_name=pull_request.target_repo.repo_name,
pull_request_id=pull_request.pull_request_id))
pull-requests: migrated code from pylons to pyramid
r1974
pylons: fixed code and test suite after removal of pylons.
r2358 self.load_default_context()
pull-requests: introduce operation state for pull requests to prevent from...
r3371
with pull_request.set_state(PullRequest.STATE_UPDATING):
check = MergeCheck.validate(
pull_request, auth_user=self._rhodecode_user,
translator=self.request.translate)
pull-requests: migrated code from pylons to pyramid
r1974 merge_possible = not check.failed
for err_type, error_msg in check.errors:
h.flash(error_msg, category=err_type)
if merge_possible:
log.debug("Pre-conditions checked, trying to merge.")
extras = vcs_operation_context(
self.request.environ, repo_name=pull_request.target_repo.repo_name,
username=self._rhodecode_db_user.username, action='push',
scm=pull_request.target_repo.repo_type)
pull-requests: introduce operation state for pull requests to prevent from...
r3371 with pull_request.set_state(PullRequest.STATE_UPDATING):
self._merge_pull_request(
pull_request, self._rhodecode_db_user, extras)
pull-requests: migrated code from pylons to pyramid
r1974 else:
log.debug("Pre-conditions failed, NOT merging.")
raise HTTPFound(
h.route_path('pullrequest_show',
repo_name=pull_request.target_repo.repo_name,
pull_request_id=pull_request.pull_request_id))
def _merge_pull_request(self, pull_request, user, extras):
_ = self.request.translate
shadow-repos: use numeric repo id for creation of shadow repos....
r2810 merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras)
pull-requests: migrated code from pylons to pyramid
r1974
if merge_resp.executed:
log.debug("The merge was successful, closing the pull request.")
PullRequestModel().close_pull_request(
pull_request.pull_request_id, user)
Session().commit()
msg = _('Pull request was successfully merged and closed.')
h.flash(msg, category='success')
else:
log.debug(
dan
pull-requests: ensure merge response provide more details...
r3339 "The merge was not successful. Merge response: %s", merge_resp)
msg = merge_resp.merge_status_message
pull-requests: migrated code from pylons to pyramid
r1974 h.flash(msg, category='error')
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_delete(self):
_ = self.request.translate
pull-request: code cleanup...
r1979 pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pylons: fixed code and test suite after removal of pylons.
r2358 self.load_default_context()
pull-requests: migrated code from pylons to pyramid
r1974
pr_closed = pull_request.is_closed()
allowed_to_delete = PullRequestModel().check_user_delete(
pull_request, self._rhodecode_user) and not pr_closed
# only owner can delete it !
if allowed_to_delete:
PullRequestModel().delete(pull_request, self._rhodecode_user)
Session().commit()
h.flash(_('Successfully deleted pull request'),
category='success')
pull-requests: redirect to repo PR after delete instead of my account.
r2051 raise HTTPFound(h.route_path('pullrequest_show_all',
repo_name=self.db_repo_name))
pull-requests: migrated code from pylons to pyramid
r1974
log.warning('user %s tried to delete pull request without access',
self._rhodecode_user)
raise HTTPNotFound()
comments: multiple changes on comments navigation/display logic...
r4543 def _pull_request_comments_create(self, pull_request, comments):
_ = self.request.translate
data = {}
if not comments:
return
drafts: support draft in commits view...
r4555 pull_request_id = pull_request.pull_request_id
comments: multiple changes on comments navigation/display logic...
r4543
all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments)
for entry in comments:
c = self.load_default_context()
comment_type = entry['comment_type']
text = entry['text']
status = entry['status']
is_draft = str2bool(entry['is_draft'])
resolves_comment_id = entry['resolves_comment_id']
close_pull_request = entry['close_pull_request']
f_path = entry['f_path']
line_no = entry['line']
apps: modernize for python3
r5093 target_elem_id = f'file-{h.safeid(h.safe_str(f_path))}'
comments: multiple changes on comments navigation/display logic...
r4543
# the logic here should work like following, if we submit close
# pr comment, use `close_pull_request_with_comment` function
# else handle regular comment logic
if close_pull_request:
# only owner or admin or person with write permissions
allowed_to_close = PullRequestModel().check_user_update(
pull_request, self._rhodecode_user)
if not allowed_to_close:
log.debug('comment: forbidden because not allowed to close '
'pull request %s', pull_request_id)
raise HTTPForbidden()
# This also triggers `review_status_change`
comment, status = PullRequestModel().close_pull_request_with_comment(
pull_request, self._rhodecode_user, self.db_repo, message=text,
auth_user=self._rhodecode_user)
Session().flush()
is_inline = comment.is_inline
PullRequestModel().trigger_pull_request_hook(
pull_request, self._rhodecode_user, 'comment',
data={'comment': comment})
else:
# regular comment case, could be inline, or one with status.
# for that one we check also permissions
# Additionally ENSURE if somehow draft is sent we're then unable to change status
allowed_to_change_status = PullRequestModel().check_user_change_status(
pull_request, self._rhodecode_user) and not is_draft
if status and allowed_to_change_status:
message = (_('Status change %(transition_icon)s %(status)s')
% {'transition_icon': '>',
'status': ChangesetStatus.get_status_lbl(status)})
text = text or message
comment = CommentsModel().create(
text=text,
repo=self.db_repo.repo_id,
user=self._rhodecode_user.user_id,
pull_request=pull_request,
f_path=f_path,
line_no=line_no,
status_change=(ChangesetStatus.get_status_lbl(status)
if status and allowed_to_change_status else None),
status_change_type=(status
if status and allowed_to_change_status else None),
comment_type=comment_type,
is_draft=is_draft,
resolves_comment_id=resolves_comment_id,
auth_user=self._rhodecode_user,
send_email=not is_draft, # skip notification for draft comments
)
is_inline = comment.is_inline
if allowed_to_change_status:
# calculate old status before we change it
old_calculated_status = pull_request.calculated_review_status()
# get status if set !
if status:
ChangesetStatusModel().set_status(
self.db_repo.repo_id,
status,
self._rhodecode_user.user_id,
comment,
pull_request=pull_request
)
Session().flush()
# this is somehow required to get access to some relationship
# loaded on comment
Session().refresh(comment)
drafts: support draft in commits view...
r4555 # skip notifications for drafts
if not is_draft:
PullRequestModel().trigger_pull_request_hook(
pull_request, self._rhodecode_user, 'comment',
data={'comment': comment})
comments: multiple changes on comments navigation/display logic...
r4543
# we now calculate the status of pull request, and based on that
# calculation we set the commits status
calculated_status = pull_request.calculated_review_status()
if old_calculated_status != calculated_status:
PullRequestModel().trigger_pull_request_hook(
pull_request, self._rhodecode_user, 'review_status_change',
data={'status': calculated_status})
comment_id = comment.comment_id
data[comment_id] = {
'target_id': target_elem_id
}
Session().flush()
c.co = comment
c.at_version_num = None
c.is_new = True
rendered_comment = render(
'rhodecode:templates/changeset/changeset_comment_block.mako',
self._get_template_context(c), self.request)
data[comment_id].update(comment.get_dict())
data[comment_id].update({'rendered_text': rendered_comment})
Session().commit()
# skip channelstream for draft comments
drafts: support draft in commits view...
r4555 if not all_drafts:
comments: multiple changes on comments navigation/display logic...
r4543 comment_broadcast_channel = channelstream.comment_channel(
self.db_repo_name, pull_request_obj=pull_request)
comment_data = data
drafts: support draft in commits view...
r4555 posted_comment_type = 'inline' if is_inline else 'general'
comments: multiple changes on comments navigation/display logic...
r4543 if len(data) == 1:
drafts: support draft in commits view...
r4555 msg = _('posted {} new {} comment').format(len(data), posted_comment_type)
comments: multiple changes on comments navigation/display logic...
r4543 else:
drafts: support draft in commits view...
r4555 msg = _('posted {} new {} comments').format(len(data), posted_comment_type)
comments: multiple changes on comments navigation/display logic...
r4543
channelstream.comment_channelstream_push(
self.request, comment_broadcast_channel, self._rhodecode_user, msg,
comment_data=comment_data)
return data
pull-requests: migrated code from pylons to pyramid
r1974 @LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_comment_create(self):
_ = self.request.translate
pull-request: code cleanup...
r1979
comments: multiple changes on comments navigation/display logic...
r4543 pull_request = PullRequest.get_or_404(self.request.matchdict['pull_request_id'])
pull-request: code cleanup...
r1979
pull-requests: migrated code from pylons to pyramid
r1974 if pull_request.is_closed():
log.debug('comment: forbidden because pull request is closed')
raise HTTPForbidden()
pull-requests: security, prevent from injecting comments to other pull requests users...
r2181 allowed_to_comment = PullRequestModel().check_user_comment(
pull_request, self._rhodecode_user)
if not allowed_to_comment:
reviewers: added observers as another way to define reviewers....
r4500 log.debug('comment: forbidden because pull request is from forbidden repo')
pull-requests: security, prevent from injecting comments to other pull requests users...
r2181 raise HTTPForbidden()
comments: multiple changes on comments navigation/display logic...
r4543 comment_data = {
'comment_type': self.request.POST.get('comment_type'),
'text': self.request.POST.get('text'),
'status': self.request.POST.get('changeset_status', None),
'is_draft': self.request.POST.get('draft'),
'resolves_comment_id': self.request.POST.get('resolves_comment_id', None),
'close_pull_request': self.request.POST.get('close_pull_request'),
'f_path': self.request.POST.get('f_path'),
'line': self.request.POST.get('line'),
pull-requests: migrated code from pylons to pyramid
r1974 }
fix(pull-requests): fixes for rendering comments
r5211
comments: multiple changes on comments navigation/display logic...
r4543 data = self._pull_request_comments_create(pull_request, [comment_data])
channelstream: cleanup, and re-organize code for posting comments/pr updated messages....
r4505
pull-requests: migrated code from pylons to pyramid
r1974 return data
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_comment_delete(self):
pull-request: code cleanup...
r1979 pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id'])
pull-requests: migrated code from pylons to pyramid
r1974
pull-request: code cleanup...
r1979 comment = ChangesetComment.get_or_404(
self.request.matchdict['comment_id'])
comment_id = comment.comment_id
comments: added immutable parameter to forbid editing/deleting certain comments
r4327 if comment.immutable:
# don't allow deleting comments that are immutable
raise HTTPForbidden()
pull-requests: migrated code from pylons to pyramid
r1974 if pull_request.is_closed():
log.debug('comment: forbidden because pull request is closed')
raise HTTPForbidden()
if not comment:
log.debug('Comment with id:%s not found, skipping', comment_id)
# comment already deleted in another call probably
return True
if comment.pull_request.is_closed():
# don't allow deleting comments on closed pull request
raise HTTPForbidden()
is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
super_admin = h.HasPermissionAny('hg.admin')()
comment_owner = comment.author.user_id == self._rhodecode_user.user_id
is_repo_comment = comment.repo.repo_name == self.db_repo_name
comment_repo_admin = is_repo_admin and is_repo_comment
comments: forbig removal of comments by anyone except the owners.
r4643 if comment.draft and not comment_owner:
# We never allow to delete draft comments for other than owners
raise HTTPNotFound()
pull-requests: migrated code from pylons to pyramid
r1974 if super_admin or comment_owner or comment_repo_admin:
old_calculated_status = comment.pull_request.calculated_review_status()
audit-logs: store properly IP and user for certain comments types....
r2728 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
pull-requests: migrated code from pylons to pyramid
r1974 Session().commit()
calculated_status = comment.pull_request.calculated_review_status()
if old_calculated_status != calculated_status:
events: trigger 'review_status_change' when reviewers are updated....
r3415 PullRequestModel().trigger_pull_request_hook(
comment.pull_request, self._rhodecode_user, 'review_status_change',
data={'status': calculated_status})
pull-requests: migrated code from pylons to pyramid
r1974 return True
else:
log.warning('No permissions for user %s to delete comment_id: %s',
self._rhodecode_db_user, comment_id)
raise HTTPNotFound()
comments: edit functionality added
r4401
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@CSRFRequired()
def pull_request_comment_edit(self):
comment-history: fixes/ui changes...
r4408 self.load_default_context()
comments: edit functionality added
r4401 pull_request = PullRequest.get_or_404(
self.request.matchdict['pull_request_id']
)
comment = ChangesetComment.get_or_404(
self.request.matchdict['comment_id']
)
comment_id = comment.comment_id
if comment.immutable:
# don't allow deleting comments that are immutable
raise HTTPForbidden()
if pull_request.is_closed():
log.debug('comment: forbidden because pull request is closed')
raise HTTPForbidden()
if comment.pull_request.is_closed():
# don't allow deleting comments on closed pull request
raise HTTPForbidden()
is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
super_admin = h.HasPermissionAny('hg.admin')()
comment_owner = comment.author.user_id == self._rhodecode_user.user_id
is_repo_comment = comment.repo.repo_name == self.db_repo_name
comment_repo_admin = is_repo_admin and is_repo_comment
if super_admin or comment_owner or comment_repo_admin:
text = self.request.POST.get('text')
version = self.request.POST.get('version')
if text == comment.text:
log.warning(
'Comment(PR): '
'Trying to create new version '
comment-history: fixes/ui changes...
r4408 'with the same comment body {}'.format(
comments: edit functionality added
r4401 comment_id,
)
)
raise HTTPNotFound()
comment-history: fixes/ui changes...
r4408
comments: edit functionality added
r4401 if version.isdigit():
version = int(version)
else:
log.warning(
'Comment(PR): Wrong version type {} {} '
'for comment {}'.format(
version,
type(version),
comment_id,
)
)
raise HTTPNotFound()
comment-history: fixes/ui changes...
r4408 try:
comment_history = CommentsModel().edit(
comment_id=comment_id,
text=text,
auth_user=self._rhodecode_user,
version=version,
)
except CommentVersionMismatch:
raise HTTPConflict()
comments: edit functionality added
r4401 if not comment_history:
raise HTTPNotFound()
comment-history: fixes/ui changes...
r4408
comments: edit functionality added
r4401 Session().commit()
drafts: support draft in commits view...
r4555 if not comment.draft:
PullRequestModel().trigger_pull_request_hook(
pull_request, self._rhodecode_user, 'comment_edit',
data={'comment': comment})
comments: added new events for comment editing to handle them in integrations.
r4444
comments: edit functionality added
r4401 return {
'comment_history_id': comment_history.comment_history_id,
'comment_id': comment.comment_id,
'comment_version': comment_history.version,
comment-history: fixes/ui changes...
r4408 'comment_author_username': comment_history.author.username,
core: multiple fixes to unicode vs str usage...
r5065 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16, request=self.request),
comment-history: fixes/ui changes...
r4408 'comment_created_on': h.age_component(comment_history.created_on,
time_is_local=True),
comments: edit functionality added
r4401 }
else:
comment-history: fixes/ui changes...
r4408 log.warning('No permissions for user %s to edit comment_id: %s',
self._rhodecode_db_user, comment_id)
comments: edit functionality added
r4401 raise HTTPNotFound()