diff --git a/.bumpversion.cfg b/.bumpversion.cfg --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,6 @@ [bumpversion] -current_version = 4.25.0 +current_version = 4.25.2 message = release: Bump version {current_version} to {new_version} [bumpversion:file:rhodecode/VERSION] + diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -75,3 +75,6 @@ 56310d93b33b97535908ef9c7b0985b89bb7fad2 7637c38528fa38c1eabc1fde6a869c20995a0da7 v4.23.2 6aeb4ac3ef7f0ac699c914740dad3688c9495e83 v4.24.0 6eaf953da06e468a4c4e5239d3d0e700bda6b163 v4.24.1 +f8161cbc2d94a935d3c395a0e758d9a094287169 v4.25.0 +77fe47b5b39338e71b2c040de2c0359b529b6251 v4.25.1 +27475bd8a718b9a00a37a8563c4927120865ad85 v4.25.2 diff --git a/.release.cfg b/.release.cfg --- a/.release.cfg +++ b/.release.cfg @@ -21,7 +21,7 @@ done = true [release] state = prepared -version = 4.11.6 +version = 4.25.2 [task:updated_translation] diff --git a/docs/release-notes/release-notes-4.25.1.rst b/docs/release-notes/release-notes-4.25.1.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-4.25.1.rst @@ -0,0 +1,40 @@ +|RCE| 4.25.1 |RNS| +------------------ + +Release Date +^^^^^^^^^^^^ + +- 2021-04-06 + + +New Features +^^^^^^^^^^^^ + + + +General +^^^^^^^ + + + +Security +^^^^^^^^ + + + +Performance +^^^^^^^^^^^ + + + +Fixes +^^^^^ + +- Artifacts: fixed admin panel bad urls generated for the new artifacts admin view in CE edition. + + + +Upgrade notes +^^^^^^^^^^^^^ + +- Un-scheduled release addressing problems in 4.25.X releases. diff --git a/docs/release-notes/release-notes-4.25.2.rst b/docs/release-notes/release-notes-4.25.2.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-4.25.2.rst @@ -0,0 +1,53 @@ +|RCE| 4.25.2 |RNS| +------------------ + +Release Date +^^^^^^^^^^^^ + +- 2021-04-14 + + +New Features +^^^^^^^^^^^^ + + + +General +^^^^^^^ + +- Comments: refresh on draft sidebar on draft submit. +- Vcsserver: log exceptions into the logs +- Archiving: make it explicit archiving a repo is irreversible. +- My-account: updated bookmarks UX +- Pull requests: added awaiting my review filter for users pull-requests. + Additionally the awaiting my review now properly filters pull requests that have no review votes on them. + + +Security +^^^^^^^^ + + + +Performance +^^^^^^^^^^^ + + + +Fixes +^^^^^ + +- Draft comments: fixed logic in toggle all draft for submit. +- Draft comments: when submitting edited drafts also clear the history to prevent DB problems. +- Mercurial: fixed a case of lookup branches that had 40 characters in length. +- Gists: block id input for public gists. +- Pull requests: fixed problems with unicode characters in branches. +- Pull requests: small ui fix for grid. +- Summary: fixed ui on summary page for non-admins. + The setup instructions were broken if user had no write permissions. +- Users: make user data loading more resilient to errors. + + +Upgrade notes +^^^^^^^^^^^^^ + +- Scheduled release addressing problems in 4.25.X releases. diff --git a/docs/release-notes/release-notes.rst b/docs/release-notes/release-notes.rst --- a/docs/release-notes/release-notes.rst +++ b/docs/release-notes/release-notes.rst @@ -9,6 +9,8 @@ Release Notes .. toctree:: :maxdepth: 1 + release-notes-4.25.2.rst + release-notes-4.25.1.rst release-notes-4.25.0.rst release-notes-4.24.1.rst release-notes-4.24.0.rst diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix --- a/pkgs/python-packages.nix +++ b/pkgs/python-packages.nix @@ -1883,7 +1883,7 @@ self: super: { }; }; "rhodecode-enterprise-ce" = super.buildPythonPackage { - name = "rhodecode-enterprise-ce-4.25.0"; + name = "rhodecode-enterprise-ce-4.25.2"; buildInputs = [ self."pytest" self."py" diff --git a/rhodecode/VERSION b/rhodecode/VERSION --- a/rhodecode/VERSION +++ b/rhodecode/VERSION @@ -1,1 +1,1 @@ -4.25.0 \ No newline at end of file +4.25.2 \ No newline at end of file diff --git a/rhodecode/api/views/repo_group_api.py b/rhodecode/api/views/repo_group_api.py --- a/rhodecode/api/views/repo_group_api.py +++ b/rhodecode/api/views/repo_group_api.py @@ -232,6 +232,9 @@ def create_repo_group( user=apiuser) Session().commit() + + PermissionModel().trigger_permission_flush() + return { 'msg': 'Created new repo group `%s`' % validated_group_name, 'repo_group': repo_group.get_api_data() diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py --- a/rhodecode/apps/admin/__init__.py +++ b/rhodecode/apps/admin/__init__.py @@ -27,6 +27,7 @@ def admin_routes(config): Admin prefixed routes """ from rhodecode.apps.admin.views.audit_logs import AdminAuditLogsView + from rhodecode.apps.admin.views.artifacts import AdminArtifactsView from rhodecode.apps.admin.views.defaults import AdminDefaultSettingsView from rhodecode.apps.admin.views.exception_tracker import ExceptionsTrackerView from rhodecode.apps.admin.views.main_views import AdminMainView @@ -60,6 +61,34 @@ def admin_routes(config): route_name='admin_audit_log_entry', request_method='GET', renderer='rhodecode:templates/admin/admin_audit_log_entry.mako') + # Artifacts EE feature + config.add_route( + 'admin_artifacts', + pattern=ADMIN_PREFIX + '/artifacts') + config.add_route( + 'admin_artifacts_show_all', + pattern=ADMIN_PREFIX + '/artifacts') + config.add_view( + AdminArtifactsView, + attr='artifacts', + route_name='admin_artifacts', request_method='GET', + renderer='rhodecode:templates/admin/artifacts/artifacts.mako') + config.add_view( + AdminArtifactsView, + attr='artifacts', + route_name='admin_artifacts_show_all', request_method='GET', + renderer='rhodecode:templates/admin/artifacts/artifacts.mako') + # EE views + config.add_route( + name='admin_artifacts_show_info', + pattern=ADMIN_PREFIX + '/artifacts/{uid}') + config.add_route( + name='admin_artifacts_delete', + pattern=ADMIN_PREFIX + '/artifacts/{uid}/delete') + config.add_route( + name='admin_artifacts_update', + pattern=ADMIN_PREFIX + '/artifacts/{uid}/update') + config.add_route( name='admin_settings_open_source', pattern='/settings/open_source') diff --git a/rhodecode/apps/admin/views/artifacts.py b/rhodecode/apps/admin/views/artifacts.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/admin/views/artifacts.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2020 RhodeCode GmbH +# +# 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 . +# +# 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 + +from rhodecode.apps._base import BaseAppView, DataGridAppView +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator + +log = logging.getLogger(__name__) + + +class AdminArtifactsView(BaseAppView, DataGridAppView): + + def load_default_context(self): + c = self._get_local_tmpl_context() + return c + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + def artifacts(self): + c = self.load_default_context() + c.active = 'artifacts' + return self._get_template_context(c) diff --git a/rhodecode/apps/admin/views/repo_groups.py b/rhodecode/apps/admin/views/repo_groups.py --- a/rhodecode/apps/admin/views/repo_groups.py +++ b/rhodecode/apps/admin/views/repo_groups.py @@ -349,13 +349,7 @@ class AdminRepoGroupsView(BaseAppView, D % repo_group_name, category='error') raise HTTPFound(h.route_path('home')) - affected_user_ids = [self._rhodecode_user.user_id] - if copy_permissions: - user_group_perms = repo_group.permissions(expand_from_user_groups=True) - copy_perms = [perm['user_id'] for perm in user_group_perms] - # also include those newly created by copy - affected_user_ids.extend(copy_perms) - PermissionModel().trigger_permission_flush(affected_user_ids) + PermissionModel().trigger_permission_flush() raise HTTPFound( h.route_path('repo_group_home', diff --git a/rhodecode/apps/admin/views/repositories.py b/rhodecode/apps/admin/views/repositories.py --- a/rhodecode/apps/admin/views/repositories.py +++ b/rhodecode/apps/admin/views/repositories.py @@ -242,11 +242,7 @@ class AdminReposView(BaseAppView, DataGr repo_name = form_result.get('repo_name_full') - affected_user_ids = [self._rhodecode_user.user_id] - if copy_permissions: - # permission flush is done in repo creating - pass - PermissionModel().trigger_permission_flush(affected_user_ids) + PermissionModel().trigger_permission_flush() raise HTTPFound( h.route_path('repo_creating', repo_name=repo_name, diff --git a/rhodecode/apps/my_account/tests/test_my_account_edit.py b/rhodecode/apps/my_account/tests/test_my_account_edit.py --- a/rhodecode/apps/my_account/tests/test_my_account_edit.py +++ b/rhodecode/apps/my_account/tests/test_my_account_edit.py @@ -76,7 +76,11 @@ class TestMyAccountEdit(TestController): 'requests requiring your participation.') @pytest.mark.backends("git", "hg") - def test_my_account_my_pullrequests_data(self, pr_util, xhr_header): + @pytest.mark.parametrize('params, expected_title', [ + ({'closed': 1}, 'Closed'), + ({'awaiting_my_review': 1}, 'Awaiting my review'), + ]) + def test_my_account_my_pullrequests_data(self, pr_util, xhr_header, params, expected_title): self.log_user() response = self.app.get(route_path('my_account_pullrequests_data'), extra_environ=xhr_header) diff --git a/rhodecode/apps/my_account/views/my_account.py b/rhodecode/apps/my_account/views/my_account.py --- a/rhodecode/apps/my_account/views/my_account.py +++ b/rhodecode/apps/my_account/views/my_account.py @@ -43,7 +43,7 @@ from rhodecode.model.comment import Comm from rhodecode.model.db import ( IntegrityError, or_, in_filter_generator, Repository, UserEmailMap, UserApiKeys, UserFollowing, - PullRequest, UserBookmark, RepoGroup) + PullRequest, UserBookmark, RepoGroup, ChangesetStatus) from rhodecode.model.meta import Session from rhodecode.model.pull_request import PullRequestModel from rhodecode.model.user import UserModel @@ -654,21 +654,31 @@ class MyAccountView(BaseAppView, DataGri Session().commit() return user.user_data['notification_status'] - def _get_pull_requests_list(self, statuses): + def _get_pull_requests_list(self, statuses, filter_type=None): draw, start, limit = self._extract_chunk(self.request) search_q, order_by, order_dir = self._extract_ordering(self.request) _render = self.request.get_partial_renderer( 'rhodecode:templates/data_table/_dt_elements.mako') - pull_requests = PullRequestModel().get_im_participating_in( - user_id=self._rhodecode_user.user_id, - statuses=statuses, query=search_q, - offset=start, length=limit, order_by=order_by, - order_dir=order_dir) + if filter_type == 'awaiting_my_review': + pull_requests = PullRequestModel().get_im_participating_in_for_review( + user_id=self._rhodecode_user.user_id, + statuses=statuses, query=search_q, + offset=start, length=limit, order_by=order_by, + order_dir=order_dir) - pull_requests_total_count = PullRequestModel().count_im_participating_in( - user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) + pull_requests_total_count = PullRequestModel().count_im_participating_in_for_review( + user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) + else: + pull_requests = PullRequestModel().get_im_participating_in( + user_id=self._rhodecode_user.user_id, + statuses=statuses, query=search_q, + offset=start, length=limit, order_by=order_by, + order_dir=order_dir) + + pull_requests_total_count = PullRequestModel().count_im_participating_in( + user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) data = [] comments_model = CommentsModel() @@ -678,6 +688,12 @@ class MyAccountView(BaseAppView, DataGri repo_id, pull_request=pr, include_drafts=False, count_only=True) owned = pr.user_id == self._rhodecode_user.user_id + 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 + data.append({ 'target_repo': _render('pullrequest_target_repo', pr.target_repo.repo_name), @@ -688,6 +704,8 @@ class MyAccountView(BaseAppView, DataGri 'name_raw': pr.pull_request_id, 'status': _render('pullrequest_status', pr.calculated_review_status()), + 'my_status': _render('pullrequest_status', + my_review_status), 'title': _render('pullrequest_title', pr.title, pr.description), 'description': h.escape(pr.description), 'updated_on': _render('pullrequest_updated_on', @@ -723,7 +741,14 @@ class MyAccountView(BaseAppView, DataGri c.active = 'pullrequests' req_get = self.request.GET - c.closed = str2bool(req_get.get('pr_show_closed')) + c.closed = str2bool(req_get.get('closed')) + c.awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) + + c.selected_filter = 'all' + if c.closed: + c.selected_filter = 'all_closed' + if c.awaiting_my_review: + c.selected_filter = 'awaiting_my_review' return self._get_template_context(c) @@ -732,13 +757,19 @@ class MyAccountView(BaseAppView, DataGri def my_account_pullrequests_data(self): self.load_default_context() req_get = self.request.GET + + awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) closed = str2bool(req_get.get('closed')) statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] if closed: statuses += [PullRequest.STATUS_CLOSED] - data = self._get_pull_requests_list(statuses=statuses) + filter_type = \ + 'awaiting_my_review' if awaiting_my_review \ + else None + + data = self._get_pull_requests_list(statuses=statuses, filter_type=filter_type) return data @LoginRequired() diff --git a/rhodecode/apps/repository/tests/test_pull_requests_list.py b/rhodecode/apps/repository/tests/test_pull_requests_list.py --- a/rhodecode/apps/repository/tests/test_pull_requests_list.py +++ b/rhodecode/apps/repository/tests/test_pull_requests_list.py @@ -41,7 +41,7 @@ class TestPullRequestList(object): @pytest.mark.parametrize('params, expected_title', [ ({'source': 0, 'closed': 1}, 'Closed'), - ({'source': 0, 'my': 1}, 'Opened by me'), + ({'source': 0, 'my': 1}, 'Created by me'), ({'source': 0, 'awaiting_review': 1}, 'Awaiting review'), ({'source': 0, 'awaiting_my_review': 1}, 'Awaiting my review'), ({'source': 1}, 'From this repo'), diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -539,8 +539,14 @@ class RepoCommitsView(RepoAppView): @CSRFRequired() def repo_commit_comment_history_view(self): c = self.load_default_context() + comment_history_id = self.request.matchdict['comment_history_id'] - comment_history_id = self.request.matchdict['comment_history_id'] + comment = ChangesetComment.get_or_404(comment_history_id) + comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id) + if comment.draft and not comment_owner: + # if we see draft comments history, we only allow this for owner + raise HTTPNotFound() + comment_history = ChangesetCommentHistory.get_or_404(comment_history_id) is_repo_comment = comment_history.comment.repo.repo_id == self.db_repo.repo_id @@ -549,8 +555,7 @@ class RepoCommitsView(RepoAppView): rendered_comment = render( 'rhodecode:templates/changeset/comment_history.mako', - self._get_template_context(c) - , self.request) + self._get_template_context(c), self.request) return rendered_comment else: log.warning('No permissions for user %s to show comment_history_id: %s', diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py --- a/rhodecode/apps/repository/views/repo_pull_requests.py +++ b/rhodecode/apps/repository/views/repo_pull_requests.py @@ -39,7 +39,7 @@ from rhodecode.lib.ext_json import json from rhodecode.lib.auth import ( LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired) -from rhodecode.lib.utils2 import str2bool, safe_str, safe_unicode, safe_int, aslist +from rhodecode.lib.utils2 import str2bool, safe_str, safe_unicode, safe_int, aslist, retry from rhodecode.lib.vcs.backends.base import ( EmptyCommit, UpdateFailureReason, unicode_to_reference) from rhodecode.lib.vcs.exceptions import ( @@ -79,21 +79,20 @@ class RepoPullRequestsView(RepoAppView, if filter_type == 'awaiting_review': pull_requests = PullRequestModel().get_awaiting_review( - repo_name, search_q=search_q, source=source, opened_by=opened_by, - statuses=statuses, offset=start, length=limit, - order_by=order_by, order_dir=order_dir) + repo_name, + search_q=search_q, statuses=statuses, + offset=start, length=limit, order_by=order_by, order_dir=order_dir) pull_requests_total_count = PullRequestModel().count_awaiting_review( - repo_name, search_q=search_q, source=source, statuses=statuses, - opened_by=opened_by) + repo_name, + search_q=search_q, statuses=statuses) elif filter_type == 'awaiting_my_review': pull_requests = PullRequestModel().get_awaiting_my_review( - repo_name, search_q=search_q, source=source, opened_by=opened_by, - user_id=self._rhodecode_user.user_id, statuses=statuses, - offset=start, length=limit, order_by=order_by, - order_dir=order_dir) + 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_total_count = PullRequestModel().count_awaiting_my_review( - repo_name, search_q=search_q, source=source, user_id=self._rhodecode_user.user_id, - statuses=statuses, opened_by=opened_by) + repo_name, self._rhodecode_user.user_id, + search_q=search_q, statuses=statuses) else: pull_requests = PullRequestModel().get_all( repo_name, search_q=search_q, source=source, opened_by=opened_by, @@ -110,6 +109,12 @@ class RepoPullRequestsView(RepoAppView, self.db_repo.repo_id, pull_request=pr, include_drafts=False, count_only=True) + 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 + data.append({ 'name': _render('pullrequest_name', pr.pull_request_id, pr.pull_request_state, @@ -118,6 +123,8 @@ class RepoPullRequestsView(RepoAppView, 'name_raw': pr.pull_request_id, 'status': _render('pullrequest_status', pr.calculated_review_status()), + 'my_status': _render('pullrequest_status', + my_review_status), 'title': _render('pullrequest_title', pr.title, pr.description), 'description': h.escape(pr.description), 'updated_on': _render('pullrequest_updated_on', @@ -1346,9 +1353,13 @@ class RepoPullRequestsView(RepoAppView, def _update_commits(self, c, pull_request): _ = self.request.translate + @retry(exception=Exception, n_tries=3) + def commits_update(): + return PullRequestModel().update_commits( + pull_request, self._rhodecode_db_user) + with pull_request.set_state(PullRequest.STATE_UPDATING): - resp = PullRequestModel().update_commits( - pull_request, self._rhodecode_db_user) + resp = commits_update() # retry x3 if resp.executed: diff --git a/rhodecode/i18n/rhodecode.pot b/rhodecode/i18n/rhodecode.pot --- a/rhodecode/i18n/rhodecode.pot +++ b/rhodecode/i18n/rhodecode.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: rhodecode-enterprise-ce 4.24.0\n" +"Project-Id-Version: rhodecode-enterprise-ce 4.25.0\n" "Report-Msgid-Bugs-To: marcin@rhodecode.com\n" -"POT-Creation-Date: 2021-01-14 15:36+0000\n" +"POT-Creation-Date: 2021-04-05 19:29+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -111,7 +111,7 @@ msgstr "" #: rhodecode/apps/admin/views/settings.py:156 #: rhodecode/apps/admin/views/settings.py:291 #: rhodecode/apps/admin/views/settings.py:360 -#: rhodecode/apps/admin/views/settings.py:663 +#: rhodecode/apps/admin/views/settings.py:664 #: rhodecode/apps/repository/views/repo_settings_vcs.py:116 msgid "Some form inputs contain invalid data." msgstr "" @@ -135,54 +135,54 @@ msgstr "" msgid "Updated application settings" msgstr "" -#: rhodecode/apps/admin/views/settings.py:399 +#: rhodecode/apps/admin/views/settings.py:400 msgid "Updated visualisation settings" msgstr "" -#: rhodecode/apps/admin/views/settings.py:402 +#: rhodecode/apps/admin/views/settings.py:403 msgid "Error occurred during updating visualisation settings" msgstr "" -#: rhodecode/apps/admin/views/settings.py:464 +#: rhodecode/apps/admin/views/settings.py:465 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:115 msgid "Invalid issue tracker pattern: {}" msgstr "" -#: rhodecode/apps/admin/views/settings.py:481 +#: rhodecode/apps/admin/views/settings.py:482 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:124 msgid "Updated issue tracker entries" msgstr "" -#: rhodecode/apps/admin/views/settings.py:498 +#: rhodecode/apps/admin/views/settings.py:499 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:82 msgid "Removed issue tracker entry." msgstr "" -#: rhodecode/apps/admin/views/settings.py:530 +#: rhodecode/apps/admin/views/settings.py:531 msgid "Please enter email address" msgstr "" -#: rhodecode/apps/admin/views/settings.py:546 +#: rhodecode/apps/admin/views/settings.py:547 msgid "Send email task created" msgstr "" -#: rhodecode/apps/admin/views/settings.py:587 +#: rhodecode/apps/admin/views/settings.py:588 msgid "Added new hook" msgstr "" -#: rhodecode/apps/admin/views/settings.py:602 +#: rhodecode/apps/admin/views/settings.py:603 msgid "Updated hooks" msgstr "" -#: rhodecode/apps/admin/views/settings.py:606 +#: rhodecode/apps/admin/views/settings.py:607 msgid "Error occurred during hook creation" msgstr "" -#: rhodecode/apps/admin/views/settings.py:687 +#: rhodecode/apps/admin/views/settings.py:688 msgid "Error occurred during updating labs settings" msgstr "" -#: rhodecode/apps/admin/views/settings.py:692 +#: rhodecode/apps/admin/views/settings.py:693 msgid "Updated Labs settings" msgstr "" @@ -592,7 +592,7 @@ msgstr "" msgid "1 month" msgstr "" -#: rhodecode/apps/gist/views.py:63 rhodecode/public/js/scripts.js:48529 +#: rhodecode/apps/gist/views.py:63 rhodecode/public/js/scripts.js:48670 #: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:48 #: rhodecode/public/js/src/rhodecode.js:634 @@ -653,8 +653,8 @@ msgstr "" #: rhodecode/templates/admin/repos/repo_add.mako:19 #: rhodecode/templates/admin/users/user_edit_advanced.mako:12 #: rhodecode/templates/base/base.mako:114 -#: rhodecode/templates/base/base.mako:133 -#: rhodecode/templates/base/base.mako:1191 +#: rhodecode/templates/base/base.mako:134 +#: rhodecode/templates/base/base.mako:1192 msgid "Repositories" msgstr "" @@ -894,104 +894,104 @@ msgstr "" msgid "No such commit exists for this repository. Commit: {}" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:358 +#: rhodecode/apps/repository/views/repo_files.py:359 msgid "Downloads disabled" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:364 +#: rhodecode/apps/repository/views/repo_files.py:365 msgid "Unknown archive type for: `{}`" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:370 +#: rhodecode/apps/repository/views/repo_files.py:371 msgid "Unknown commit_id {}" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:373 +#: rhodecode/apps/repository/views/repo_files.py:374 msgid "Empty repository" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:378 +#: rhodecode/apps/repository/views/repo_files.py:384 msgid "No node at path {} for this repository" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:429 +#: rhodecode/apps/repository/views/repo_files.py:436 msgid "Unknown archive type" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:986 +#: rhodecode/apps/repository/views/repo_files.py:993 msgid "Changesets" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1007 -#: rhodecode/apps/repository/views/repo_summary.py:243 -#: rhodecode/model/pull_request.py:1910 rhodecode/model/scm.py:999 +#: rhodecode/apps/repository/views/repo_files.py:1014 +#: rhodecode/apps/repository/views/repo_summary.py:239 +#: rhodecode/model/pull_request.py:1912 rhodecode/model/scm.py:999 #: rhodecode/templates/base/vcs_settings.mako:235 #: rhodecode/templates/summary/components.mako:10 msgid "Branches" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1011 +#: rhodecode/apps/repository/views/repo_files.py:1018 #: rhodecode/model/scm.py:1016 rhodecode/templates/base/vcs_settings.mako:260 #: rhodecode/templates/summary/components.mako:34 msgid "Tags" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1155 -#: rhodecode/apps/repository/views/repo_files.py:1181 +#: rhodecode/apps/repository/views/repo_files.py:1162 +#: rhodecode/apps/repository/views/repo_files.py:1188 msgid "Deleted file {} via RhodeCode Enterprise" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1202 +#: rhodecode/apps/repository/views/repo_files.py:1209 msgid "Successfully deleted file `{}`" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1206 +#: rhodecode/apps/repository/views/repo_files.py:1213 +#: rhodecode/apps/repository/views/repo_files.py:1326 +#: rhodecode/apps/repository/views/repo_files.py:1450 +#: rhodecode/apps/repository/views/repo_files.py:1571 +msgid "Error occurred during commit" +msgstr "" + +#: rhodecode/apps/repository/views/repo_files.py:1243 +#: rhodecode/apps/repository/views/repo_files.py:1272 +msgid "Edited file {} via RhodeCode Enterprise" +msgstr "" + +#: rhodecode/apps/repository/views/repo_files.py:1295 +msgid "No changes detected on {}" +msgstr "" + #: rhodecode/apps/repository/views/repo_files.py:1319 -#: rhodecode/apps/repository/views/repo_files.py:1443 -#: rhodecode/apps/repository/views/repo_files.py:1564 -msgid "Error occurred during commit" -msgstr "" - -#: rhodecode/apps/repository/views/repo_files.py:1236 -#: rhodecode/apps/repository/views/repo_files.py:1265 -msgid "Edited file {} via RhodeCode Enterprise" -msgstr "" - -#: rhodecode/apps/repository/views/repo_files.py:1288 -msgid "No changes detected on {}" -msgstr "" - -#: rhodecode/apps/repository/views/repo_files.py:1312 msgid "Successfully committed changes to file `{}`" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1348 -#: rhodecode/apps/repository/views/repo_files.py:1387 +#: rhodecode/apps/repository/views/repo_files.py:1355 +#: rhodecode/apps/repository/views/repo_files.py:1394 msgid "Added file via RhodeCode Enterprise" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1403 +#: rhodecode/apps/repository/views/repo_files.py:1410 msgid "No filename specified" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1428 +#: rhodecode/apps/repository/views/repo_files.py:1435 msgid "Successfully committed new file `{}`" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1436 -#: rhodecode/apps/repository/views/repo_files.py:1546 +#: rhodecode/apps/repository/views/repo_files.py:1443 +#: rhodecode/apps/repository/views/repo_files.py:1553 msgid "The location specified must be a relative path and must not contain .. in the path" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1491 +#: rhodecode/apps/repository/views/repo_files.py:1498 msgid "Uploaded file via RhodeCode Enterprise" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1535 +#: rhodecode/apps/repository/views/repo_files.py:1542 msgid "Successfully committed {} new files" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:1537 +#: rhodecode/apps/repository/views/repo_files.py:1544 msgid "Successfully committed 1 new file" msgstr "" @@ -1215,23 +1215,23 @@ msgstr "" msgid "Error occurred during updating repository VCS settings" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:222 +#: rhodecode/apps/repository/views/repo_summary.py:218 #: rhodecode/templates/admin/permissions/permissions.mako:42 #: rhodecode/templates/summary/components.mako:8 msgid "Branch" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:223 +#: rhodecode/apps/repository/views/repo_summary.py:219 #: rhodecode/templates/summary/components.mako:32 msgid "Tag" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:224 +#: rhodecode/apps/repository/views/repo_summary.py:220 #: rhodecode/templates/summary/components.mako:44 msgid "Bookmark" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:244 +#: rhodecode/apps/repository/views/repo_summary.py:240 msgid "Closed branches" msgstr "" @@ -1291,9 +1291,9 @@ msgid "Enable or disable this authentica msgstr "" #: rhodecode/authentication/schema.py:38 rhodecode/integrations/schema.py:32 -#: rhodecode/model/permission.py:110 rhodecode/model/permission.py:114 -#: rhodecode/model/permission.py:118 rhodecode/model/permission.py:122 -#: rhodecode/model/permission.py:126 rhodecode/model/permission.py:130 +#: rhodecode/model/permission.py:112 rhodecode/model/permission.py:116 +#: rhodecode/model/permission.py:120 rhodecode/model/permission.py:124 +#: rhodecode/model/permission.py:128 rhodecode/model/permission.py:132 #: rhodecode/model/validation_schema/schemas/integration_schema.py:195 #: rhodecode/templates/admin/auth/auth_settings.mako:64 #: rhodecode/templates/admin/integrations/list.mako:71 @@ -1806,7 +1806,7 @@ msgstr "" #: rhodecode/templates/admin/settings/settings_issuetracker.mako:16 #: rhodecode/templates/admin/settings/settings_labs.mako:49 #: rhodecode/templates/admin/settings/settings_vcs.mako:14 -#: rhodecode/templates/admin/settings/settings_visual.mako:215 +#: rhodecode/templates/admin/settings/settings_visual.mako:218 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:217 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:107 #: rhodecode/templates/admin/users/user_edit_emails.mako:66 @@ -1841,7 +1841,7 @@ msgstr "" #: rhodecode/templates/changeset/changeset_file_comment.mako:236 #: rhodecode/templates/changeset/changeset_file_comment.mako:250 #: rhodecode/templates/changeset/changeset_file_comment.mako:259 -#: rhodecode/templates/data_table/_dt_elements.mako:439 +#: rhodecode/templates/data_table/_dt_elements.mako:445 #: rhodecode/templates/debug_style/buttons.html:132 #: rhodecode/templates/files/files_source.mako:40 #: rhodecode/templates/files/files_source.mako:47 @@ -2229,15 +2229,15 @@ msgstr "" msgid "Commit not found" msgstr "" -#: rhodecode/lib/auth.py:1769 +#: rhodecode/lib/auth.py:1771 msgid "IP {} not allowed" msgstr "" -#: rhodecode/lib/auth.py:1861 +#: rhodecode/lib/auth.py:1863 msgid "You need to be a registered user to perform this action" msgstr "" -#: rhodecode/lib/auth.py:1905 +#: rhodecode/lib/auth.py:1907 msgid "You need to be signed in to view this page" msgstr "" @@ -2249,7 +2249,7 @@ msgstr "" msgid "Click to select line" msgstr "" -#: rhodecode/lib/helpers.py:1878 +#: rhodecode/lib/helpers.py:1883 msgid "" "Example filter terms:\n" " repository:vcs\n" @@ -2271,7 +2271,7 @@ msgid "" " \"username:test AND repository:test*\"\n" msgstr "" -#: rhodecode/lib/helpers.py:1902 +#: rhodecode/lib/helpers.py:1907 #, python-format msgid "%s repository is not mapped to db perhaps it was created or renamed from the filesystem please run the application again in order to rescan repositories" msgstr "" @@ -2760,7 +2760,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3011 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3012 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3230 rhodecode/model/db.py:3997 -#: rhodecode/public/js/scripts.js:42595 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42733 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:72 #: rhodecode/public/js/src/rhodecode/pullrequests.js:396 msgid "Not Reviewed" @@ -3520,7 +3520,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2358 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2359 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:3174 -#: rhodecode/model/permission.py:105 +#: rhodecode/model/permission.py:107 msgid "Manual activation of external account" msgstr "" @@ -3560,7 +3560,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2359 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2360 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2560 rhodecode/model/db.py:3175 -#: rhodecode/model/permission.py:106 +#: rhodecode/model/permission.py:108 msgid "Automatic activation of external account" msgstr "" @@ -3986,51 +3986,51 @@ msgstr "" msgid "Commit index" msgstr "" -#: rhodecode/lib/vcs/backends/base.py:186 +#: rhodecode/lib/vcs/backends/base.py:190 msgid "This pull request can be automatically merged." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:188 +#: rhodecode/lib/vcs/backends/base.py:192 msgid "This pull request cannot be merged because of an unhandled exception. {exception}" msgstr "" -#: rhodecode/lib/vcs/backends/base.py:191 +#: rhodecode/lib/vcs/backends/base.py:195 msgid "This pull request cannot be merged because of merge conflicts. {unresolved_files}" msgstr "" -#: rhodecode/lib/vcs/backends/base.py:193 +#: rhodecode/lib/vcs/backends/base.py:197 msgid "This pull request could not be merged because push to target:`{target}@{merge_commit}` failed." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:196 +#: rhodecode/lib/vcs/backends/base.py:200 msgid "This pull request cannot be merged because the target `{target_ref.name}` is not a head." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:199 +#: rhodecode/lib/vcs/backends/base.py:203 msgid "This pull request cannot be merged because the source contains more branches than the target." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:202 +#: rhodecode/lib/vcs/backends/base.py:206 msgid "This pull request cannot be merged because the target `{target_ref.name}` has multiple heads: `{heads}`." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:205 -msgid "This pull request cannot be merged because the target repository is locked by {locked_by}." -msgstr "" - #: rhodecode/lib/vcs/backends/base.py:209 +msgid "This pull request cannot be merged because the target repository is locked by {locked_by}." +msgstr "" + +#: rhodecode/lib/vcs/backends/base.py:213 msgid "This pull request cannot be merged because the target reference `{target_ref.name}` is missing." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:212 +#: rhodecode/lib/vcs/backends/base.py:216 msgid "This pull request cannot be merged because the source reference `{source_ref.name}` is missing." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:215 +#: rhodecode/lib/vcs/backends/base.py:219 msgid "This pull request cannot be merged because of conflicts related to sub repositories." msgstr "" -#: rhodecode/lib/vcs/backends/base.py:220 +#: rhodecode/lib/vcs/backends/base.py:224 msgid "This pull request cannot be merged because the target or the source reference is missing." msgstr "" @@ -4138,8 +4138,8 @@ msgstr "" msgid "%(user)s commented on pull request at %(date_or_age)s" msgstr "" -#: rhodecode/model/permission.py:71 rhodecode/model/permission.py:77 -#: rhodecode/model/permission.py:83 +#: rhodecode/model/permission.py:73 rhodecode/model/permission.py:79 +#: rhodecode/model/permission.py:85 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:11 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:217 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:11 @@ -4147,27 +4147,27 @@ msgstr "" msgid "None" msgstr "" -#: rhodecode/model/permission.py:72 rhodecode/model/permission.py:78 -#: rhodecode/model/permission.py:84 +#: rhodecode/model/permission.py:74 rhodecode/model/permission.py:80 +#: rhodecode/model/permission.py:86 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:12 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:12 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:16 msgid "Read" msgstr "" -#: rhodecode/model/permission.py:73 rhodecode/model/permission.py:79 -#: rhodecode/model/permission.py:85 +#: rhodecode/model/permission.py:75 rhodecode/model/permission.py:81 +#: rhodecode/model/permission.py:87 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:13 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:13 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:17 #: rhodecode/templates/changeset/changeset_file_comment.mako:392 #: rhodecode/templates/changeset/changeset_file_comment.mako:443 -#: rhodecode/templates/data_table/_dt_elements.mako:453 +#: rhodecode/templates/data_table/_dt_elements.mako:460 msgid "Write" msgstr "" -#: rhodecode/model/permission.py:74 rhodecode/model/permission.py:80 -#: rhodecode/model/permission.py:86 +#: rhodecode/model/permission.py:76 rhodecode/model/permission.py:82 +#: rhodecode/model/permission.py:88 #: rhodecode/templates/admin/auth/plugin_settings.mako:12 #: rhodecode/templates/admin/defaults/defaults.mako:12 #: rhodecode/templates/admin/integrations/base.mako:21 @@ -4189,51 +4189,51 @@ msgstr "" #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:18 #: rhodecode/templates/admin/users/user_add.mako:11 #: rhodecode/templates/admin/users/user_edit.mako:12 -#: rhodecode/templates/base/base.mako:838 +#: rhodecode/templates/base/base.mako:839 msgid "Admin" msgstr "" -#: rhodecode/model/permission.py:89 -msgid "Protected/No Access" -msgstr "" - -#: rhodecode/model/permission.py:90 -msgid "Web merge" -msgstr "" - #: rhodecode/model/permission.py:91 -msgid "Push" +msgid "Protected/No Access" msgstr "" #: rhodecode/model/permission.py:92 +msgid "Web merge" +msgstr "" + +#: rhodecode/model/permission.py:93 +msgid "Push" +msgstr "" + +#: rhodecode/model/permission.py:94 msgid "Force Push" msgstr "" -#: rhodecode/model/permission.py:95 rhodecode/model/permission.py:109 -#: rhodecode/model/permission.py:113 rhodecode/model/permission.py:117 -#: rhodecode/model/permission.py:121 rhodecode/model/permission.py:125 -#: rhodecode/model/permission.py:129 +#: rhodecode/model/permission.py:97 rhodecode/model/permission.py:111 +#: rhodecode/model/permission.py:115 rhodecode/model/permission.py:119 +#: rhodecode/model/permission.py:123 rhodecode/model/permission.py:127 +#: rhodecode/model/permission.py:131 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:27 msgid "Disabled" msgstr "" -#: rhodecode/model/permission.py:96 +#: rhodecode/model/permission.py:98 msgid "Allowed with manual account activation" msgstr "" -#: rhodecode/model/permission.py:97 +#: rhodecode/model/permission.py:99 msgid "Allowed with automatic account activation" msgstr "" -#: rhodecode/model/permission.py:100 -msgid "Allow password recovery" -msgstr "" - -#: rhodecode/model/permission.py:101 -msgid "Hide password recovery link" -msgstr "" - #: rhodecode/model/permission.py:102 +msgid "Allow password recovery" +msgstr "" + +#: rhodecode/model/permission.py:103 +msgid "Hide password recovery link" +msgstr "" + +#: rhodecode/model/permission.py:104 msgid "Disable password recovery" msgstr "" @@ -4261,79 +4261,79 @@ msgstr "" msgid "This pull request cannot be updated because the source reference is missing." msgstr "" -#: rhodecode/model/pull_request.py:1688 +#: rhodecode/model/pull_request.py:1690 msgid "Server-side pull request merging is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1691 +#: rhodecode/model/pull_request.py:1693 msgid "This pull request is closed." msgstr "" -#: rhodecode/model/pull_request.py:1705 +#: rhodecode/model/pull_request.py:1707 msgid "Pull request merging is not supported." msgstr "" -#: rhodecode/model/pull_request.py:1722 +#: rhodecode/model/pull_request.py:1724 msgid "Target repository large files support is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1725 +#: rhodecode/model/pull_request.py:1727 msgid "Source repository large files support is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1909 rhodecode/model/scm.py:1008 +#: rhodecode/model/pull_request.py:1911 rhodecode/model/scm.py:1008 #: rhodecode/templates/admin/my_account/my_account.mako:32 -#: rhodecode/templates/base/base.mako:638 +#: rhodecode/templates/base/base.mako:639 #: rhodecode/templates/summary/components.mako:46 msgid "Bookmarks" msgstr "" -#: rhodecode/model/pull_request.py:1914 +#: rhodecode/model/pull_request.py:1916 msgid "Commit IDs" msgstr "" -#: rhodecode/model/pull_request.py:1917 +#: rhodecode/model/pull_request.py:1919 #: rhodecode/templates/summary/components.mako:22 msgid "Closed Branches" msgstr "" -#: rhodecode/model/pull_request.py:2103 +#: rhodecode/model/pull_request.py:2105 msgid "WIP marker in title prevents from accidental merge." msgstr "" -#: rhodecode/model/pull_request.py:2113 +#: rhodecode/model/pull_request.py:2115 msgid "User `{}` not allowed to perform merge." msgstr "" -#: rhodecode/model/pull_request.py:2131 +#: rhodecode/model/pull_request.py:2133 msgid "Target branch `{}` changes rejected by rule {}." msgstr "" -#: rhodecode/model/pull_request.py:2146 +#: rhodecode/model/pull_request.py:2148 msgid "Pull request reviewer approval is pending." msgstr "" -#: rhodecode/model/pull_request.py:2160 +#: rhodecode/model/pull_request.py:2162 msgid "Cannot merge, {} TODO still not resolved." msgstr "" -#: rhodecode/model/pull_request.py:2163 +#: rhodecode/model/pull_request.py:2165 msgid "Cannot merge, {} TODOs still not resolved." msgstr "" -#: rhodecode/model/pull_request.py:2218 +#: rhodecode/model/pull_request.py:2220 msgid "Merge strategy: rebase" msgstr "" -#: rhodecode/model/pull_request.py:2223 +#: rhodecode/model/pull_request.py:2225 msgid "Merge strategy: explicit merge commit" msgstr "" -#: rhodecode/model/pull_request.py:2231 -msgid "Source branch will be closed before the merge." -msgstr "" - #: rhodecode/model/pull_request.py:2233 +msgid "Source branch will be closed before the merge." +msgstr "" + +#: rhodecode/model/pull_request.py:2235 msgid "Source branch will be deleted after the merge." msgstr "" @@ -4880,129 +4880,133 @@ msgstr "" msgid "Note Comment" msgstr "" -#: rhodecode/public/js/scripts.js:39599 rhodecode/public/js/scripts.js:39987 +#: rhodecode/public/js/scripts.js:39599 rhodecode/public/js/scripts.js:39985 #: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:103 #: rhodecode/public/js/src/rhodecode/codemirror.js:730 -#: rhodecode/public/js/src/rhodecode/comments.js:267 +#: rhodecode/public/js/src/rhodecode/comments.js:265 msgid "Status Review" msgstr "" -#: rhodecode/public/js/scripts.js:39614 rhodecode/public/js/scripts.js:40004 +#: rhodecode/public/js/scripts.js:39614 rhodecode/public/js/scripts.js:40002 #: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:24 #: rhodecode/public/js/src/rhodecode/codemirror.js:745 -#: rhodecode/public/js/src/rhodecode/comments.js:284 +#: rhodecode/public/js/src/rhodecode/comments.js:282 msgid "Comment text will be set automatically based on currently selected status ({0}) ..." msgstr "" -#: rhodecode/public/js/scripts.js:39695 rhodecode/public/js/scripts.js:40213 -#: rhodecode/public/js/scripts.js:41745 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:39695 rhodecode/public/js/scripts.js:40211 +#: rhodecode/public/js/scripts.js:41883 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:49 #: rhodecode/public/js/src/rhodecode/codemirror.js:826 -#: rhodecode/public/js/src/rhodecode/comments.js:493 +#: rhodecode/public/js/src/rhodecode/comments.js:491 #: rhodecode/public/js/src/rhodecode/files.js:499 #: rhodecode/templates/files/files_browser_tree.mako:57 msgid "Loading ..." msgstr "" -#: rhodecode/public/js/scripts.js:39860 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:39859 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:123 -#: rhodecode/public/js/src/rhodecode/comments.js:140 +#: rhodecode/public/js/src/rhodecode/comments.js:139 msgid "Update Comment" msgstr "" -#: rhodecode/public/js/scripts.js:39884 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:39883 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:150 -#: rhodecode/public/js/src/rhodecode/comments.js:164 +#: rhodecode/public/js/src/rhodecode/comments.js:163 msgid "resolve comment" msgstr "" +#: rhodecode/public/js/scripts.js:40155 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:83 +#: rhodecode/public/js/src/rhodecode/comments.js:435 +msgid "Saving Draft..." +msgstr "" + #: rhodecode/public/js/scripts.js:40157 rhodecode/public/js/scripts.min.js:1 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:83 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:108 #: rhodecode/public/js/src/rhodecode/comments.js:437 -msgid "Saving Draft..." -msgstr "" - -#: rhodecode/public/js/scripts.js:40159 rhodecode/public/js/scripts.min.js:1 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:108 -#: rhodecode/public/js/src/rhodecode/comments.js:439 msgid "Submitting..." msgstr "" -#: rhodecode/public/js/scripts.js:40481 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:40479 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:131 -#: rhodecode/public/js/src/rhodecode/comments.js:761 +#: rhodecode/public/js/src/rhodecode/comments.js:759 msgid "Yes, delete comment #{0}!" msgstr "" -#: rhodecode/public/js/scripts.js:40526 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:40524 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:106 -#: rhodecode/public/js/src/rhodecode/comments.js:806 +#: rhodecode/public/js/src/rhodecode/comments.js:804 msgid "Submit {0} draft comment." msgstr "" -#: rhodecode/public/js/scripts.js:40529 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:40527 rhodecode/public/js/scripts.js:41225 +#: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:130 -#: rhodecode/public/js/src/rhodecode/comments.js:809 +#: rhodecode/public/js/src/rhodecode/comments.js:807 +#: rhodecode/public/js/src/rhodecode/comments.js:1505 msgid "Yes" msgstr "" -#: rhodecode/public/js/scripts.js:40621 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:40619 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:47 -#: rhodecode/public/js/src/rhodecode/comments.js:901 +#: rhodecode/public/js/src/rhodecode/comments.js:899 msgid "Leave a resolution comment, or click resolve button to resolve TODO comment #{0}" msgstr "" -#: rhodecode/public/js/scripts.js:40825 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:40823 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:23 -#: rhodecode/public/js/src/rhodecode/comments.js:1105 +#: rhodecode/public/js/src/rhodecode/comments.js:1103 msgid "Comment body was not changed." msgstr "" -#: rhodecode/public/js/scripts.js:41071 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41074 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:44 -#: rhodecode/public/js/src/rhodecode/comments.js:1351 +#: rhodecode/public/js/src/rhodecode/comments.js:1354 msgid "Leave a comment on file {0} line {1}." msgstr "" -#: rhodecode/public/js/scripts.js:41212 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41214 rhodecode/public/js/scripts.js:41267 +#: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:113 -#: rhodecode/public/js/src/rhodecode/comments.js:1492 +#: rhodecode/public/js/src/rhodecode/comments.js:1494 +#: rhodecode/public/js/src/rhodecode/comments.js:1547 msgid "TODO from comment {0} was fixed." msgstr "" -#: rhodecode/public/js/scripts.js:41494 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41632 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:154 #: rhodecode/public/js/src/rhodecode/files.js:248 msgid "truncated result" msgstr "" -#: rhodecode/public/js/scripts.js:41496 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41634 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:155 #: rhodecode/public/js/src/rhodecode/files.js:250 msgid "truncated results" msgstr "" -#: rhodecode/public/js/scripts.js:41505 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41643 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:60 #: rhodecode/public/js/src/rhodecode/files.js:259 msgid "No matching files" msgstr "" -#: rhodecode/public/js/scripts.js:41563 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41701 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:86 #: rhodecode/public/js/src/rhodecode/files.js:317 msgid "Selection link" msgstr "" -#: rhodecode/public/js/scripts.js:41660 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41798 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:10 #: rhodecode/public/js/src/rhodecode/files.js:414 msgid "All Authors" msgstr "" -#: rhodecode/public/js/scripts.js:41810 rhodecode/public/js/scripts.js:41813 +#: rhodecode/public/js/scripts.js:41948 rhodecode/public/js/scripts.js:41951 #: rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:38 #: rhodecode/public/js/src/rhodecode/files.js:564 @@ -5010,141 +5014,141 @@ msgstr "" msgid "File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version." msgstr "" -#: rhodecode/public/js/scripts.js:41816 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41954 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:117 #: rhodecode/public/js/src/rhodecode/files.js:570 msgid "There is an existing path `{0}` at this commit." msgstr "" -#: rhodecode/public/js/scripts.js:41819 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:41957 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:116 #: rhodecode/public/js/src/rhodecode/files.js:573 msgid "There is a later version of file tree available. Click {0} to create a file at the latest tree." msgstr "" -#: rhodecode/public/js/scripts.js:41873 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42011 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:105 #: rhodecode/public/js/src/rhodecode/followers.js:26 msgid "Stopped watching this repository" msgstr "" -#: rhodecode/public/js/scripts.js:41874 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42012 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:129 #: rhodecode/public/js/src/rhodecode/followers.js:27 -#: rhodecode/templates/base/base.mako:310 +#: rhodecode/templates/base/base.mako:311 msgid "Watch" msgstr "" -#: rhodecode/public/js/scripts.js:41877 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42015 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:102 #: rhodecode/public/js/src/rhodecode/followers.js:30 msgid "Started watching this repository" msgstr "" -#: rhodecode/public/js/scripts.js:41878 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42016 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:122 #: rhodecode/public/js/src/rhodecode/followers.js:31 -#: rhodecode/templates/base/base.mako:308 +#: rhodecode/templates/base/base.mako:309 msgid "Unwatch" msgstr "" -#: rhodecode/public/js/scripts.js:42384 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42522 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:12 #: rhodecode/public/js/src/rhodecode/pullrequests.js:185 msgid "All reviewers must vote." msgstr "" -#: rhodecode/public/js/scripts.js:42408 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42546 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:54 #: rhodecode/public/js/src/rhodecode/pullrequests.js:209 msgid "No additional review rules set." msgstr "" -#: rhodecode/public/js/scripts.js:42454 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42592 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:50 #: rhodecode/public/js/src/rhodecode/pullrequests.js:255 msgid "Loading diff ..." msgstr "" -#: rhodecode/public/js/scripts.js:42507 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42645 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:115 #: rhodecode/public/js/src/rhodecode/pullrequests.js:308 msgid "There are no commits to merge." msgstr "" -#: rhodecode/public/js/scripts.js:42579 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42717 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:128 #: rhodecode/public/js/src/rhodecode/pullrequests.js:380 msgid "User `{0}` not allowed to be a reviewer" msgstr "" -#: rhodecode/public/js/scripts.js:42585 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42723 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:127 #: rhodecode/public/js/src/rhodecode/pullrequests.js:386 msgid "User `{0}` already in reviewers/observers" msgstr "" -#: rhodecode/public/js/scripts.js:42699 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42838 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:135 #: rhodecode/public/js/src/rhodecode/pullrequests.js:501 msgid "added manually by \"{0}\"" msgstr "" -#: rhodecode/public/js/scripts.js:42704 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:42843 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:147 #: rhodecode/public/js/src/rhodecode/pullrequests.js:506 msgid "member of \"{0}\"" msgstr "" -#: rhodecode/public/js/scripts.js:42937 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:43076 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:125 #: rhodecode/public/js/src/rhodecode/pullrequests.js:739 msgid "Updating..." msgstr "" -#: rhodecode/public/js/scripts.js:42947 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:43086 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:40 #: rhodecode/public/js/src/rhodecode/pullrequests.js:749 msgid "Force updating..." msgstr "" -#: rhodecode/public/js/scripts.js:47812 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:47953 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:98 #: rhodecode/public/js/src/rhodecode/users.js:54 msgid "Show this authentication token?" msgstr "" -#: rhodecode/public/js/scripts.js:47814 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:47955 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:90 #: rhodecode/public/js/src/rhodecode/users.js:56 msgid "Show" msgstr "" -#: rhodecode/public/js/scripts.js:47850 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:47991 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:16 #: rhodecode/public/js/src/rhodecode/users.js:92 msgid "Authentication Token" msgstr "" -#: rhodecode/public/js/scripts.js:48039 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:48180 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:139 #: rhodecode/public/js/src/rhodecode.js:144 msgid "file" msgstr "" -#: rhodecode/public/js/scripts.js:48183 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:48324 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:53 #: rhodecode/public/js/src/rhodecode.js:288 msgid "Loading..." msgstr "" -#: rhodecode/public/js/scripts.js:48565 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:48706 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:136 #: rhodecode/public/js/src/rhodecode.js:670 msgid "date not in future" msgstr "" -#: rhodecode/public/js/scripts.js:48573 rhodecode/public/js/scripts.min.js:1 +#: rhodecode/public/js/scripts.js:48714 rhodecode/public/js/scripts.min.js:1 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:100 #: rhodecode/public/js/src/rhodecode.js:678 msgid "Specified expiration date" @@ -5737,8 +5741,8 @@ msgid "%s Repository group dashboard" msgstr "" #: rhodecode/templates/index_repo_group.mako:13 -#: rhodecode/templates/base/base.mako:810 #: rhodecode/templates/base/base.mako:811 +#: rhodecode/templates/base/base.mako:812 msgid "Home" msgstr "" @@ -5933,9 +5937,9 @@ msgstr "" #: rhodecode/templates/admin/admin_log_base.mako:10 #: rhodecode/templates/admin/defaults/defaults.mako:32 #: rhodecode/templates/admin/permissions/permissions_objects.mako:16 -#: rhodecode/templates/base/base.mako:658 -#: rhodecode/templates/base/base.mako:660 -#: rhodecode/templates/base/base.mako:662 +#: rhodecode/templates/base/base.mako:659 +#: rhodecode/templates/base/base.mako:661 +#: rhodecode/templates/base/base.mako:663 #: rhodecode/templates/search/search_commit.mako:8 #: rhodecode/templates/search/search_path.mako:7 msgid "Repository" @@ -6261,7 +6265,7 @@ msgid "Expires" msgstr "" #: rhodecode/templates/admin/gists/gist_new.mako:5 -#: rhodecode/templates/base/base.mako:577 +#: rhodecode/templates/base/base.mako:578 msgid "New Gist" msgstr "" @@ -6353,7 +6357,7 @@ msgstr "" #: rhodecode/templates/admin/integrations/new.mako:15 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:33 #: rhodecode/templates/admin/repos/repo_edit.mako:74 -#: rhodecode/templates/base/base.mako:120 +#: rhodecode/templates/base/base.mako:121 msgid "Integrations" msgstr "" @@ -6368,7 +6372,7 @@ msgstr "" #: rhodecode/templates/admin/settings/settings.mako:14 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:34 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:9 -#: rhodecode/templates/base/base.mako:122 +#: rhodecode/templates/base/base.mako:123 msgid "Settings" msgstr "" @@ -6469,7 +6473,7 @@ msgid "No description available" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:5 -#: rhodecode/templates/base/base.mako:622 +#: rhodecode/templates/base/base.mako:623 msgid "My account" msgstr "" @@ -6520,15 +6524,15 @@ msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:45 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:42 -#: rhodecode/templates/base/base.mako:385 -#: rhodecode/templates/base/base.mako:626 +#: rhodecode/templates/base/base.mako:386 +#: rhodecode/templates/base/base.mako:627 msgid "Pull Requests" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:46 #: rhodecode/templates/admin/permissions/permissions.mako:14 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:35 -#: rhodecode/templates/base/base.mako:118 +#: rhodecode/templates/base/base.mako:119 msgid "Permissions" msgstr "" @@ -7047,7 +7051,7 @@ msgstr "" #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:14 #: rhodecode/templates/admin/users/user_edit_advanced.mako:13 #: rhodecode/templates/base/base.mako:115 -#: rhodecode/templates/base/base.mako:136 +#: rhodecode/templates/base/base.mako:137 msgid "Repository groups" msgstr "" @@ -7062,7 +7066,7 @@ msgstr "" #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:25 #: rhodecode/templates/admin/repos/repo_add_base.mako:43 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:33 -#: rhodecode/templates/base/base.mako:671 +#: rhodecode/templates/base/base.mako:672 #: rhodecode/templates/data_table/_dt_elements.mako:217 #: rhodecode/templates/forks/fork.mako:41 msgid "Repository group" @@ -7312,7 +7316,7 @@ msgid "Import Existing Repository ?" msgstr "" #: rhodecode/templates/admin/repos/repo_add_base.mako:23 -#: rhodecode/templates/base/base.mako:332 +#: rhodecode/templates/base/base.mako:333 msgid "Clone from" msgstr "" @@ -8024,7 +8028,7 @@ msgstr "" #: rhodecode/templates/admin/settings/settings_global.mako:140 #: rhodecode/templates/admin/settings/settings_labs.mako:48 #: rhodecode/templates/admin/settings/settings_vcs.mako:13 -#: rhodecode/templates/admin/settings/settings_visual.mako:214 +#: rhodecode/templates/admin/settings/settings_visual.mako:217 msgid "Save settings" msgstr "" @@ -8550,7 +8554,7 @@ msgstr "" msgid "Clone URL templates" msgstr "" -#: rhodecode/templates/admin/settings/settings_visual.mako:181 +#: rhodecode/templates/admin/settings/settings_visual.mako:184 msgid "" "Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" " {scheme} 'http' or 'https' sent from running RhodeCode server,\n" @@ -8562,11 +8566,11 @@ msgid "" " {repoid} ID of repository, can be used to contruct clone-by-id" msgstr "" -#: rhodecode/templates/admin/settings/settings_visual.mako:196 +#: rhodecode/templates/admin/settings/settings_visual.mako:199 msgid "Custom Support Link" msgstr "" -#: rhodecode/templates/admin/settings/settings_visual.mako:204 +#: rhodecode/templates/admin/settings/settings_visual.mako:207 #, python-format msgid "" "Custom url for the support link located at the bottom.\n" @@ -8582,7 +8586,7 @@ msgstr "" #: rhodecode/templates/admin/user_groups/user_group_add.mako:13 #: rhodecode/templates/admin/users/user_edit_advanced.mako:14 #: rhodecode/templates/base/base.mako:117 -#: rhodecode/templates/base/base.mako:139 +#: rhodecode/templates/base/base.mako:140 msgid "User groups" msgstr "" @@ -9090,16 +9094,21 @@ msgstr "" msgid "Delegated Admin Panel" msgstr "" -#: rhodecode/templates/base/base.mako:119 +#: rhodecode/templates/base/base.mako:118 +#: rhodecode/templates/base/base.mako:395 +msgid "Artifacts" +msgstr "" + +#: rhodecode/templates/base/base.mako:120 msgid "Authentication" msgstr "" -#: rhodecode/templates/base/base.mako:121 +#: rhodecode/templates/base/base.mako:122 msgid "Defaults" msgstr "" -#: rhodecode/templates/base/base.mako:161 -#: rhodecode/templates/base/base.mako:201 +#: rhodecode/templates/base/base.mako:162 +#: rhodecode/templates/base/base.mako:202 #: rhodecode/templates/changeset/changeset.mako:140 #: rhodecode/templates/files/files_source_header.mako:57 #: rhodecode/templates/files/files_tree_header.mako:44 @@ -9107,40 +9116,40 @@ msgstr "" msgid "Show More" msgstr "" -#: rhodecode/templates/base/base.mako:304 -#: rhodecode/templates/base/base.mako:315 +#: rhodecode/templates/base/base.mako:305 +#: rhodecode/templates/base/base.mako:316 msgid "RSS Feed" msgstr "" -#: rhodecode/templates/base/base.mako:306 +#: rhodecode/templates/base/base.mako:307 msgid "Watch this Repository and actions on it in your personalized journal" msgstr "" -#: rhodecode/templates/base/base.mako:324 +#: rhodecode/templates/base/base.mako:325 msgid "Fork of" msgstr "" -#: rhodecode/templates/base/base.mako:341 +#: rhodecode/templates/base/base.mako:342 #, python-format msgid "Repository locked by %(user)s" msgstr "" -#: rhodecode/templates/base/base.mako:346 +#: rhodecode/templates/base/base.mako:347 msgid "Repository not locked. Pull repository to lock it." msgstr "" -#: rhodecode/templates/base/base.mako:362 +#: rhodecode/templates/base/base.mako:363 msgid "This repository has been archived. It is now read-only." msgstr "" -#: rhodecode/templates/base/base.mako:375 +#: rhodecode/templates/base/base.mako:376 #: rhodecode/templates/data_table/_dt_elements.mako:58 #: rhodecode/templates/data_table/_dt_elements.mako:59 #: rhodecode/templates/data_table/_dt_elements.mako:207 msgid "Summary" msgstr "" -#: rhodecode/templates/base/base.mako:376 +#: rhodecode/templates/base/base.mako:377 #: rhodecode/templates/data_table/_dt_elements.mako:63 #: rhodecode/templates/data_table/_dt_elements.mako:64 #: rhodecode/templates/files/file_authors_box.mako:30 @@ -9150,7 +9159,7 @@ msgstr "" msgid "Commits" msgstr "" -#: rhodecode/templates/base/base.mako:377 +#: rhodecode/templates/base/base.mako:378 #: rhodecode/templates/data_table/_dt_elements.mako:68 #: rhodecode/templates/data_table/_dt_elements.mako:69 #: rhodecode/templates/files/files.mako:15 @@ -9158,87 +9167,83 @@ msgstr "" msgid "Files" msgstr "" -#: rhodecode/templates/base/base.mako:378 +#: rhodecode/templates/base/base.mako:379 #: rhodecode/templates/bookmarks/bookmarks.mako:78 #: rhodecode/templates/branches/branches.mako:77 #: rhodecode/templates/tags/tags.mako:78 msgid "Compare" msgstr "" -#: rhodecode/templates/base/base.mako:383 +#: rhodecode/templates/base/base.mako:384 #, python-format msgid "Show Pull Requests for %s" msgstr "" -#: rhodecode/templates/base/base.mako:394 -msgid "Artifacts" -msgstr "" - -#: rhodecode/templates/base/base.mako:400 +#: rhodecode/templates/base/base.mako:401 msgid "Repository Settings" msgstr "" -#: rhodecode/templates/base/base.mako:406 +#: rhodecode/templates/base/base.mako:407 msgid "Options" msgstr "" -#: rhodecode/templates/base/base.mako:411 +#: rhodecode/templates/base/base.mako:412 msgid "Unlock Repository" msgstr "" -#: rhodecode/templates/base/base.mako:413 +#: rhodecode/templates/base/base.mako:414 msgid "Lock Repository" msgstr "" -#: rhodecode/templates/base/base.mako:466 +#: rhodecode/templates/base/base.mako:467 msgid "Group Home" msgstr "" -#: rhodecode/templates/base/base.mako:470 +#: rhodecode/templates/base/base.mako:471 msgid "You have admin right to this group, and can edit it" msgstr "" -#: rhodecode/templates/base/base.mako:470 +#: rhodecode/templates/base/base.mako:471 msgid "Group Settings" msgstr "" -#: rhodecode/templates/base/base.mako:521 +#: rhodecode/templates/base/base.mako:522 msgid "This Repository" msgstr "" -#: rhodecode/templates/base/base.mako:523 +#: rhodecode/templates/base/base.mako:524 msgid "Create Pull Request" msgstr "" -#: rhodecode/templates/base/base.mako:527 +#: rhodecode/templates/base/base.mako:528 msgid "Fork this repository" msgstr "" -#: rhodecode/templates/base/base.mako:534 +#: rhodecode/templates/base/base.mako:535 msgid "This Repository Group" msgstr "" -#: rhodecode/templates/base/base.mako:538 -#: rhodecode/templates/base/base.mako:554 -#: rhodecode/templates/base/base.mako:566 +#: rhodecode/templates/base/base.mako:539 +#: rhodecode/templates/base/base.mako:555 +#: rhodecode/templates/base/base.mako:567 msgid "New Repository" msgstr "" -#: rhodecode/templates/base/base.mako:544 -#: rhodecode/templates/base/base.mako:558 -#: rhodecode/templates/base/base.mako:572 +#: rhodecode/templates/base/base.mako:545 +#: rhodecode/templates/base/base.mako:559 +#: rhodecode/templates/base/base.mako:573 msgid "New Repository Group" msgstr "" -#: rhodecode/templates/base/base.mako:599 +#: rhodecode/templates/base/base.mako:600 msgid "Sign in" msgstr "" -#: rhodecode/templates/base/base.mako:624 +#: rhodecode/templates/base/base.mako:625 msgid "My personal group" msgstr "" -#: rhodecode/templates/base/base.mako:630 +#: rhodecode/templates/base/base.mako:631 #: rhodecode/templates/debug_style/alerts.html:5 #: rhodecode/templates/debug_style/buttons.html:5 #: rhodecode/templates/debug_style/code-block.html:6 @@ -9261,62 +9266,62 @@ msgstr "" msgid "Style" msgstr "" -#: rhodecode/templates/base/base.mako:631 +#: rhodecode/templates/base/base.mako:632 msgid "[Style]" msgstr "" -#: rhodecode/templates/base/base.mako:648 +#: rhodecode/templates/base/base.mako:649 msgid "No Bookmarks yet." msgstr "" -#: rhodecode/templates/base/base.mako:686 +#: rhodecode/templates/base/base.mako:687 msgid "Sign Out" msgstr "" -#: rhodecode/templates/base/base.mako:731 +#: rhodecode/templates/base/base.mako:732 #: rhodecode/templates/changeset/changeset_file_comment.mako:538 msgid "dismiss" msgstr "" -#: rhodecode/templates/base/base.mako:772 +#: rhodecode/templates/base/base.mako:773 msgid "search / go to..." msgstr "" -#: rhodecode/templates/base/base.mako:817 -msgid "Show activity journal" -msgstr "" - #: rhodecode/templates/base/base.mako:818 +msgid "Show activity journal" +msgstr "" + +#: rhodecode/templates/base/base.mako:819 #: rhodecode/templates/journal/journal.mako:4 #: rhodecode/templates/journal/journal.mako:14 msgid "Journal" msgstr "" -#: rhodecode/templates/base/base.mako:823 -msgid "Show Public activity journal" -msgstr "" - #: rhodecode/templates/base/base.mako:824 +msgid "Show Public activity journal" +msgstr "" + +#: rhodecode/templates/base/base.mako:825 msgid "Public journal" msgstr "" -#: rhodecode/templates/base/base.mako:830 -msgid "Show Gists" -msgstr "" - #: rhodecode/templates/base/base.mako:831 +msgid "Show Gists" +msgstr "" + +#: rhodecode/templates/base/base.mako:832 msgid "Gists" msgstr "" -#: rhodecode/templates/base/base.mako:837 +#: rhodecode/templates/base/base.mako:838 msgid "Admin settings" msgstr "" -#: rhodecode/templates/base/base.mako:1154 +#: rhodecode/templates/base/base.mako:1155 msgid "Keyboard shortcuts" msgstr "" -#: rhodecode/templates/base/base.mako:1162 +#: rhodecode/templates/base/base.mako:1163 msgid "Site-wide shortcuts" msgstr "" @@ -9357,7 +9362,7 @@ msgid "Repository Forking" msgstr "" #: rhodecode/templates/base/default_perms_box.mako:65 -msgid "Permission to create root level repository forks. When disabled, users can still fork repositories inside their own repository groups." +msgid "Permission to create repository forks. Root level forks will only work if repository creation is enabled." msgstr "" #: rhodecode/templates/base/default_perms_box.mako:70 @@ -9418,7 +9423,7 @@ msgstr "" #: rhodecode/templates/base/issue_tracker_settings.mako:300 #: rhodecode/templates/changeset/changeset_file_comment.mako:395 #: rhodecode/templates/changeset/changeset_file_comment.mako:446 -#: rhodecode/templates/data_table/_dt_elements.mako:456 +#: rhodecode/templates/data_table/_dt_elements.mako:463 #: rhodecode/templates/files/files_add.mako:59 #: rhodecode/templates/files/files_edit.mako:61 msgid "Preview" @@ -10481,11 +10486,11 @@ msgstr "" msgid "Work in progress" msgstr "" -#: rhodecode/templates/data_table/_dt_elements.mako:432 +#: rhodecode/templates/data_table/_dt_elements.mako:438 msgid "Info" msgstr "" -#: rhodecode/templates/data_table/_dt_elements.mako:473 +#: rhodecode/templates/data_table/_dt_elements.mako:480 #, python-format msgid "Parsed using %s syntax" msgstr "" @@ -10645,7 +10650,7 @@ msgid "{mention_prefix}{user} left a {co msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:54 -#: rhodecode/templates/email_templates/pull_request_comment.mako:63 +#: rhodecode/templates/email_templates/pull_request_comment.mako:62 msgid "Comment link" msgstr "" @@ -10662,26 +10667,26 @@ msgid "Commit message" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:65 -#: rhodecode/templates/email_templates/pull_request_comment.mako:77 +#: rhodecode/templates/email_templates/pull_request_comment.mako:76 msgid "File: {comment_file} on line {comment_line}" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:69 #: rhodecode/templates/email_templates/commit_comment.mako:161 -#: rhodecode/templates/email_templates/pull_request_comment.mako:81 -#: rhodecode/templates/email_templates/pull_request_comment.mako:191 +#: rhodecode/templates/email_templates/pull_request_comment.mako:80 +#: rhodecode/templates/email_templates/pull_request_comment.mako:190 msgid "`TODO` number" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:71 #: rhodecode/templates/email_templates/commit_comment.mako:163 -#: rhodecode/templates/email_templates/pull_request_comment.mako:83 -#: rhodecode/templates/email_templates/pull_request_comment.mako:193 +#: rhodecode/templates/email_templates/pull_request_comment.mako:82 +#: rhodecode/templates/email_templates/pull_request_comment.mako:192 msgid "`Note` number" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:104 -#: rhodecode/templates/email_templates/pull_request_comment.mako:124 +#: rhodecode/templates/email_templates/pull_request_comment.mako:123 msgid "left a" msgstr "" @@ -10702,18 +10707,18 @@ msgid "Commit Status" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:153 -#: rhodecode/templates/email_templates/pull_request_comment.mako:183 +#: rhodecode/templates/email_templates/pull_request_comment.mako:182 #: rhodecode/templates/search/search_path.mako:9 msgid "File" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:154 -#: rhodecode/templates/email_templates/pull_request_comment.mako:184 +#: rhodecode/templates/email_templates/pull_request_comment.mako:183 msgid "`{comment_file}` on line {comment_line}" msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:173 -#: rhodecode/templates/email_templates/pull_request_comment.mako:203 +#: rhodecode/templates/email_templates/pull_request_comment.mako:202 msgid "Reply" msgstr "" @@ -10729,35 +10734,35 @@ msgstr "" msgid "{mention_prefix}{user} left a {comment_type} on pull request !{pr_id}: \"{pr_title}\"" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:65 +#: rhodecode/templates/email_templates/pull_request_comment.mako:64 #: rhodecode/templates/hovercards/hovercard_pull_request.mako:24 msgid "Pull Request" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:67 +#: rhodecode/templates/email_templates/pull_request_comment.mako:66 #: rhodecode/templates/email_templates/pull_request_review.mako:45 #: rhodecode/templates/email_templates/pull_request_update.mako:41 msgid "Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:70 +#: rhodecode/templates/email_templates/pull_request_comment.mako:69 msgid "{user} submitted pull request !{pr_id} status: *{status}*" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:73 +#: rhodecode/templates/email_templates/pull_request_comment.mako:72 msgid "{user} submitted pull request !{pr_id} status: *{status} and closed*" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:127 +#: rhodecode/templates/email_templates/pull_request_comment.mako:126 msgid "{comment_type} on file `{comment_file}` in pull request." msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:129 +#: rhodecode/templates/email_templates/pull_request_comment.mako:128 msgid "{comment_type} on pull request." msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:134 -#: rhodecode/templates/email_templates/pull_request_comment.mako:164 +#: rhodecode/templates/email_templates/pull_request_comment.mako:133 +#: rhodecode/templates/email_templates/pull_request_comment.mako:163 #: rhodecode/templates/email_templates/pull_request_review.mako:100 #: rhodecode/templates/email_templates/pull_request_review.mako:116 #: rhodecode/templates/email_templates/pull_request_update.mako:104 @@ -10765,26 +10770,26 @@ msgstr "" msgid "Pull request" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:153 +#: rhodecode/templates/email_templates/pull_request_comment.mako:152 msgid "Review Status" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:156 +#: rhodecode/templates/email_templates/pull_request_comment.mako:155 msgid "Closed pull request with status" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:158 +#: rhodecode/templates/email_templates/pull_request_comment.mako:157 msgid "Submitted review status" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:173 +#: rhodecode/templates/email_templates/pull_request_comment.mako:172 #: rhodecode/templates/email_templates/pull_request_review.mako:125 #: rhodecode/templates/email_templates/pull_request_update.mako:130 msgid "Commit Flow" msgstr "" -#: rhodecode/templates/email_templates/pull_request_comment.mako:175 -#: rhodecode/templates/email_templates/pull_request_comment.mako:177 +#: rhodecode/templates/email_templates/pull_request_comment.mako:174 +#: rhodecode/templates/email_templates/pull_request_comment.mako:176 #: rhodecode/templates/email_templates/pull_request_review.mako:127 #: rhodecode/templates/email_templates/pull_request_review.mako:129 #: rhodecode/templates/email_templates/pull_request_update.mako:132 @@ -11447,12 +11452,12 @@ msgstr "" msgid "In pull request description" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:838 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:857 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:840 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:860 msgid "No Ticket data found." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:843 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:845 msgid "In commit messages" msgstr "" diff --git a/rhodecode/integrations/types/base.py b/rhodecode/integrations/types/base.py --- a/rhodecode/integrations/types/base.py +++ b/rhodecode/integrations/types/base.py @@ -131,7 +131,7 @@ class IntegrationTypeBase(object): :param event: :return: bool """ - allowed_events = self.settings['events'] + allowed_events = self.settings.get('events') or [] if event.name not in allowed_events: log.debug('event ignored: %r event %s not in allowed set of events %s', event, event.name, allowed_events) diff --git a/rhodecode/lib/celerylib/tasks.py b/rhodecode/lib/celerylib/tasks.py --- a/rhodecode/lib/celerylib/tasks.py +++ b/rhodecode/lib/celerylib/tasks.py @@ -38,6 +38,7 @@ from rhodecode.lib import hooks_base from rhodecode.lib.utils2 import safe_int, str2bool, aslist from rhodecode.model.db import ( Session, IntegrityError, true, Repository, RepoGroup, User) +from rhodecode.model.permission import PermissionModel @async_task(ignore_result=True, base=RequestContextTask) @@ -216,6 +217,9 @@ def create_repo(form_data, cur_user): repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id)) Session().commit() + + PermissionModel().trigger_permission_flush() + except Exception as e: log.warning('Exception occurred when creating repository, ' 'doing cleanup...', exc_info=True) diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -35,7 +35,7 @@ import urllib import urlobject import uuid import getpass -from functools import update_wrapper, partial +from functools import update_wrapper, partial, wraps import pygments.lexers import sqlalchemy @@ -1038,16 +1038,17 @@ class CachedProperty(object): """ Lazy Attributes. With option to invalidate the cache by running a method - class Foo(): + >>> class Foo(object): + ... + ... @CachedProperty + ... def heavy_func(self): + ... return 'super-calculation' + ... + ... foo = Foo() + ... foo.heavy_func() # first computation + ... foo.heavy_func() # fetch from cache + ... foo._invalidate_prop_cache('heavy_func') - @CachedProperty - def heavy_func(): - return 'super-calculation' - - foo = Foo() - foo.heavy_func() # first computions - foo.heavy_func() # fetch from cache - foo._invalidate_prop_cache('heavy_func') # at this point calling foo.heavy_func() will be re-computed """ @@ -1072,3 +1073,76 @@ class CachedProperty(object): def _invalidate_prop_cache(self, inst, name): inst.__dict__.pop(name, None) + + +def retry(func=None, exception=Exception, n_tries=5, delay=5, backoff=1, logger=True): + """ + Retry decorator with exponential backoff. + + Parameters + ---------- + func : typing.Callable, optional + Callable on which the decorator is applied, by default None + exception : Exception or tuple of Exceptions, optional + Exception(s) that invoke retry, by default Exception + n_tries : int, optional + Number of tries before giving up, by default 5 + delay : int, optional + Initial delay between retries in seconds, by default 5 + backoff : int, optional + Backoff multiplier e.g. value of 2 will double the delay, by default 1 + logger : bool, optional + Option to log or print, by default False + + Returns + ------- + typing.Callable + Decorated callable that calls itself when exception(s) occur. + + Examples + -------- + >>> import random + >>> @retry(exception=Exception, n_tries=3) + ... def test_random(text): + ... x = random.random() + ... if x < 0.5: + ... raise Exception("Fail") + ... else: + ... print("Success: ", text) + >>> test_random("It works!") + """ + + if func is None: + return partial( + retry, + exception=exception, + n_tries=n_tries, + delay=delay, + backoff=backoff, + logger=logger, + ) + + @wraps(func) + def wrapper(*args, **kwargs): + _n_tries, n_delay = n_tries, delay + log = logging.getLogger('rhodecode.retry') + + while _n_tries > 1: + try: + return func(*args, **kwargs) + except exception as e: + e_details = repr(e) + msg = "Exception on calling func {func}: {e}, " \ + "Retrying in {n_delay} seconds..."\ + .format(func=func, e=e_details, n_delay=n_delay) + if logger: + log.warning(msg) + else: + print(msg) + time.sleep(n_delay) + _n_tries -= 1 + n_delay *= backoff + + return func(*args, **kwargs) + + return wrapper diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py --- a/rhodecode/lib/vcs/backends/base.py +++ b/rhodecode/lib/vcs/backends/base.py @@ -311,6 +311,7 @@ class BaseRepository(object): DEFAULT_CONTACT = u"Unknown" DEFAULT_DESCRIPTION = u"unknown" EMPTY_COMMIT_ID = '0' * 40 + COMMIT_ID_PAT = re.compile(r'[0-9a-fA-F]{40}') path = None diff --git a/rhodecode/lib/vcs/backends/git/repository.py b/rhodecode/lib/vcs/backends/git/repository.py --- a/rhodecode/lib/vcs/backends/git/repository.py +++ b/rhodecode/lib/vcs/backends/git/repository.py @@ -618,7 +618,7 @@ class GitRepository(BaseRepository): else: output, __ = self.run_git_command( ['merge-base', commit_id1, commit_id2]) - ancestor_id = re.findall(r'[0-9a-fA-F]{40}', output)[0] + ancestor_id = self.COMMIT_ID_PAT.findall(output)[0] log.debug('Found common ancestor with sha: %s', ancestor_id) @@ -642,7 +642,7 @@ class GitRepository(BaseRepository): '%s..%s' % (commit_id1, commit_id2)]) commits = [ repo1.get_commit(commit_id=commit_id, pre_load=pre_load) - for commit_id in re.findall(r'[0-9a-fA-F]{40}', output)] + for commit_id in self.COMMIT_ID_PAT.findall(output)] return commits diff --git a/rhodecode/model/changeset_status.py b/rhodecode/model/changeset_status.py --- a/rhodecode/model/changeset_status.py +++ b/rhodecode/model/changeset_status.py @@ -354,7 +354,7 @@ class ChangesetStatusModel(BaseModel): Session().add(new_status) return new_statuses - def aggregate_votes_by_user(self, commit_statuses, reviewers_data): + def aggregate_votes_by_user(self, commit_statuses, reviewers_data, user=None): commit_statuses_map = collections.defaultdict(list) for st in commit_statuses: @@ -368,6 +368,10 @@ class ChangesetStatusModel(BaseModel): for obj in reviewers_data: if not obj.user: continue + if user and obj.user.username != user.username: + # single user filter + continue + statuses = commit_statuses_map.get(obj.user.username, None) if statuses: status_groups = itertools.groupby( @@ -376,16 +380,19 @@ class ChangesetStatusModel(BaseModel): reviewers.append((obj, obj.user, obj.reasons, obj.mandatory, statuses)) - return reviewers + if user: + return reviewers[0] if reviewers else reviewers + else: + return reviewers - def reviewers_statuses(self, pull_request): + def reviewers_statuses(self, pull_request, user=None): _commit_statuses = self.get_statuses( pull_request.source_repo, pull_request=pull_request, with_revisions=True) reviewers = pull_request.get_pull_request_reviewers( role=PullRequestReviewers.ROLE_REVIEWER) - return self.aggregate_votes_by_user(_commit_statuses, reviewers) + return self.aggregate_votes_by_user(_commit_statuses, reviewers, user=user) def calculated_review_status(self, pull_request): """ diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -41,10 +41,10 @@ from sqlalchemy import ( Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column, Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary, Text, Float, PickleType, BigInteger) -from sqlalchemy.sql.expression import true, false, case +from sqlalchemy.sql.expression import true, false, case, null from sqlalchemy.sql.functions import coalesce, count # pragma: no cover from sqlalchemy.orm import ( - relationship, joinedload, class_mapper, validates, aliased) + relationship, lazyload, joinedload, class_mapper, validates, aliased) from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.exc import IntegrityError # pragma: no cover @@ -911,7 +911,7 @@ class User(Base, BaseModel): return {} try: - return json.loads(self._user_data) + return json.loads(self._user_data) or {} except TypeError: return {} @@ -4062,7 +4062,7 @@ class _SetState(object): return self def __exit__(self, exc_type, exc_val, exc_tb): - if exc_val is not None: + if exc_val is not None or exc_type is not None: log.error(traceback.format_exc(exc_tb)) return None @@ -4479,9 +4479,9 @@ class PullRequest(Base, _PullRequestBase from rhodecode.model.changeset_status import ChangesetStatusModel return ChangesetStatusModel().calculated_review_status(self) - def reviewers_statuses(self): + def reviewers_statuses(self, user=None): from rhodecode.model.changeset_status import ChangesetStatusModel - return ChangesetStatusModel().reviewers_statuses(self) + return ChangesetStatusModel().reviewers_statuses(self, user=user) def get_pull_request_reviewers(self, role=None): qry = PullRequestReviewers.query()\ diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py --- a/rhodecode/model/pull_request.py +++ b/rhodecode/model/pull_request.py @@ -56,7 +56,7 @@ from rhodecode.model import BaseModel from rhodecode.model.changeset_status import ChangesetStatusModel from rhodecode.model.comment import CommentsModel from rhodecode.model.db import ( - or_, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, + aliased, null, lazyload, and_, or_, func, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User) from rhodecode.model.meta import Session from rhodecode.model.notification import NotificationModel, \ @@ -319,7 +319,7 @@ class PullRequestModel(BaseModel): if search_q: like_expression = u'%{}%'.format(safe_unicode(search_q)) - q = q.join(User) + q = q.join(User, User.user_id == PullRequest.user_id) q = q.filter(or_( cast(PullRequest.pull_request_id, String).ilike(like_expression), User.username.ilike(like_expression), @@ -405,36 +405,30 @@ class PullRequestModel(BaseModel): return pull_requests - def count_awaiting_review(self, repo_name, search_q=None, source=False, statuses=None, - opened_by=None): + def count_awaiting_review(self, repo_name, search_q=None, statuses=None): """ Count the number of pull requests for a specific repository that are awaiting review. :param repo_name: target or source repo :param search_q: filter by text - :param source: boolean flag to specify if repo_name refers to source :param statuses: list of pull request statuses - :param opened_by: author user of the pull request :returns: int number of pull requests """ pull_requests = self.get_awaiting_review( - repo_name, search_q=search_q, source=source, statuses=statuses, opened_by=opened_by) + repo_name, search_q=search_q, statuses=statuses) return len(pull_requests) - def get_awaiting_review(self, repo_name, search_q=None, source=False, statuses=None, - opened_by=None, offset=0, length=None, - order_by=None, order_dir='desc'): + def get_awaiting_review(self, repo_name, search_q=None, statuses=None, + offset=0, length=None, order_by=None, order_dir='desc'): """ Get all pull requests for a specific repository that are awaiting review. :param repo_name: target or source repo :param search_q: filter by text - :param source: boolean flag to specify if repo_name refers to source :param statuses: list of pull request statuses - :param opened_by: author user of the pull request :param offset: pagination offset :param length: length of returned list :param order_by: order of the returned list @@ -442,8 +436,8 @@ class PullRequestModel(BaseModel): :returns: list of pull requests """ pull_requests = self.get_all( - repo_name, search_q=search_q, source=source, statuses=statuses, - opened_by=opened_by, order_by=order_by, order_dir=order_dir) + repo_name, search_q=search_q, statuses=statuses, + order_by=order_by, order_dir=order_dir) _filtered_pull_requests = [] for pr in pull_requests: @@ -456,68 +450,117 @@ class PullRequestModel(BaseModel): else: return _filtered_pull_requests - def count_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None, - opened_by=None, user_id=None): + def _prepare_awaiting_my_review_review_query( + self, repo_name, user_id, search_q=None, statuses=None, + order_by=None, order_dir='desc'): + + for_review_statuses = [ + ChangesetStatus.STATUS_UNDER_REVIEW, ChangesetStatus.STATUS_NOT_REVIEWED + ] + + pull_request_alias = aliased(PullRequest) + status_alias = aliased(ChangesetStatus) + reviewers_alias = aliased(PullRequestReviewers) + repo_alias = aliased(Repository) + + last_ver_subq = Session()\ + .query(func.min(ChangesetStatus.version)) \ + .filter(ChangesetStatus.pull_request_id == reviewers_alias.pull_request_id)\ + .filter(ChangesetStatus.user_id == reviewers_alias.user_id) \ + .subquery() + + q = Session().query(pull_request_alias) \ + .options(lazyload(pull_request_alias.author)) \ + .join(reviewers_alias, + reviewers_alias.pull_request_id == pull_request_alias.pull_request_id) \ + .join(repo_alias, + repo_alias.repo_id == pull_request_alias.target_repo_id) \ + .outerjoin(status_alias, + and_(status_alias.user_id == reviewers_alias.user_id, + status_alias.pull_request_id == reviewers_alias.pull_request_id)) \ + .filter(or_(status_alias.version == null(), + status_alias.version == last_ver_subq)) \ + .filter(reviewers_alias.user_id == user_id) \ + .filter(repo_alias.repo_name == repo_name) \ + .filter(or_(status_alias.status == null(), status_alias.status.in_(for_review_statuses))) \ + .group_by(pull_request_alias) + + # closed,opened + if statuses: + q = q.filter(pull_request_alias.status.in_(statuses)) + + if search_q: + like_expression = u'%{}%'.format(safe_unicode(search_q)) + q = q.join(User, User.user_id == pull_request_alias.user_id) + q = q.filter(or_( + cast(pull_request_alias.pull_request_id, String).ilike(like_expression), + User.username.ilike(like_expression), + pull_request_alias.title.ilike(like_expression), + pull_request_alias.description.ilike(like_expression), + )) + + if order_by: + order_map = { + 'name_raw': pull_request_alias.pull_request_id, + 'title': pull_request_alias.title, + 'updated_on_raw': pull_request_alias.updated_on, + 'target_repo': pull_request_alias.target_repo_id + } + if order_dir == 'asc': + q = q.order_by(order_map[order_by].asc()) + else: + q = q.order_by(order_map[order_by].desc()) + + return q + + def count_awaiting_my_review(self, repo_name, user_id, search_q=None, statuses=None): """ Count the number of pull requests for a specific repository that are awaiting review from a specific user. :param repo_name: target or source repo + :param user_id: reviewer user of the pull request :param search_q: filter by text - :param source: boolean flag to specify if repo_name refers to source :param statuses: list of pull request statuses - :param opened_by: author user of the pull request - :param user_id: reviewer user of the pull request :returns: int number of pull requests """ - pull_requests = self.get_awaiting_my_review( - repo_name, search_q=search_q, source=source, statuses=statuses, - opened_by=opened_by, user_id=user_id) + q = self._prepare_awaiting_my_review_review_query( + repo_name, user_id, search_q=search_q, statuses=statuses) + return q.count() - return len(pull_requests) - - def get_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None, - opened_by=None, user_id=None, offset=0, - length=None, order_by=None, order_dir='desc'): + def get_awaiting_my_review(self, repo_name, user_id, search_q=None, statuses=None, + offset=0, length=None, order_by=None, order_dir='desc'): """ Get all pull requests for a specific repository that are awaiting review from a specific user. :param repo_name: target or source repo + :param user_id: reviewer user of the pull request :param search_q: filter by text - :param source: boolean flag to specify if repo_name refers to source :param statuses: list of pull request statuses - :param opened_by: author user of the pull request - :param user_id: reviewer user of the pull request :param offset: pagination offset :param length: length of returned list :param order_by: order of the returned list :param order_dir: 'asc' or 'desc' ordering direction :returns: list of pull requests """ - pull_requests = self.get_all( - repo_name, search_q=search_q, source=source, statuses=statuses, - opened_by=opened_by, order_by=order_by, order_dir=order_dir) - _my = PullRequestModel().get_not_reviewed(user_id) - my_participation = [] - for pr in pull_requests: - if pr in _my: - my_participation.append(pr) - _filtered_pull_requests = my_participation + q = self._prepare_awaiting_my_review_review_query( + repo_name, user_id, search_q=search_q, statuses=statuses, + order_by=order_by, order_dir=order_dir) + if length: - return _filtered_pull_requests[offset:offset+length] + pull_requests = q.limit(length).offset(offset).all() else: - return _filtered_pull_requests + pull_requests = q.all() + + return pull_requests - def get_not_reviewed(self, user_id): - return [ - x.pull_request for x in PullRequestReviewers.query().filter( - PullRequestReviewers.user_id == user_id).all() - ] - - def _prepare_participating_query(self, user_id=None, statuses=None, query='', - order_by=None, order_dir='desc'): + def _prepare_im_participating_query(self, user_id=None, statuses=None, query='', + order_by=None, order_dir='desc'): + """ + return a query of pull-requests user is an creator, or he's added as a reviewer + """ q = PullRequest.query() if user_id: reviewers_subquery = Session().query( @@ -535,7 +578,7 @@ class PullRequestModel(BaseModel): if query: like_expression = u'%{}%'.format(safe_unicode(query)) - q = q.join(User) + q = q.join(User, User.user_id == PullRequest.user_id) q = q.filter(or_( cast(PullRequest.pull_request_id, String).ilike(like_expression), User.username.ilike(like_expression), @@ -557,17 +600,97 @@ class PullRequestModel(BaseModel): return q def count_im_participating_in(self, user_id=None, statuses=None, query=''): - q = self._prepare_participating_query(user_id, statuses=statuses, query=query) + q = self._prepare_im_participating_query(user_id, statuses=statuses, query=query) return q.count() def get_im_participating_in( self, user_id=None, statuses=None, query='', offset=0, length=None, order_by=None, order_dir='desc'): """ - Get all Pull requests that i'm participating in, or i have opened + Get all Pull requests that i'm participating in as a reviewer, or i have opened """ - q = self._prepare_participating_query( + q = self._prepare_im_participating_query( + user_id, statuses=statuses, query=query, order_by=order_by, + order_dir=order_dir) + + if length: + pull_requests = q.limit(length).offset(offset).all() + else: + pull_requests = q.all() + + return pull_requests + + def _prepare_participating_in_for_review_query( + self, user_id, statuses=None, query='', order_by=None, order_dir='desc'): + + for_review_statuses = [ + ChangesetStatus.STATUS_UNDER_REVIEW, ChangesetStatus.STATUS_NOT_REVIEWED + ] + + pull_request_alias = aliased(PullRequest) + status_alias = aliased(ChangesetStatus) + reviewers_alias = aliased(PullRequestReviewers) + + last_ver_subq = Session()\ + .query(func.min(ChangesetStatus.version)) \ + .filter(ChangesetStatus.pull_request_id == reviewers_alias.pull_request_id)\ + .filter(ChangesetStatus.user_id == reviewers_alias.user_id) \ + .subquery() + + q = Session().query(pull_request_alias) \ + .options(lazyload(pull_request_alias.author)) \ + .join(reviewers_alias, + reviewers_alias.pull_request_id == pull_request_alias.pull_request_id) \ + .outerjoin(status_alias, + and_(status_alias.user_id == reviewers_alias.user_id, + status_alias.pull_request_id == reviewers_alias.pull_request_id)) \ + .filter(or_(status_alias.version == null(), + status_alias.version == last_ver_subq)) \ + .filter(reviewers_alias.user_id == user_id) \ + .filter(or_(status_alias.status == null(), status_alias.status.in_(for_review_statuses))) \ + .group_by(pull_request_alias) + + # closed,opened + if statuses: + q = q.filter(pull_request_alias.status.in_(statuses)) + + if query: + like_expression = u'%{}%'.format(safe_unicode(query)) + q = q.join(User, User.user_id == pull_request_alias.user_id) + q = q.filter(or_( + cast(pull_request_alias.pull_request_id, String).ilike(like_expression), + User.username.ilike(like_expression), + pull_request_alias.title.ilike(like_expression), + pull_request_alias.description.ilike(like_expression), + )) + + if order_by: + order_map = { + 'name_raw': pull_request_alias.pull_request_id, + 'title': pull_request_alias.title, + 'updated_on_raw': pull_request_alias.updated_on, + 'target_repo': pull_request_alias.target_repo_id + } + if order_dir == 'asc': + q = q.order_by(order_map[order_by].asc()) + else: + q = q.order_by(order_map[order_by].desc()) + + return q + + def count_im_participating_in_for_review(self, user_id, statuses=None, query=''): + q = self._prepare_participating_in_for_review_query(user_id, statuses=statuses, query=query) + return q.count() + + def get_im_participating_in_for_review( + self, user_id, statuses=None, query='', offset=0, + length=None, order_by=None, order_dir='desc'): + """ + Get all Pull requests that needs user approval or rejection + """ + + q = self._prepare_participating_in_for_review_query( user_id, statuses=statuses, query=query, order_by=order_by, order_dir=order_dir) diff --git a/rhodecode/public/css/buttons.less b/rhodecode/public/css/buttons.less --- a/rhodecode/public/css/buttons.less +++ b/rhodecode/public/css/buttons.less @@ -618,13 +618,13 @@ input[type="reset"] { text-align: right; li { - - + list-style: none; + text-align: right; + display: inline-block; } - li.active { - background-color: @grey6; - .border ( @border-thickness, @grey4 ); + a.active { + border: 2px solid @rcblue; } } diff --git a/rhodecode/public/css/panels.less b/rhodecode/public/css/panels.less --- a/rhodecode/public/css/panels.less +++ b/rhodecode/public/css/panels.less @@ -44,7 +44,7 @@ padding: @panel-padding; &.panel-body-min-height { - min-height: 150px + min-height: 200px } } diff --git a/rhodecode/public/js/src/rhodecode/comments.js b/rhodecode/public/js/src/rhodecode/comments.js --- a/rhodecode/public/js/src/rhodecode/comments.js +++ b/rhodecode/public/js/src/rhodecode/comments.js @@ -791,6 +791,11 @@ var CommentsController = function() { refreshDraftComments() } + if (window.refreshAllComments !== undefined) { + // if we have this handler, run it, and refresh all comments boxes + refreshAllComments() + } + return false; }; diff --git a/rhodecode/templates/admin/artifacts/artifacts.mako b/rhodecode/templates/admin/artifacts/artifacts.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/artifacts/artifacts.mako @@ -0,0 +1,39 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.mako"/> + +<%def name="title()"> + ${_('Artifacts Admin')} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="breadcrumbs_links()"> + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='admin')} + + +<%def name="menu_bar_subnav()"> + ${self.admin_menu(active='artifacts')} + + +<%def name="main()"> + +
+ +
+
+

${_('Artifacts Administration.')}

+
+
+

${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='sales@rhodecode.com')|n}

+ +
+
+ +
+ + + + diff --git a/rhodecode/templates/admin/gists/gist_index.mako b/rhodecode/templates/admin/gists/gist_index.mako --- a/rhodecode/templates/admin/gists/gist_index.mako +++ b/rhodecode/templates/admin/gists/gist_index.mako @@ -27,13 +27,13 @@ diff --git a/rhodecode/templates/admin/gists/gist_new.mako b/rhodecode/templates/admin/gists/gist_new.mako --- a/rhodecode/templates/admin/gists/gist_new.mako +++ b/rhodecode/templates/admin/gists/gist_new.mako @@ -65,11 +65,11 @@
- + ${_('Private Gist')} - + ${_('Public Gist')}
@@ -99,5 +99,14 @@ setCodeMirrorModeFromInput( modes_select, filename_selector, myCodeMirror, null); + setGistId = function(gistType) { + if (gistType === 'private') { + $('#gistid').removeAttr('disabled'); + } + else { + $('#gistid').val(''); + $('#gistid').attr('disabled', 'disabled') + } + } diff --git a/rhodecode/templates/admin/my_account/my_account_bookmarks.mako b/rhodecode/templates/admin/my_account/my_account_bookmarks.mako --- a/rhodecode/templates/admin/my_account/my_account_bookmarks.mako +++ b/rhodecode/templates/admin/my_account/my_account_bookmarks.mako @@ -26,50 +26,41 @@ -

- ${_('Server URL is available as ${server_url} variable. E.g. Redirect url: ${server_url}/_admin/exception_tracker')} -

-
+
- +

+ ${_('Server URL is available as ${server_url} variable. E.g. Redirect url: ${server_url}/_admin/exception_tracker')} +

-
+
+
+ +
+ % if repo: -
- -
${dt.repo_name(name=repo.repo_name, rtype=repo.repo_type,rstate=None,private=None,archived=False,fork_of=False)} ${h.hidden('bookmark_repo', repo.repo_id)} % elif repo_group: -
- -
${dt.repo_group_name(repo_group.group_name)} ${h.hidden('bookmark_repo_group', repo_group.group_id)} % else: -
- +
+ ${h.hidden('bookmark_repo', class_='bookmark_repo')} +

${_('Available as ${repo_url} e.g. Redirect url: ${repo_url}/changelog')}

- ${h.hidden('bookmark_repo', class_='bookmark_repo')} - OR - ${h.hidden('bookmark_repo_group', class_='bookmark_repo_group')} +
+ ${h.hidden('bookmark_repo_group', class_='bookmark_repo_group')} +

${_('Available as ${repo_group_url} e.g. Redirect url: ${repo_group_url}')}

+
+ % endif
-

- % if repo: - ${_('Available as ${repo_url} e.g. Redirect url: ${repo_url}/changelog')} - % elif repo_group: - ${_('Available as ${repo_group_url} e.g. Redirect url: ${repo_group_url}')} - % else: - ${_('Available as full url variables in redirect url. i.e: ${repo_url}, ${repo_group_url}.')} - % endif -

diff --git a/rhodecode/templates/admin/my_account/my_account_pullrequests.mako b/rhodecode/templates/admin/my_account/my_account_pullrequests.mako --- a/rhodecode/templates/admin/my_account/my_account_pullrequests.mako +++ b/rhodecode/templates/admin/my_account/my_account_pullrequests.mako @@ -1,17 +1,29 @@ <%namespace name="base" file="/base/base.mako"/>
-
-
- <% - selected_filter = 'all' - if c.closed: - selected_filter = 'all_closed' - %> +
+

${_('Pull Requests You Participate In')}

+
+ -
+
-
-
-

${_('Pull Requests You Participate In')}

-
-
@@ -52,6 +58,7 @@ "url": "${h.route_path('my_account_pullrequests_data')}", "data": function (d) { d.closed = "${c.closed}"; + d.awaiting_my_review = "${c.awaiting_my_review}"; }, "dataSrc": function (json) { return json.data; @@ -60,13 +67,19 @@ dom: 'rtp', pageLength: ${c.visual.dashboard_items}, - order: [[1, "desc"]], + order: [[2, "desc"]], columns: [ { data: { "_": "status", "sort": "status" - }, title: "", className: "td-status", orderable: false + }, title: "PR", className: "td-status", orderable: false + }, + { + data: { + "_": "my_status", + "sort": "status" + }, title: "You", className: "td-status", orderable: false }, { data: { diff --git a/rhodecode/templates/admin/repos/repo_edit_advanced.mako b/rhodecode/templates/admin/repos/repo_edit_advanced.mako --- a/rhodecode/templates/admin/repos/repo_edit_advanced.mako +++ b/rhodecode/templates/admin/repos/repo_edit_advanced.mako @@ -171,7 +171,7 @@ This repository is already archived. Only super-admin users can un-archive this repository. % else: @@ -180,6 +180,9 @@
+ + ${_('This action is irreversible')} ! +
${_('Archiving the repository will make it entirely read-only. The repository cannot be committed to.' 'It is hidden from the search results and dashboard. ')}
diff --git a/rhodecode/templates/compare/compare_commits.mako b/rhodecode/templates/compare/compare_commits.mako --- a/rhodecode/templates/compare/compare_commits.mako +++ b/rhodecode/templates/compare/compare_commits.mako @@ -63,7 +63,7 @@ %endfor - + ${_ungettext('{} commit hidden, click expand to show them.', '{} commits hidden, click expand to show them.', len(c.commit_ranges)).format(len(c.commit_ranges))} diff --git a/rhodecode/templates/email_templates/pull_request_comment.mako b/rhodecode/templates/email_templates/pull_request_comment.mako --- a/rhodecode/templates/email_templates/pull_request_comment.mako +++ b/rhodecode/templates/email_templates/pull_request_comment.mako @@ -171,9 +171,9 @@ data = { ${_('Commit Flow')}: - ${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)} ${_('of')} ${data['source_repo_url']} + ${data['source_ref_type']}:${pull_request.source_ref_parts.name} ${_('of')} ${data['source_repo_url']} → - ${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)} ${_('of')} ${data['target_repo_url']} + ${data['target_ref_type']}:${pull_request.target_ref_parts.name} ${_('of')} ${data['target_repo_url']} diff --git a/rhodecode/templates/email_templates/pull_request_review.mako b/rhodecode/templates/email_templates/pull_request_review.mako --- a/rhodecode/templates/email_templates/pull_request_review.mako +++ b/rhodecode/templates/email_templates/pull_request_review.mako @@ -124,9 +124,9 @@ data = { ${_('Commit Flow')}: - ${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)} ${_('of')} ${data['source_repo_url']} + ${data['source_ref_type']}:${pull_request.source_ref_parts.name} ${_('of')} ${data['source_repo_url']} → - ${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)} ${_('of')} ${data['target_repo_url']} + ${data['target_ref_type']}:${pull_request.target_ref_parts.name} ${_('of')} ${data['target_repo_url']} diff --git a/rhodecode/templates/email_templates/pull_request_update.mako b/rhodecode/templates/email_templates/pull_request_update.mako --- a/rhodecode/templates/email_templates/pull_request_update.mako +++ b/rhodecode/templates/email_templates/pull_request_update.mako @@ -129,9 +129,9 @@ data = { ${_('Commit Flow')}: - ${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)} ${_('of')} ${data['source_repo_url']} + ${data['source_ref_type']}:${pull_request.source_ref_parts.name} ${_('of')} ${data['source_repo_url']} → - ${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)} ${_('of')} ${data['target_repo_url']} + ${data['target_ref_type']}:${pull_request.target_ref_parts.name} ${_('of')} ${data['target_repo_url']} diff --git a/rhodecode/templates/pullrequests/pullrequest_show.mako b/rhodecode/templates/pullrequests/pullrequest_show.mako --- a/rhodecode/templates/pullrequests/pullrequest_show.mako +++ b/rhodecode/templates/pullrequests/pullrequest_show.mako @@ -143,9 +143,9 @@ ## pull url
  • %if h.is_hg(c.pull_request.source_repo): - <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %> + <% clone_url = u'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %> %elif h.is_git(c.pull_request.source_repo): - <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %> + <% clone_url = u'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %> %endif ${_('Pull changes from source')}: @@ -560,7 +560,7 @@