.. _changelog:
Changelog
=========
1.3.2 (**2012-XX-XX**)
----------------------
:status: in-progress
:branch: beta
news
++++
fixes
+++++
- fixed git protocol issues with repos-groups
- fixed git remote repos validator that prevented from cloning remote git repos
- fixes #370 ending slashes fixes for repo and groups
1.3.1 (**2012-02-27**)
- redirection loop occurs when remember-me wasn't checked during login
- fixes issues with git blob history generation
- don't fetch branch for git in file history dropdown. Causes unneeded slowness
1.3.0 (**2012-02-26**)
- code review, inspired by github code-comments
- #215 rst and markdown README files support
- #252 Container-based and proxy pass-through authentication support
- #44 branch browser. Filtering of changelog by branches
- mercurial bookmarks support
- new hover top menu, optimized to add maximum size for important views
- configurable clone url template with possibility to specify protocol like
ssh:// or http:// and also manually alter other parts of clone_url.
- enabled largefiles extension by default
- optimized summary file pages and saved a lot of unused space in them
- #239 option to manually mark repository as fork
- #320 mapping of commit authors to RhodeCode users
- #304 hashes are displayed using monospace font
- diff configuration, toggle white lines and context lines
- #307 configurable diffs, whitespace toggle, increasing context lines
- sorting on branches, tags and bookmarks using YUI datatable
- improved file filter on files page
- implements #330 api method for listing nodes ar particular revision
- #73 added linking issues in commit messages to chosen issue tracker url
based on user defined regular expression
- added linking of changesets in commit messages
- new compact changelog with expandable commit messages
- firstname and lastname are optional in user creation
- #348 added post-create repository hook
- #212 global encoding settings is now configurable from .ini files
- #227 added repository groups permissions
- markdown gets codehilite extensions
@@ -218,96 +218,101 @@ class ReposGroupsController(BaseControll
except Exception:
log.error(traceback.format_exc())
h.flash(_('error occurred during deletion of repos '
'group %s' % gr.group_name), category='error')
return redirect(url('repos_groups'))
@HasReposGroupPermissionAnyDecorator('group.admin')
def delete_repos_group_user_perm(self, group_name):
"""
DELETE an existing repositories group permission user
:param group_name:
try:
ReposGroupModel().revoke_user_permission(
repos_group=group_name, user=request.POST['user_id']
)
Session.commit()
h.flash(_('An error occurred during deletion of group user'),
category='error')
raise HTTPInternalServerError()
def delete_repos_group_users_group_perm(self, group_name):
DELETE an existing repositories group permission users group
ReposGroupModel().revoke_users_group_permission(
repos_group=group_name,
group_name=request.POST['users_group_id']
h.flash(_('An error occurred during deletion of group'
' users groups'),
def show_by_name(self, group_name):
This is a proxy that does a lookup group_name -> id, and shows
the group by id view instead
group_name = group_name.rstrip('/')
id_ = RepoGroup.get_by_group_name(group_name).group_id
return self.show(id_)
@HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
'group.admin')
def show(self, id, format='html'):
"""GET /repos_groups/id: Show a specific item"""
# url('repos_group', id=ID)
c.group = RepoGroup.get(id)
if c.group:
c.group_repos = c.group.repositories.all()
else:
return redirect(url('home'))
#overwrite our cached list with current filter
gr_filter = c.group_repos
c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
c.repos_list = c.cached_repo_list
c.repo_cnt = 0
c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
.filter(RepoGroup.group_parent_id == id).all()
return render('admin/repos_groups/repos_groups.html')
@HasPermissionAnyDecorator('hg.admin')
def edit(self, id, format='html'):
"""GET /repos_groups/id/edit: Form to edit an existing item"""
# url('edit_repos_group', id=ID)
id_ = int(id)
c.repos_group = RepoGroup.get(id_)
defaults = self.__load_data(id_)
# we need to exclude this group from the group list for editing
c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
return htmlfill.render(
render('admin/repos_groups/repos_groups_edit.html'),
defaults=defaults,
encoding="UTF-8",
force_defaults=False
@@ -47,101 +47,107 @@ from rhodecode.lib.vcs.utils.helpers imp
from rhodecode.lib.vcs.exceptions import VCSError
from rhodecode.lib.caching_query import FromCache
from rhodecode.model import meta
from rhodecode.model.db import Repository, User, RhodeCodeUi, \
UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm
from rhodecode.model.meta import Session
from rhodecode.model.repos_group import ReposGroupModel
log = logging.getLogger(__name__)
def recursive_replace(str_, replace=' '):
"""Recursive replace of given sign to just one instance
:param str_: given string
:param replace: char to find and replace multiple instances
Examples::
>>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
'Mighty-Mighty-Bo-sstones'
if str_.find(replace * 2) == -1:
return str_
str_ = str_.replace(replace * 2, replace)
return recursive_replace(str_, replace)
def repo_name_slug(value):
"""Return slug of name of repository
This function is called on each creation/modification
of repository to prevent bad names in repo
slug = remove_formatting(value)
slug = strip_tags(slug)
for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
slug = slug.replace(c, '-')
slug = recursive_replace(slug, '-')
slug = collapse(slug, '-')
return slug
def get_repo_slug(request):
return request.environ['pylons.routes_dict'].get('repo_name')
_repo = request.environ['pylons.routes_dict'].get('repo_name')
if _repo:
_repo = _repo.rstrip('/')
return _repo
def get_repos_group_slug(request):
return request.environ['pylons.routes_dict'].get('group_name')
_group = request.environ['pylons.routes_dict'].get('group_name')
if _group:
_group = _group.rstrip('/')
return _group
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
Action logger for various actions made by users
:param user: user that made this action, can be a unique username string or
object containing user_id attribute
:param action: action to log, should be on of predefined unique actions for
easy translations
:param repo: string name of repository or object containing repo_id,
that action was made on
:param ipaddr: optional ip address from what the action was made
:param sa: optional sqlalchemy session
if not sa:
sa = meta.Session
if hasattr(user, 'user_id'):
user_obj = user
elif isinstance(user, basestring):
user_obj = User.get_by_username(user)
raise Exception('You have to provide user object or username')
if hasattr(repo, 'repo_id'):
repo_obj = Repository.get(repo.repo_id)
repo_name = repo_obj.repo_name
elif isinstance(repo, basestring):
repo_name = repo.lstrip('/')
repo_obj = Repository.get_by_repo_name(repo_name)
raise Exception('You have to provide repository to action logger')
user_log = UserLog()
user_log.user_id = user_obj.user_id
user_log.action = action
user_log.repository_id = repo_obj.repo_id
user_log.repository_name = repo_name
user_log.action_date = datetime.datetime.now()
user_log.user_ip = ipaddr
sa.add(user_log)
Status change: