reviewers: add repo review rule models and expose default
reviewers route for pull requests via ajax, refs #1131
This commit is contained in:
parent
f28e511072
commit
9b38ba8c8f
15 changed files with 3994 additions and 34 deletions
|
|
@ -51,7 +51,7 @@ PYRAMID_SETTINGS = {}
|
|||
EXTENSIONS = {}
|
||||
|
||||
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
|
||||
__dbversion__ = 58 # defines current db version for migrations
|
||||
__dbversion__ = 59 # defines current db version for migrations
|
||||
__platform__ = platform.system()
|
||||
__license__ = 'AGPLv3, and Commercial License'
|
||||
__author__ = 'RhodeCode GmbH'
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ def make_map(config):
|
|||
rmap.connect('user_autocomplete_data', '/_users', controller='home',
|
||||
action='user_autocomplete_data', jsroute=True)
|
||||
rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
|
||||
action='user_group_autocomplete_data')
|
||||
action='user_group_autocomplete_data', jsroute=True)
|
||||
|
||||
rmap.connect(
|
||||
'user_profile', '/_profiles/{username}', controller='users',
|
||||
|
|
@ -699,6 +699,9 @@ def make_map(config):
|
|||
rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
|
||||
controller='summary', action='repo_refs_changelog_data',
|
||||
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
|
||||
rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
|
||||
controller='summary', action='repo_default_reviewers_data',
|
||||
jsroute=True, requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
|
||||
controller='changeset', revision='tip', jsroute=True,
|
||||
|
|
@ -824,6 +827,10 @@ def make_map(config):
|
|||
controller='admin/repos', action='repo_delete_svn_pattern',
|
||||
conditions={'method': ['DELETE'], 'function': check_repo},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
|
||||
controller='admin/repos', action='repo_settings_pullrequest',
|
||||
conditions={'method': ['GET', 'POST'], 'function': check_repo},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
# still working url for backward compat.
|
||||
rmap.connect('raw_changeset_home_depraced',
|
||||
|
|
|
|||
|
|
@ -286,4 +286,3 @@ class HomeController(BaseController):
|
|||
_user_groups = _user_groups
|
||||
|
||||
return {'suggestions': _user_groups}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,6 +251,16 @@ class SummaryController(BaseRepoController):
|
|||
}
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
|
||||
'repository.admin')
|
||||
@jsonify
|
||||
def repo_default_reviewers_data(self, repo_name):
|
||||
return {
|
||||
'reviewers': [utils.reviewer_as_json(
|
||||
user=c.rhodecode_db_repo.user, reasons=None)]
|
||||
}
|
||||
|
||||
@jsonify
|
||||
def repo_refs_changelog_data(self, repo_name):
|
||||
repo = c.rhodecode_repo
|
||||
|
|
|
|||
|
|
@ -86,3 +86,21 @@ def get_commit_from_ref_name(repo, ref_name, ref_type=None):
|
|||
'%s "%s" does not exist' % (ref_type, ref_name))
|
||||
|
||||
return repo_scm.get_commit(commit_id)
|
||||
|
||||
|
||||
def reviewer_as_json(user, reasons):
|
||||
"""
|
||||
Returns json struct of a reviewer for frontend
|
||||
|
||||
:param user: the reviewer
|
||||
:param reasons: list of strings of why they are reviewers
|
||||
"""
|
||||
|
||||
return {
|
||||
'user_id': user.user_id,
|
||||
'reasons': reasons,
|
||||
'username': user.username,
|
||||
'firstname': user.firstname,
|
||||
'lastname': user.lastname,
|
||||
'gravatar_link': h.gravatar_url(user.email, 14),
|
||||
}
|
||||
|
|
|
|||
3640
rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py
Normal file
3640
rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py
Normal file
File diff suppressed because it is too large
Load diff
35
rhodecode/lib/dbmigrate/versions/059_version_4_4_0.py
Normal file
35
rhodecode/lib/dbmigrate/versions/059_version_4_4_0.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import logging
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.exc import DatabaseError
|
||||
from sqlalchemy.orm import relation, backref, class_mapper, joinedload
|
||||
from sqlalchemy.orm.session import Session
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from rhodecode.lib.dbmigrate.migrate import *
|
||||
from rhodecode.lib.dbmigrate.migrate.changeset import *
|
||||
from rhodecode.lib.utils2 import str2bool
|
||||
|
||||
from rhodecode.model.meta import Base
|
||||
from rhodecode.model import meta
|
||||
from rhodecode.lib.dbmigrate.versions import _reset_base, notify
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
"""
|
||||
Upgrade operations go here.
|
||||
Don't create your own engine; bind migrate_engine to your metadata
|
||||
"""
|
||||
_reset_base(migrate_engine)
|
||||
from rhodecode.lib.dbmigrate.schema import db_4_4_0_2
|
||||
|
||||
db_4_4_0_2.RepoReviewRule.__table__.create()
|
||||
db_4_4_0_2.RepoReviewRuleUser.__table__.create()
|
||||
db_4_4_0_2.RepoReviewRuleUserGroup.__table__.create()
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
|
@ -893,3 +893,44 @@ def get_routes_generator_for_server_url(server_url):
|
|||
environ['wsgi.url_scheme'] = 'https'
|
||||
|
||||
return routes.util.URLGenerator(rhodecode.CONFIG['routes.map'], environ)
|
||||
|
||||
|
||||
def glob2re(pat):
|
||||
"""
|
||||
Translate a shell PATTERN to a regular expression.
|
||||
|
||||
There is no way to quote meta-characters.
|
||||
"""
|
||||
|
||||
i, n = 0, len(pat)
|
||||
res = ''
|
||||
while i < n:
|
||||
c = pat[i]
|
||||
i = i+1
|
||||
if c == '*':
|
||||
#res = res + '.*'
|
||||
res = res + '[^/]*'
|
||||
elif c == '?':
|
||||
#res = res + '.'
|
||||
res = res + '[^/]'
|
||||
elif c == '[':
|
||||
j = i
|
||||
if j < n and pat[j] == '!':
|
||||
j = j+1
|
||||
if j < n and pat[j] == ']':
|
||||
j = j+1
|
||||
while j < n and pat[j] != ']':
|
||||
j = j+1
|
||||
if j >= n:
|
||||
res = res + '\\['
|
||||
else:
|
||||
stuff = pat[i:j].replace('\\','\\\\')
|
||||
i = j+1
|
||||
if stuff[0] == '!':
|
||||
stuff = '^' + stuff[1:]
|
||||
elif stuff[0] == '^':
|
||||
stuff = '\\' + stuff
|
||||
res = '%s[%s]' % (res, stuff)
|
||||
else:
|
||||
res = res + re.escape(c)
|
||||
return res + '\Z(?ms)'
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
Database Models for RhodeCode Enterprise
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
|
@ -56,7 +57,8 @@ from rhodecode.lib.vcs.backends.base import (
|
|||
EmptyCommit, Reference, MergeFailureReason)
|
||||
from rhodecode.lib.utils2 import (
|
||||
str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe,
|
||||
time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict)
|
||||
time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
|
||||
glob2re)
|
||||
from rhodecode.lib.jsonalchemy import MutationObj, JsonType, JSONDict
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.caching_query import FromCache
|
||||
|
|
@ -3514,3 +3516,125 @@ class Integration(Base, BaseModel):
|
|||
|
||||
def __repr__(self):
|
||||
return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
|
||||
|
||||
|
||||
class RepoReviewRuleUser(Base, BaseModel):
|
||||
__tablename__ = 'repo_review_rules_users'
|
||||
__table_args__ = (
|
||||
{'extend_existing': True, 'mysql_engine': 'InnoDB',
|
||||
'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
|
||||
)
|
||||
repo_review_rule_user_id = Column(
|
||||
'repo_review_rule_user_id', Integer(), primary_key=True)
|
||||
repo_review_rule_id = Column("repo_review_rule_id",
|
||||
Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
|
||||
user_id = Column("user_id", Integer(), ForeignKey('users.user_id'),
|
||||
nullable=False)
|
||||
user = relationship('User')
|
||||
|
||||
|
||||
class RepoReviewRuleUserGroup(Base, BaseModel):
|
||||
__tablename__ = 'repo_review_rules_users_groups'
|
||||
__table_args__ = (
|
||||
{'extend_existing': True, 'mysql_engine': 'InnoDB',
|
||||
'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
|
||||
)
|
||||
repo_review_rule_users_group_id = Column(
|
||||
'repo_review_rule_users_group_id', Integer(), primary_key=True)
|
||||
repo_review_rule_id = Column("repo_review_rule_id",
|
||||
Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
|
||||
users_group_id = Column("users_group_id", Integer(),
|
||||
ForeignKey('users_groups.users_group_id'), nullable=False)
|
||||
users_group = relationship('UserGroup')
|
||||
|
||||
|
||||
class RepoReviewRule(Base, BaseModel):
|
||||
__tablename__ = 'repo_review_rules'
|
||||
__table_args__ = (
|
||||
{'extend_existing': True, 'mysql_engine': 'InnoDB',
|
||||
'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
|
||||
)
|
||||
|
||||
repo_review_rule_id = Column(
|
||||
'repo_review_rule_id', Integer(), primary_key=True)
|
||||
repo_id = Column(
|
||||
"repo_id", Integer(), ForeignKey('repositories.repo_id'))
|
||||
repo = relationship('Repository', backref='review_rules')
|
||||
|
||||
_branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'),
|
||||
default=u'*') # glob
|
||||
_file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'),
|
||||
default=u'*') # glob
|
||||
|
||||
use_authors_for_review = Column("use_authors_for_review", Boolean(),
|
||||
nullable=False, default=False)
|
||||
rule_users = relationship('RepoReviewRuleUser')
|
||||
rule_user_groups = relationship('RepoReviewRuleUserGroup')
|
||||
|
||||
@hybrid_property
|
||||
def branch_pattern(self):
|
||||
return self._branch_pattern or '*'
|
||||
|
||||
def _validate_glob(self, value):
|
||||
re.compile('^' + glob2re(value) + '$')
|
||||
|
||||
@branch_pattern.setter
|
||||
def branch_pattern(self, value):
|
||||
self._validate_glob(value)
|
||||
self._branch_pattern = value or '*'
|
||||
|
||||
@hybrid_property
|
||||
def file_pattern(self):
|
||||
return self._file_pattern or '*'
|
||||
|
||||
@file_pattern.setter
|
||||
def file_pattern(self, value):
|
||||
self._validate_glob(value)
|
||||
self._file_pattern = value or '*'
|
||||
|
||||
def matches(self, branch, files_changed):
|
||||
"""
|
||||
Check if this review rule matches a branch/files in a pull request
|
||||
|
||||
:param branch: branch name for the commit
|
||||
:param files_changed: list of file paths changed in the pull request
|
||||
"""
|
||||
|
||||
branch = branch or ''
|
||||
files_changed = files_changed or []
|
||||
|
||||
branch_matches = True
|
||||
if branch:
|
||||
branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$')
|
||||
branch_matches = bool(branch_regex.search(branch))
|
||||
|
||||
files_matches = True
|
||||
if self.file_pattern != '*':
|
||||
files_matches = False
|
||||
file_regex = re.compile(glob2re(self.file_pattern))
|
||||
for filename in files_changed:
|
||||
if file_regex.search(filename):
|
||||
files_matches = True
|
||||
break
|
||||
|
||||
return branch_matches and files_matches
|
||||
|
||||
@property
|
||||
def review_users(self):
|
||||
""" Returns the users which this rule applies to """
|
||||
|
||||
users = set()
|
||||
users |= set([
|
||||
rule_user.user for rule_user in self.rule_users
|
||||
if rule_user.user.active])
|
||||
users |= set(
|
||||
member.user
|
||||
for rule_user_group in self.rule_user_groups
|
||||
for member in rule_user_group.users_group.members
|
||||
if member.user.active
|
||||
)
|
||||
return users
|
||||
|
||||
def __repr__(self):
|
||||
return '<RepoReviewerRule(id=%r, repo=%r)>' % (
|
||||
self.repo_review_rule_id, self.repo)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
import ipaddress
|
||||
import colander
|
||||
|
||||
from rhodecode.translation import _
|
||||
from rhodecode.lib.utils2 import glob2re
|
||||
|
||||
|
||||
def ip_addr_validator(node, value):
|
||||
|
|
@ -13,3 +15,12 @@ def ip_addr_validator(node, value):
|
|||
except ValueError:
|
||||
msg = _(u'Please enter a valid IPv4 or IpV6 address')
|
||||
raise colander.Invalid(node, msg)
|
||||
|
||||
|
||||
def glob_validator(node, value):
|
||||
try:
|
||||
re.compile('^' + glob2re(value) + '$')
|
||||
except Exception:
|
||||
raise
|
||||
msg = _(u'Invalid glob pattern')
|
||||
raise colander.Invalid(node, msg)
|
||||
|
|
|
|||
|
|
@ -90,28 +90,50 @@
|
|||
height: 40px;
|
||||
}
|
||||
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item label {
|
||||
display: none;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item:first-child label {
|
||||
display: block;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item .panel-heading {
|
||||
display: none;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item.form-group {
|
||||
margin: 0;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group .form-group {
|
||||
width: 45%; padding: 0 2px; float: left; clear: none;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel {
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
border: none;
|
||||
}
|
||||
.deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel > .panel-body {
|
||||
padding: 0;
|
||||
.deform-full-field-sequence.control-inputs {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.deform-table-sequence {
|
||||
.deform-seq-container {
|
||||
.deform-seq-item {
|
||||
margin: 0;
|
||||
label {
|
||||
display: none;
|
||||
}
|
||||
.panel-heading {
|
||||
display: none;
|
||||
}
|
||||
.deform-seq-item-group > .panel {
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
border: none;
|
||||
&> .panel-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
&:first-child label {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.deform-table-2-sequence {
|
||||
.deform-seq-container {
|
||||
.deform-seq-item {
|
||||
.form-group {
|
||||
width: 45% !important; padding: 0 2px; float: left; clear: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.deform-table-3-sequence {
|
||||
.deform-seq-container {
|
||||
.deform-seq-item {
|
||||
.form-group {
|
||||
width: 30% !important; padding: 0 2px; float: left; clear: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ function registerRCRoutes() {
|
|||
// routes registration
|
||||
pyroutes.register('home', '/', []);
|
||||
pyroutes.register('user_autocomplete_data', '/_users', []);
|
||||
pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
|
||||
pyroutes.register('new_repo', '/_admin/create_repository', []);
|
||||
pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
|
||||
pyroutes.register('gists', '/_admin/gists', []);
|
||||
|
|
@ -22,6 +23,7 @@ function registerRCRoutes() {
|
|||
pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
|
||||
pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
|
||||
pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
|
||||
pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
|
||||
pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
|
||||
pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
|
||||
pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
|
||||
|
|
|
|||
|
|
@ -40,14 +40,23 @@ var removeReviewMember = function(reviewer_id, mark_delete){
|
|||
}
|
||||
};
|
||||
|
||||
var addReviewMember = function(id,fname,lname,nname,gravatar_link){
|
||||
var addReviewMember = function(id, fname, lname, nname, gravatar_link, reasons) {
|
||||
var members = $('#review_members').get(0);
|
||||
var reasons_html = '';
|
||||
if (reasons) {
|
||||
for (var i = 0; i < reasons.length; i++) {
|
||||
reasons_html += '<div class="reviewer_reason">- {0}</div>'.format(
|
||||
reasons[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
var tmpl = '<li id="reviewer_{2}">'+
|
||||
'<div class="reviewer_status">'+
|
||||
'<div class="flag_status not_reviewed pull-left reviewer_member_status"></div>'+
|
||||
'</div>'+
|
||||
'<img alt="gravatar" class="gravatar" src="{0}"/>'+
|
||||
'<span class="reviewer_name user">{1}</span>'+
|
||||
reasons_html +
|
||||
'<input type="hidden" value="{2}" name="review_members" />'+
|
||||
'<div class="reviewer_member_remove action_button" onclick="removeReviewMember({2})">' +
|
||||
'<i class="icon-remove-sign"></i>'+
|
||||
|
|
|
|||
|
|
@ -71,6 +71,22 @@
|
|||
<li class="${'active' if c.active=='integrations' else ''}">
|
||||
<a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a>
|
||||
</li>
|
||||
## TODO: dan: replace repo navigation with navlist registry like with
|
||||
## admin menu. First must find way to allow runtime configuration
|
||||
## it to account for the c.repo_info.repo_type != 'svn' call above
|
||||
<%
|
||||
reviewer_settings = False
|
||||
try:
|
||||
import rc_reviewers
|
||||
reviewer_settings = True
|
||||
except ImportError:
|
||||
pass
|
||||
%>
|
||||
%if reviewer_settings:
|
||||
<li class="${'active' if c.active=='reviewers' else ''}">
|
||||
<a href="${h.route_path('repo_reviewers_home', repo_name=c.repo_name)}">${_('Reviewers')}</a>
|
||||
</li>
|
||||
%endif
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -439,13 +439,6 @@ $(function(){
|
|||
};
|
||||
|
||||
var targetRepoChanged = function(repoData) {
|
||||
// reset && add the reviewer based on selected repo
|
||||
$('#review_members').html('');
|
||||
addReviewMember(
|
||||
repoData.user.user_id, repoData.user.firstname,
|
||||
repoData.user.lastname, repoData.user.username,
|
||||
repoData.user.gravatar_link);
|
||||
|
||||
// generate new DESC of target repo displayed next to select
|
||||
$('#target_repo_desc').html(
|
||||
"<strong>${_('Destination repository')}</strong>: {0}".format(repoData['description'])
|
||||
|
|
@ -488,10 +481,12 @@ $(function(){
|
|||
|
||||
$sourceRef.on('change', function(e){
|
||||
loadRepoRefDiffPreview();
|
||||
loadDefaultReviewers();
|
||||
});
|
||||
|
||||
$targetRef.on('change', function(e){
|
||||
loadRepoRefDiffPreview();
|
||||
loadDefaultReviewers();
|
||||
});
|
||||
|
||||
$targetRepo.on('change', function(e){
|
||||
|
|
@ -518,6 +513,36 @@ $(function(){
|
|||
|
||||
});
|
||||
|
||||
var loadDefaultReviewers = function() {
|
||||
if (loadDefaultReviewers._currentRequest) {
|
||||
loadDefaultReviewers._currentRequest.abort();
|
||||
}
|
||||
var url = pyroutes.url('repo_default_reviewers_data', {'repo_name': targetRepoName});
|
||||
|
||||
var sourceRepo = $sourceRepo.eq(0).val();
|
||||
var sourceRef = $sourceRef.eq(0).val().split(':');
|
||||
var targetRepo = $targetRepo.eq(0).val();
|
||||
var targetRef = $targetRef.eq(0).val().split(':');
|
||||
url += '?source_repo=' + sourceRepo;
|
||||
url += '&source_ref=' + sourceRef[2];
|
||||
url += '&target_repo=' + targetRepo;
|
||||
url += '&target_ref=' + targetRef[2];
|
||||
|
||||
loadDefaultReviewers._currentRequest = $.get(url)
|
||||
.done(function(data) {
|
||||
loadDefaultReviewers._currentRequest = null;
|
||||
|
||||
// reset && add the reviewer based on selected repo
|
||||
$('#review_members').html('');
|
||||
for (var i = 0; i < data.reviewers.length; i++) {
|
||||
var reviewer = data.reviewers[i];
|
||||
addReviewMember(
|
||||
reviewer.user_id, reviewer.firstname,
|
||||
reviewer.lastname, reviewer.username,
|
||||
reviewer.gravatar_link, reviewer.reasons);
|
||||
}
|
||||
});
|
||||
};
|
||||
prButtonLock(true, "${_('Please select origin and destination')}");
|
||||
|
||||
// auto-load on init, the target refs select2
|
||||
|
|
@ -532,6 +557,7 @@ $(function(){
|
|||
// in case we have a pre-selected value, use it now
|
||||
$sourceRef.select2('val', '${c.default_source_ref}');
|
||||
loadRepoRefDiffPreview();
|
||||
loadDefaultReviewers();
|
||||
%endif
|
||||
|
||||
ReviewerAutoComplete('user');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue