Changeset - 6e8027c2f49c
[Not reviewed]
Merge beta
0 68 1
Leonardo - 13 years ago 2013-03-11 17:09:43
leo@unity3d.com
Merge
69 files changed with 1032 insertions and 432 deletions:
test.ini
90
6
0 comments (0 inline, 0 general)
development.ini
Show inline comments
 
@@ -65,6 +65,8 @@ static_files = true
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = rc-develop
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
@@ -154,6 +156,11 @@ instance_id =
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
docs/api/api.rst
Show inline comments
 
@@ -178,7 +178,8 @@ lock
 
----
 

	
 
Set locking state on given repository by given user. If userid param is skipped
 
, then it is set to id of user whos calling this method.
 
, then it is set to id of user whos calling this method. If locked param is skipped
 
then function shows current lock state of given repo.
 
This command can be executed only using api_key belonging to user with admin
 
rights or regular user that have admin or write access to repository.
 

	
 
@@ -190,7 +191,7 @@ INPUT::
 
    args :    {
 
                "repoid" : "<reponame or repo_id>"
 
                "userid" : "<user_id or username = Optional(=apiuser)>",
 
                "locked" : "<bool true|false>"
 
                "locked" : "<bool true|false = Optional(=None)>"
 
              }
 

	
 
OUTPUT::
docs/changelog.rst
Show inline comments
 
@@ -16,6 +16,27 @@ news
 
fixes
 
+++++
 

	
 
1.5.4 (**2013-03-13**)
 
----------------------
 

	
 
news
 
++++
 

	
 

	
 
fixes
 
+++++
 

	
 
- fixed webtest dependency issues
 
- fixed issues with celery tasks for password reset
 
- fixed #763 gravatar helper function should fallback into default image
 
  if email is empty
 
- fixes #762 user global activation flag is also respected for LDAP created
 
  accounts
 
- use password obfuscate when clonning a remote repo with credentials inside
 
- fixed issue with renaming repos group together with changing parents
 
- disallow cloning from file:/// URIs
 
- handle all cases with multiple IP addresses in proxy headers
 

	
 
1.5.3 (**2013-02-12**)
 
----------------------
 

	
 
@@ -139,8 +160,8 @@ fixes
 
  When this is used together with mercurial internal translation system
 
  it can lead to UnicodeDecodeErrors
 
- fixes #645 Fix git handler when doing delete remote branch
 
- implements #649 added two seperate method for author and commiter to VCS
 
  changeset class switch author for git backed to be the real author not commiter
 
- implements #649 added two seperate method for author and committer to VCS
 
  changeset class switch author for git backed to be the real author not committer
 
- fix issue #504 RhodeCode is showing different versions of README on
 
  different summary page loads
 
- implemented #658 Changing username in LDAP-Mode should not be allowed.
docs/setup.rst
Show inline comments
 
@@ -478,7 +478,7 @@ Changing default encoding
 

	
 
By default RhodeCode uses utf8 encoding, starting from 1.3 series this
 
can be changed, simply edit default_encoding in .ini file to desired one.
 
This affects many parts in rhodecode including commiters names, filenames,
 
This affects many parts in rhodecode including committers names, filenames,
 
encoding of commit messages. In addition RhodeCode can detect if `chardet`
 
library is installed. If `chardet` is detected RhodeCode will fallback to it
 
when there are encode/decode errors.
docs/theme/nature/static/pygments.css
Show inline comments
 
@@ -51,4 +51,4 @@
 
.vc { color: #ff99ff } /* Name.Variable.Class */
 
.vg { color: #ff99ff } /* Name.Variable.Global */
 
.vi { color: #ff99ff } /* Name.Variable.Instance */
 
.il { color: #009999 } /* Literal.Number.Integer.Long */
 
.il { color: #009999 } /* Literal.Number.Integer.Long */
 
\ No newline at end of file
production.ini
Show inline comments
 
@@ -65,6 +65,8 @@ static_files = true
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = rc-production
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
@@ -154,6 +156,11 @@ instance_id =
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
rhodecode/config/deployment.ini_tmpl
Show inline comments
 
@@ -65,6 +65,8 @@ static_files = true
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = ${app_instance_uuid}
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
@@ -154,6 +156,11 @@ instance_id =
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
rhodecode/config/middleware.py
Show inline comments
 
@@ -15,6 +15,7 @@ from rhodecode.lib.middleware.simplehg i
 
from rhodecode.lib.middleware.simplegit import SimpleGit
 
from rhodecode.lib.middleware.https_fixup import HttpsFixup
 
from rhodecode.config.environment import load_environment
 
from rhodecode.lib.middleware.wrapper import RequestWrapper
 

	
 

	
 
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
 
@@ -55,7 +56,7 @@ def make_app(global_conf, full_stack=Tru
 

	
 
        from rhodecode.lib.middleware.sentry import Sentry
 
        from rhodecode.lib.middleware.errormator import Errormator
 
        if Errormator:
 
        if Errormator and asbool(config['app_conf'].get('errormator')):
 
            app = Errormator(app, config)
 
        elif Sentry:
 
            app = Sentry(app, config)
 
@@ -67,7 +68,7 @@ def make_app(global_conf, full_stack=Tru
 
        # need any pylons stack middleware in them
 
        app = SimpleHg(app, config)
 
        app = SimpleGit(app, config)
 

	
 
        app = RequestWrapper(app, config)
 
        # Display error documents for 401, 403, 404 status codes (and
 
        # 500 when debug is disabled)
 
        if asbool(config['debug']):
rhodecode/config/routing.py
Show inline comments
 
@@ -56,6 +56,18 @@ def make_map(config):
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'])
 

	
 
    def check_group_skip_path(environ, match_dict):
 
        """
 
        check for valid repository group for proper 404 handling, but skips
 
        verification of existing path
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'],
 
                                    skip_path_check=True)
 

	
 
    def check_int(environ, match_dict):
 
        return match_dict.get('id').isdigit()
 

	
 
@@ -171,9 +183,10 @@ def make_map(config):
 
                                                   function=check_group))
 
        m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="delete", conditions=dict(method=["DELETE"],
 
                                                   function=check_group))
 
                                                   function=check_group_skip_path))
 
        m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
 
                  action="edit", conditions=dict(method=["GET"],))
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("formatted_edit_repos_group",
 
                  "/repos_groups/{group_name:.*?}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"],
rhodecode/controllers/admin/repos_groups.py
Show inline comments
 
@@ -251,31 +251,25 @@ class ReposGroupsController(BaseControll
 
        repos = gr.repositories.all()
 
        if repos:
 
            h.flash(_('This group contains %s repositores and cannot be '
 
                      'deleted') % len(repos),
 
                    category='error')
 
                      'deleted') % len(repos), category='warning')
 
            return redirect(url('repos_groups'))
 

	
 
        children = gr.children.all()
 
        if children:
 
            h.flash(_('This group contains %s subgroups and cannot be deleted'
 
                      % (len(children))), category='warning')
 
            return redirect(url('repos_groups'))
 

	
 
        try:
 
            ReposGroupModel().delete(group_name)
 
            Session().commit()
 
            h.flash(_('removed repos group %s') % gr.group_name,
 
            h.flash(_('removed repos group %s') % group_name,
 
                    category='success')
 
            #TODO: in future action_logger(, '', '', '', self.sa)
 
        except IntegrityError, e:
 
            if str(e.message).find('groups_group_parent_id_fkey') != -1:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Cannot delete this group it still contains '
 
                          'subgroups'),
 
                        category='warning')
 
            else:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during deletion of repos '
 
                          'group %s') % gr.group_name, category='error')
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during deletion of repos '
 
                      'group %s') % gr.group_name, category='error')
 
                      'group %s') % group_name, category='error')
 

	
 
        return redirect(url('repos_groups'))
 

	
rhodecode/controllers/admin/settings.py
Show inline comments
 
@@ -38,7 +38,7 @@ from pylons.i18n.translation import _
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator, NotAnonymous, HasPermissionAny,\
 
    HasReposGroupPermissionAll, HasReposGroupPermissionAny
 
    HasReposGroupPermissionAll, HasReposGroupPermissionAny, AuthUser
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.celerylib import tasks, run_task
 
from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
 
@@ -409,6 +409,8 @@ class SettingsController(BaseController)
 
        # url('admin_settings_my_account')
 

	
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.ldap_dn = c.user.ldap_dn
 

	
 
        if c.user.username == 'default':
 
@@ -440,6 +442,8 @@ class SettingsController(BaseController)
 
        # url('admin_settings_my_account_update', id=ID)
 
        uid = self.rhodecode_user.user_id
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.ldap_dn = c.user.ldap_dn
 
        email = self.rhodecode_user.email
 
        _form = UserForm(edit=True,
rhodecode/controllers/api/api.py
Show inline comments
 
@@ -27,14 +27,14 @@
 

	
 
import traceback
 
import logging
 
from pylons.controllers.util import abort
 

	
 
from rhodecode.controllers.api import JSONRPCController, JSONRPCError
 
from rhodecode.lib.auth import PasswordGenerator, AuthUser, \
 
    HasPermissionAllDecorator, HasPermissionAnyDecorator, \
 
    HasPermissionAnyApi, HasRepoPermissionAnyApi
 
from rhodecode.lib.utils import map_groups, repo2db_mapper
 
from rhodecode.lib.utils2 import str2bool
 
from rhodecode.lib.utils2 import str2bool, time_to_datetime, safe_int
 
from rhodecode.lib import helpers as h
 
from rhodecode.model.meta import Session
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.repo import RepoModel
 
@@ -42,6 +42,7 @@ from rhodecode.model.user import UserMod
 
from rhodecode.model.users_group import UserGroupModel
 
from rhodecode.model.permission import PermissionModel
 
from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap
 
from rhodecode.lib.compat import json
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -229,7 +230,8 @@ class ApiController(JSONRPCController):
 
                'Error occurred during cache invalidation action'
 
            )
 

	
 
    def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))):
 
    def lock(self, apiuser, repoid, locked=Optional(None),
 
             userid=Optional(OAttr('apiuser'))):
 
        """
 
        Set locking state on particular repository by given user, if
 
        this command is runned by non-admin account userid is set to user
 
@@ -257,21 +259,77 @@ class ApiController(JSONRPCController):
 

	
 
        if isinstance(userid, Optional):
 
            userid = apiuser.user_id
 

	
 
        user = get_user_or_error(userid)
 
        locked = str2bool(locked)
 
        try:
 
            if locked:
 
                Repository.lock(repo, user.user_id)
 

	
 
        if isinstance(locked, Optional):
 
            lockobj = Repository.getlock(repo)
 

	
 
            if lockobj[0] is None:
 
                return ('Repo `%s` not locked. Locked=`False`.'
 
                        % (repo.repo_name))
 
            else:
 
                Repository.unlock(repo)
 
                userid, time_ = lockobj
 
                user = get_user_or_error(userid)
 

	
 
                return ('Repo `%s` locked by `%s`. Locked=`True`. '
 
                        'Locked since: `%s`'
 
                    % (repo.repo_name, user.username,
 
                       json.dumps(time_to_datetime(time_))))
 

	
 
        else:
 
            locked = str2bool(locked)
 
            try:
 
                if locked:
 
                    Repository.lock(repo, user.user_id)
 
                else:
 
                    Repository.unlock(repo)
 

	
 
                return ('User `%s` set lock state for repo `%s` to `%s`'
 
                        % (user.username, repo.repo_name, locked))
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                raise JSONRPCError(
 
                    'Error occurred locking repository `%s`' % repo.repo_name
 
                )
 

	
 
            return ('User `%s` set lock state for repo `%s` to `%s`'
 
                    % (user.username, repo.repo_name, locked))
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'Error occurred locking repository `%s`' % repo.repo_name
 
            )
 
    def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
 
        """
 
        Get all locks for given userid, if
 
        this command is runned by non-admin account userid is set to user
 
        who is calling this method, thus returning locks for himself
 

	
 
        :param apiuser:
 
        :param userid:
 
        """
 
        if HasPermissionAnyApi('hg.admin')(user=apiuser):
 
            pass
 
        else:
 
            #make sure normal user does not pass someone else userid,
 
            #he is not allowed to do that
 
            if not isinstance(userid, Optional) and userid != apiuser.user_id:
 
                raise JSONRPCError(
 
                    'userid is not the same as your user'
 
                )
 
        ret = []
 
        if isinstance(userid, Optional):
 
            user = None
 
        else:
 
            user = get_user_or_error(userid)
 

	
 
        #show all locks
 
        for r in Repository.getAll():
 
            userid, time_ = r.locked
 
            if time_:
 
                _api_data = r.get_api_data()
 
                # if we use userfilter just show the locks for this user
 
                if user:
 
                    if safe_int(userid) == user.user_id:
 
                        ret.append(_api_data)
 
                else:
 
                    ret.append(_api_data)
 

	
 
        return ret
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def show_ip(self, apiuser, userid):
rhodecode/controllers/compare.py
Show inline comments
 
@@ -89,11 +89,17 @@ class CompareController(BaseRepoControll
 
        # other_ref will be evaluated in other_repo
 
        other_ref = (other_ref_type, other_ref)
 
        other_repo = request.GET.get('other_repo', org_repo)
 
        # If merge is True:
 
        #   Show what org would get if merged with other:
 
        #   List changesets that are ancestors of other but not of org.
 
        #   New changesets in org is thus ignored.
 
        #   Diff will be from common ancestor, and merges of org to other will thus be ignored.
 
        # If merge is False:
 
        #   Make a raw diff from org to other, no matter if related or not.
 
        #   Changesets in one and not in the other will be ignored
 
        merge = bool(request.GET.get('merge'))
 
        # fulldiff disables cut_off_limit
 
        c.fulldiff = request.GET.get('fulldiff')
 
        # only consider this range of changesets
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 
        # partial uses compare_cs.html template directly
 
        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
 
        # as_form puts hidden input field with changeset revisions
 
@@ -103,7 +109,8 @@ class CompareController(BaseRepoControll
 
            repo_name=other_repo,
 
            org_ref_type=other_ref[0], org_ref=other_ref[1],
 
            other_repo=org_repo,
 
            other_ref_type=org_ref[0], other_ref=org_ref[1])
 
            other_ref_type=org_ref[0], other_ref=org_ref[1],
 
            merge=merge or '')
 

	
 
        org_repo = Repository.get_by_repo_name(org_repo)
 
        other_repo = Repository.get_by_repo_name(other_repo)
 
@@ -133,37 +140,23 @@ class CompareController(BaseRepoControll
 
        c.org_ref_type = org_ref[0]
 
        c.other_ref_type = other_ref[0]
 

	
 
        if rev_start and rev_end:
 
            # swap revs with cherry picked ones, save them for display
 
            #org_ref = ('rev', rev_start)
 
            #other_ref = ('rev', rev_end)
 
            c.org_ref = rev_start[:12]
 
            c.other_ref = rev_end[:12]
 
            # get parent of
 
            # rev start to include it in the diff
 
            _cs = other_repo.scm_instance.get_changeset(rev_start)
 
            rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset().raw_id
 
            org_ref = ('rev', rev_start)
 
            other_ref = ('rev', rev_end)
 
            #if we cherry pick it's not remote, make the other_repo org_repo
 
            org_repo = other_repo
 

	
 
        c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
 
            org_repo, org_ref, other_repo, other_ref)
 
        c.cs_ranges, c.ancestor = PullRequestModel().get_compare_data(
 
            org_repo, org_ref, other_repo, other_ref, merge)
 

	
 
        c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
 
                                                   c.cs_ranges])
 
        if partial:
 
            assert c.ancestor
 
            return render('compare/compare_cs.html')
 

	
 
        if ancestor and org_repo != other_repo:
 
        if c.ancestor:
 
            assert merge
 
            # case we want a simple diff without incoming changesets,
 
            # previewing what will be merged.
 
            # Make the diff on the forked repo, with
 
            # revision that is common ancestor
 
            # Make the diff on the other repo (which is known to have other_ref)
 
            log.debug('Using ancestor %s as org_ref instead of %s'
 
                      % (ancestor, org_ref))
 
            org_ref = ('rev', ancestor)
 
                      % (c.ancestor, org_ref))
 
            org_ref = ('rev', c.ancestor)
 
            org_repo = other_repo
 

	
 
        diff_limit = self.cut_off_limit if not c.fulldiff else None
rhodecode/controllers/files.py
Show inline comments
 
@@ -27,6 +27,7 @@ import os
 
import logging
 
import traceback
 
import tempfile
 
import shutil
 

	
 
from pylons import request, response, tmpl_context as c, url
 
from pylons.i18n.translation import _
 
@@ -315,7 +316,7 @@ class FilesController(BaseRepoController
 
            try:
 
                self.scm_model.commit_change(repo=c.rhodecode_repo,
 
                                             repo_name=repo_name, cs=c.cs,
 
                                             user=self.rhodecode_user,
 
                                             user=self.rhodecode_user.user_id,
 
                                             author=author, message=message,
 
                                             content=content, f_path=f_path)
 
                h.flash(_('Successfully committed to %s') % f_path,
 
@@ -378,7 +379,7 @@ class FilesController(BaseRepoController
 
            try:
 
                self.scm_model.create_node(repo=c.rhodecode_repo,
 
                                           repo_name=repo_name, cs=c.cs,
 
                                           user=self.rhodecode_user,
 
                                           user=self.rhodecode_user.user_id,
 
                                           author=author, message=message,
 
                                           content=content, f_path=node_path)
 
                h.flash(_('Successfully committed to %s') % node_path,
 
@@ -429,11 +430,40 @@ class FilesController(BaseRepoController
 
            return _('Empty repository')
 
        except (ImproperArchiveTypeError, KeyError):
 
            return _('Unknown archive type')
 
        # archive cache
 
        from rhodecode import CONFIG
 
        rev_name = cs.raw_id[:12]
 
        archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
 
                                    safe_str(rev_name), ext)
 

	
 
        fd, archive = tempfile.mkstemp()
 
        t = open(archive, 'wb')
 
        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 
        t.close()
 
        use_cached_archive = False  # defines if we use cached version of archive
 
        archive_cache_enabled = CONFIG.get('archive_cache_dir')
 
        if not subrepos and archive_cache_enabled:
 
            #check if we it's ok to write
 
            if not os.path.isdir(CONFIG['archive_cache_dir']):
 
                os.makedirs(CONFIG['archive_cache_dir'])
 
            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
 
            if os.path.isfile(cached_archive_path):
 
                log.debug('Found cached archive in %s' % cached_archive_path)
 
                fd, archive = None, cached_archive_path
 
                use_cached_archive = True
 
            else:
 
                log.debug('Archive %s is not yet cached' % (archive_name))
 

	
 
        if not use_cached_archive:
 
            #generate new archive
 
            try:
 
                fd, archive = tempfile.mkstemp()
 
                t = open(archive, 'wb')
 
                log.debug('Creating new temp archive in %s' % archive)
 
                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 
                if archive_cache_enabled:
 
                    #if we generated the archive and use cache rename that
 
                    log.debug('Storing new archive in %s' % cached_archive_path)
 
                    shutil.move(archive, cached_archive_path)
 
                    archive = cached_archive_path
 
            finally:
 
                t.close()
 

	
 
        def get_chunked_archive(archive):
 
            stream = open(archive, 'rb')
 
@@ -441,13 +471,15 @@ class FilesController(BaseRepoController
 
                data = stream.read(16 * 1024)
 
                if not data:
 
                    stream.close()
 
                    os.close(fd)
 
                    os.remove(archive)
 
                    if fd:  # fd means we used temporary file
 
                        os.close(fd)
 
                    if not archive_cache_enabled:
 
                        log.debug('Destroing temp archive %s' % archive)
 
                        os.remove(archive)
 
                    break
 
                yield data
 

	
 
        response.content_disposition = str('attachment; filename=%s-%s%s' \
 
                                           % (repo_name, revision[:12], ext))
 
        response.content_disposition = str('attachment; filename=%s' % (archive_name))
 
        response.content_type = str(content_type)
 
        return get_chunked_archive(archive)
 

	
rhodecode/controllers/pullrequests.py
Show inline comments
 
@@ -52,6 +52,7 @@ from rhodecode.model.repo import RepoMod
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.forms import PullRequestForm
 
from mercurial import scmutil
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -67,7 +68,7 @@ class PullrequestsController(BaseRepoCon
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def _get_repo_refs(self, repo, rev=None):
 
    def _get_repo_refs(self, repo, rev=None, branch_rev=None):
 
        """return a structure with repo's interesting changesets, suitable for
 
        the selectors in pullrequest.html"""
 
        branches = [('branch:%s:%s' % (k, v), k)
 
@@ -83,11 +84,25 @@ class PullrequestsController(BaseRepoCon
 
        tips = [x[1] for x in branches + bookmarks + tags
 
                if x[0].endswith(colontip)]
 
        selected = 'tag:tip:%s' % tip
 
        special = [(selected, 'tip (%s)' % ', '.join(tips))]
 
        special = [(selected, 'tip: %s' % ', '.join(tips))]
 

	
 
        if rev:
 
            selected = 'rev:%s:%s' % (rev, rev)
 
            special.append((selected, rev))
 
            special.append((selected, '%s: %s' % (_("Selected"), rev[:12])))
 

	
 
        # list named branches that has been merged to this named branch - it should probably merge back
 
        if branch_rev:
 
            # not restricting to merge() would also get branch point and be better
 
            # (especially because it would get the branch point) ... but is currently too expensive
 
            revs = ["sort(parents(branch(id('%s')) and merge()) - branch(id('%s')))" %
 
                    (branch_rev, branch_rev)]
 
            otherbranches = {}
 
            for i in scmutil.revrange(repo._repo, revs):
 
                cs = repo.get_changeset(i)
 
                otherbranches[cs.branch] = cs.raw_id
 
            for branch, node in otherbranches.iteritems():
 
                selected = 'branch:%s:%s' % (branch, node)
 
                special.append((selected, '%s: %s' % (_('Peer'), branch)))
 

	
 
        return [(special, _("Special")),
 
                (bookmarks, _("Bookmarks")),
 
@@ -121,18 +136,23 @@ class PullrequestsController(BaseRepoCon
 
                    category='warning')
 
            redirect(url('summary_home', repo_name=org_repo.repo_name))
 

	
 
        org_rev = request.GET.get('rev_end')
 
        # rev_start is not directly useful - its parent could however be used
 
        # as default for other and thus give a simple compare view
 
        #other_rev = request.POST.get('rev_start')
 

	
 
        other_repos_info = {}
 

	
 
        c.org_repos = []
 
        c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
 
        c.default_org_repo = org_repo.repo_name
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance)
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, org_rev)
 

	
 
        c.other_repos = []
 
        # add org repo to other so we can open pull request against itself
 
        c.other_repos.extend(c.org_repos)
 
        c.default_other_repo = org_repo.repo_name
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance)
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance, branch_rev=org_rev)
 
        usr_data = lambda usr: dict(user_id=usr.user_id,
 
                                    username=usr.username,
 
                                    firstname=usr.firstname,
 
@@ -191,23 +211,12 @@ class PullrequestsController(BaseRepoCon
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        org_repo = _form['org_repo']
 
        org_ref = _form['org_ref']
 
        org_ref = 'rev:merge:%s' % _form['merge_rev']
 
        other_repo = _form['other_repo']
 
        other_ref = _form['other_ref']
 
        other_ref = 'rev:ancestor:%s' % _form['ancestor_rev']
 
        revisions = _form['revisions']
 
        reviewers = _form['review_members']
 

	
 
        # if we have cherry picked pull request we don't care what is in
 
        # org_ref/other_ref
 
        rev_start = request.POST.get('rev_start')
 
        rev_end = request.POST.get('rev_end')
 

	
 
        if rev_start and rev_end:
 
            # this is swapped to simulate that rev_end is a revision from
 
            # parent of the fork
 
            org_ref = 'rev:%s:%s' % (rev_end, rev_end)
 
            other_ref = 'rev:%s:%s' % (rev_start, rev_start)
 

	
 
        title = _form['pullrequest_title']
 
        description = _form['pullrequest_desc']
 

	
 
@@ -265,9 +274,6 @@ class PullrequestsController(BaseRepoCon
 
        :param pull_request:
 
        :type pull_request:
 
        """
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 

	
 
        org_repo = pull_request.org_repo
 
        (org_ref_type,
 
         org_ref_name,
 
@@ -279,7 +285,7 @@ class PullrequestsController(BaseRepoCon
 
         other_ref_rev) = pull_request.other_ref.split(':')
 

	
 
        # despite opening revisions for bookmarks/branches/tags, we always
 
        # convert this to rev to prevent changes after book or branch change
 
        # convert this to rev to prevent changes after bookmark or branch change
 
        org_ref = ('rev', org_ref_rev)
 
        other_ref = ('rev', other_ref_rev)
 

	
 
@@ -290,10 +296,6 @@ class PullrequestsController(BaseRepoCon
 

	
 
        c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
 

	
 
        other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
 
                                  if c.cs_ranges[0].parents
 
                                  else EmptyChangeset(), 'raw_id'))
 

	
 
        c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
 

	
 
        c.org_ref = org_ref[1]
 
@@ -394,6 +396,7 @@ class PullrequestsController(BaseRepoCon
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 

	
 
        c.as_form = False
 
        c.ancestor = None # there is one - but right here we don't know which
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @NotAnonymous()
rhodecode/i18n/en/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3730,7 +3730,7 @@ msgid "Last modified"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3869,7 +3869,7 @@ msgid "Last modified"
 
msgstr "Dernière modification"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Dernier commiteur"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3743,7 +3743,7 @@ msgid "Last modified"
 
msgstr "最終更新日"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最後の作成者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3836,7 +3836,7 @@ msgid "Last modified"
 
msgstr "Ostatnio modyfikowany"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Autor"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/pt_BR/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3910,7 +3910,7 @@ msgid "Last modified"
 
msgstr "Última alteração"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Último commiter"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/rhodecode.pot
Show inline comments
 
@@ -3680,7 +3680,7 @@ msgid "Last modified"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/zh_CN/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3733,7 +3733,7 @@ msgid "Last modified"
 
msgstr "最后修改于"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最后提交者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/i18n/zh_TW/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3860,7 +3860,7 @@ msgid "Last modified"
 
msgstr "最後修改"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最後的遞交者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
rhodecode/lib/base.py
Show inline comments
 
@@ -43,15 +43,17 @@ def _get_ip_addr(environ):
 

	
 
    ip = environ.get(proxy_key2)
 
    if ip:
 
        # HTTP_X_FORWARDED_FOR can have mutliple ips inside
 
        # the left-most being the original client, and each successive proxy
 
        # that passed the request adding the IP address where it received the
 
        # request from.
 
        if ',' in ip:
 
            ip = ip.split(',')[0].strip()
 
        return ip
 

	
 
    ip = environ.get(def_key, '0.0.0.0')
 

	
 
    # HEADERS can have mutliple ips inside
 
    # the left-most being the original client, and each successive proxy
 
    # that passed the request adding the IP address where it received the
 
    # request from.
 
    if ',' in ip:
 
        ip = ip.split(',')[0].strip()
 

	
 
    return ip
 

	
 

	
 
@@ -279,7 +281,6 @@ class BaseController(WSGIController):
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        start = time.time()
 
        try:
 
            self.ip_addr = _get_ip_addr(environ)
 
            # make sure that we update permissions each time we call controller
 
@@ -300,10 +301,6 @@ class BaseController(WSGIController):
 
            )
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            log.info('IP: %s Request to %s time: %.3fs' % (
 
                _get_ip_addr(environ),
 
                safe_unicode(_get_access_path(environ)), time.time() - start)
 
            )
 
            meta.Session.remove()
 

	
 

	
rhodecode/lib/celerylib/__init__.py
Show inline comments
 
@@ -59,6 +59,7 @@ class ResultWrapper(object):
 

	
 

	
 
def run_task(task, *args, **kwargs):
 
    global CELERY_ON
 
    if CELERY_ON:
 
        try:
 
            t = task.apply_async(args=args, kwargs=kwargs)
 
@@ -68,7 +69,6 @@ def run_task(task, *args, **kwargs):
 
        except socket.error, e:
 
            if isinstance(e, IOError) and e.errno == 111:
 
                log.debug('Unable to connect to celeryd. Sync execution')
 
                global CELERY_ON
 
                CELERY_ON = False
 
            else:
 
                log.error(traceback.format_exc())
rhodecode/lib/exceptions.py
Show inline comments
 
@@ -60,12 +60,17 @@ class StatusChangeOnClosedPullRequestErr
 

	
 
class HTTPLockedRC(HTTPClientError):
 
    """
 
    Special Exception For locked Repos in RhodeCode
 
    Special Exception For locked Repos in RhodeCode, the return code can
 
    be overwritten by _code keyword argument passed into constructors
 
    """
 
    code = 423
 
    title = explanation = 'Repository Locked'
 

	
 
    def __init__(self, reponame, username, *args, **kwargs):
 
        from rhodecode import CONFIG
 
        from rhodecode.lib.utils2 import safe_int
 
        _code = CONFIG.get('lock_ret_code')
 
        self.code = safe_int(_code, self.code)
 
        self.title = self.explanation = ('Repository `%s` locked by '
 
                                         'user `%s`' % (reponame, username))
 
        super(HTTPLockedRC, self).__init__(*args, **kwargs)
rhodecode/lib/helpers.py
Show inline comments
 
@@ -550,13 +550,18 @@ def action_parser(user_log, feed=False, 
 
            return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
 
                           class_='lazy-cs' if lazy_cs else '')
 

	
 
        def _get_op(rev_txt):
 
            _op = None
 
            _name = rev_txt
 
            if len(rev_txt.split('=>')) == 2:
 
                _op, _name = rev_txt.split('=>')
 
            return _op, _name
 

	
 
        revs = []
 
        if len(filter(lambda v: v != '', revs_ids)) > 0:
 
            repo = None
 
            for rev in revs_ids[:revs_top_limit]:
 
                _op = _name = None
 
                if len(rev.split('=>')) == 2:
 
                    _op, _name = rev.split('=>')
 
                _op, _name = _get_op(rev)
 

	
 
                # we want parsed changesets, or new log store format is bad
 
                if parse_cs:
 
@@ -583,6 +588,10 @@ def action_parser(user_log, feed=False, 
 
            [lnk(rev, repo_name) for rev in revs[:revs_limit]]
 
            )
 
        )
 
        _op1, _name1 = _get_op(revs_ids[0])
 
        _op2, _name2 = _get_op(revs_ids[-1])
 

	
 
        _rev = '%s...%s' % (_name1, _name2)
 

	
 
        compare_view = (
 
            ' <div class="compare_view tooltip" title="%s">'
 
@@ -591,7 +600,7 @@ def action_parser(user_log, feed=False, 
 
                    revs_ids[0][:12], revs_ids[-1][:12]
 
                ),
 
                url('changeset_home', repo_name=repo_name,
 
                    revision='%s...%s' % (revs_ids[0], revs_ids[-1])
 
                    revision=_rev
 
                ),
 
                _('compare view')
 
            )
rhodecode/lib/hooks.py
Show inline comments
 
@@ -36,7 +36,7 @@ from rhodecode.lib.utils import action_l
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.exceptions import HTTPLockedRC
 
from rhodecode.lib.utils2 import safe_str, datetime_to_time
 
from rhodecode.lib.utils2 import safe_str
 
from rhodecode.model.db import Repository, User
 

	
 

	
 
@@ -113,7 +113,14 @@ def pre_push(ui, repo, **kwargs):
 
    usr = User.get_by_username(username)
 
    if locked_by[0] and usr.user_id != int(locked_by[0]):
 
        locked_by = User.get(locked_by[0]).username
 
        raise HTTPLockedRC(repository, locked_by)
 
        # this exception is interpreted in git/hg middlewares and based
 
        # on that proper return code is server to client
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
        else:
 
            raise _http_ret
 

	
 

	
 
def pre_pull(ui, repo, **kwargs):
 
@@ -139,7 +146,14 @@ def pre_pull(ui, repo, **kwargs):
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        raise HTTPLockedRC(repository, locked_by)
 
        # this exception is interpreted in git/hg middlewares and based
 
        # on that proper return code is server to client
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
        else:
 
            raise _http_ret
 

	
 

	
 
def log_pull_action(ui, repo, **kwargs):
 
@@ -159,12 +173,14 @@ def log_pull_action(ui, repo, **kwargs):
 
        repository = extras['repository']
 
        scm = extras['scm']
 
        make_lock = extras['make_lock']
 
        locked_by = extras['locked_by']
 
        ip = extras['ip']
 
    elif 'username' in rc_extras:
 
        username = rc_extras['username']
 
        repository = rc_extras['repository']
 
        scm = rc_extras['scm']
 
        make_lock = rc_extras['make_lock']
 
        locked_by = rc_extras['locked_by']
 
        ip = rc_extras['ip']
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 
@@ -185,6 +201,12 @@ def log_pull_action(ui, repo, **kwargs):
 
        #msg = 'Made lock on repo `%s`' % repository
 
        #sys.stdout.write(msg)
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
    return 0
 

	
 

	
 
@@ -207,15 +229,19 @@ def log_push_action(ui, repo, **kwargs):
 
        repository = extras['repository']
 
        scm = extras['scm']
 
        make_lock = extras['make_lock']
 
        locked_by = extras['locked_by']
 
        action = extras['action']
 
    elif 'username' in rc_extras:
 
        username = rc_extras['username']
 
        repository = rc_extras['repository']
 
        scm = rc_extras['scm']
 
        make_lock = rc_extras['make_lock']
 
        locked_by = rc_extras['locked_by']
 
        action = extras['action']
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 

	
 
    action = 'push' + ':%s'
 
    action = action + ':%s'
 

	
 
    if scm == 'hg':
 
        node = kwargs['node']
 
@@ -255,6 +281,13 @@ def log_push_action(ui, repo, **kwargs):
 
        msg = 'Released lock on repo `%s`\n' % repository
 
        sys.stdout.write(msg)
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 

	
 
    return 0
 

	
 

	
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
@@ -234,7 +234,8 @@ class SimpleGit(BaseVCSController):
 
            app = self.__make_app(repo_name, repo_path, extras)
 
            return app(environ, start_response)
 
        except HTTPLockedRC, e:
 
            log.debug('Repository LOCKED ret code 423!')
 
            _code = CONFIG.get('lock_ret_code')
 
            log.debug('Repository LOCKED ret code %s!' % (_code))
 
            return e(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
rhodecode/lib/middleware/simplehg.py
Show inline comments
 
@@ -199,7 +199,8 @@ class SimpleHg(BaseVCSController):
 
            if str(e).find('not found') != -1:
 
                return HTTPNotFound()(environ, start_response)
 
        except HTTPLockedRC, e:
 
            log.debug('Repository LOCKED ret code 423!')
 
            _code = CONFIG.get('lock_ret_code')
 
            log.debug('Repository LOCKED ret code %s!' % (_code))
 
            return e(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
rhodecode/lib/middleware/wrapper.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.wrapper
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    request time mesuring app
 

	
 
    :created_on: May 23, 2013
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# 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 General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import time
 
import logging
 
from rhodecode.lib.base import _get_ip_addr, _get_access_path
 
from rhodecode.lib.utils2 import safe_unicode
 

	
 

	
 
class RequestWrapper(object):
 

	
 
    def __init__(self, app, config):
 
        self.application = app
 
        self.config = config
 

	
 
    def __call__(self, environ, start_response):
 
        start = time.time()
 
        try:
 
            return self.application(environ, start_response)
 
        finally:
 
            log = logging.getLogger('rhodecode.' + self.__class__.__name__)
 
            log.info('IP: %s Request to %s time: %.3fs' % (
 
                _get_ip_addr(environ),
 
                safe_unicode(_get_access_path(environ)), time.time() - start)
 
            )
rhodecode/lib/utils.py
Show inline comments
 
@@ -240,7 +240,7 @@ def is_valid_repo(repo_name, base_path, 
 
        return False
 

	
 

	
 
def is_valid_repos_group(repos_group_name, base_path):
 
def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
 
    """
 
    Returns True if given path is a repos group False otherwise
 

	
 
@@ -263,7 +263,7 @@ def is_valid_repos_group(repos_group_nam
 
        pass
 

	
 
    # check if it's a valid path
 
    if os.path.isdir(full_path):
 
    if skip_path_check or os.path.isdir(full_path):
 
        return True
 

	
 
    return False
 
@@ -495,7 +495,6 @@ def repo2db_mapper(initial_repo_list, re
 
                    #don't hold further removals on error
 
                    log.error(traceback.format_exc())
 
                    sa.rollback()
 

	
 
    return added, removed
 

	
 

	
rhodecode/lib/utils2.py
Show inline comments
 
@@ -565,11 +565,15 @@ def fix_PATH(os_=None):
 

	
 

	
 
def obfuscate_url_pw(engine):
 
    from sqlalchemy.engine import url
 
    url = url.make_url(engine)
 
    if url.password:
 
        url.password = 'XXXXX'
 
    return str(url)
 
    _url = engine or ''
 
    from sqlalchemy.engine import url as sa_url
 
    try:
 
        _url = sa_url.make_url(engine)
 
        if _url.password:
 
            _url.password = 'XXXXX'
 
    except:
 
        pass
 
    return str(_url)
 

	
 

	
 
def get_server_url(environ):
rhodecode/lib/vcs/backends/base.py
Show inline comments
 
@@ -9,7 +9,7 @@
 
    :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
 
"""
 

	
 

	
 
import datetime
 
from itertools import chain
 
from rhodecode.lib.vcs.utils import author_name, author_email
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
@@ -311,6 +311,27 @@ class BaseRepository(object):
 
        """
 
        raise NotImplementedError
 

	
 
    def inject_ui(self, **extras):
 
        """
 
        Injects extra parameters into UI object of this repo
 
        """
 
        required_extras = [
 
            'ip',
 
            'username',
 
            'action',
 
            'repository',
 
            'scm',
 
            'config',
 
            'server_url',
 
            'make_lock',
 
            'locked_by',
 
        ]
 
        for req in required_extras:
 
            if req not in extras:
 
                raise AttributeError('Missing attribute %s in extras' % (req))
 
        for k, v in extras.items():
 
            self._repo.ui.setconfig('rhodecode_extras', k, v)
 

	
 

	
 
class BaseChangeset(object):
 
    """
 
@@ -433,28 +454,28 @@ class BaseChangeset(object):
 
        raise NotImplementedError
 

	
 
    @LazyProperty
 
    def commiter(self):
 
    def committer(self):
 
        """
 
        Returns Commiter for given commit
 
        Returns Committer for given commit
 
        """
 

	
 
        raise NotImplementedError
 

	
 
    @LazyProperty
 
    def commiter_name(self):
 
    def committer_name(self):
 
        """
 
        Returns Author name for given commit
 
        """
 

	
 
        return author_name(self.commiter)
 
        return author_name(self.committer)
 

	
 
    @LazyProperty
 
    def commiter_email(self):
 
    def committer_email(self):
 
        """
 
        Returns Author email address for given commit
 
        """
 

	
 
        return author_email(self.commiter)
 
        return author_email(self.committer)
 

	
 
    @LazyProperty
 
    def author(self):
 
@@ -959,12 +980,12 @@ class EmptyChangeset(BaseChangeset):
 
    """
 

	
 
    def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
 
                 alias=None, revision=-1, message='', author='', date=''):
 
                 alias=None, revision=-1, message='', author='', date=None):
 
        self._empty_cs = cs
 
        self.revision = revision
 
        self.message = message
 
        self.author = author
 
        self.date = date
 
        self.date = date or datetime.datetime.fromtimestamp(0)
 
        self.repository = repo
 
        self.requested_revision = requested_revision
 
        self.alias = alias
rhodecode/lib/vcs/backends/git/changeset.py
Show inline comments
 
@@ -17,6 +17,7 @@ from rhodecode.lib.vcs.nodes import File
 
from rhodecode.lib.vcs.utils import safe_unicode
 
from rhodecode.lib.vcs.utils import date_fromtimestamp
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.utils2 import safe_int
 

	
 

	
 
class GitChangeset(BaseChangeset):
 
@@ -41,7 +42,7 @@ class GitChangeset(BaseChangeset):
 
        self._commit = commit
 

	
 
        self._tree_id = commit.tree
 
        self._commiter_property = 'committer'
 
        self._committer_property = 'committer'
 
        self._author_property = 'author'
 
        self._date_property = 'commit_time'
 
        self._date_tz_property = 'commit_timezone'
 
@@ -53,8 +54,8 @@ class GitChangeset(BaseChangeset):
 
        self._paths = {}
 

	
 
    @LazyProperty
 
    def commiter(self):
 
        return safe_unicode(getattr(self._commit, self._commiter_property))
 
    def committer(self):
 
        return safe_unicode(getattr(self._commit, self._committer_property))
 

	
 
    @LazyProperty
 
    def author(self):
 
@@ -275,10 +276,9 @@ class GitChangeset(BaseChangeset):
 
        """
 
        Returns last commit of the file at the given ``path``.
 
        """
 
        node = self.get_node(path)
 
        return node.history[0]
 
        return self.get_file_history(path, limit=1)[0]
 

	
 
    def get_file_history(self, path):
 
    def get_file_history(self, path, limit=None):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 
@@ -287,11 +287,16 @@ class GitChangeset(BaseChangeset):
 
        which is generally not good. Should be replaced with algorithm
 
        iterating commits.
 
        """
 

	
 
        self._get_filectx(path)
 

	
 
        cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                  self.id, path
 
               )
 
        if limit:
 
            cmd = 'log -n %s --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                      safe_int(limit, 0), self.id, path
 
                   )
 
        else:
 
            cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                      self.id, path
 
                   )
 
        so, se = self.repository.run_git_command(cmd)
 
        ids = re.findall(r'[0-9a-fA-F]{40}', so)
 
        return [self.repository.get_changeset(id) for id in ids]
rhodecode/lib/vcs/backends/git/repository.py
Show inline comments
 
@@ -67,14 +67,12 @@ class GitRepository(BaseRepository):
 
    @ThreadLocalLazyProperty
 
    def _repo(self):
 
        repo = Repo(self.path)
 
        #temporary set that to now at later we will move it to constructor
 
        baseui = None
 
        if baseui is None:
 
        # patch the instance of GitRepo with an "FAKE" ui object to add
 
        # compatibility layer with Mercurial
 
        if not hasattr(repo, 'ui'):
 
            from mercurial.ui import ui
 
            baseui = ui()
 
        # patch the instance of GitRepo with an "FAKE" ui object to add
 
        # compatibility layer with Mercurial
 
        setattr(repo, 'ui', baseui)
 
            setattr(repo, 'ui', baseui)
 
        return repo
 

	
 
    @property
 
@@ -306,6 +304,15 @@ class GitRepository(BaseRepository):
 
            url = ':///'.join(('file', url))
 
        return url
 

	
 
    def get_hook_location(self):
 
        """
 
        returns absolute path to location where hooks are stored
 
        """
 
        loc = os.path.join(self.path, 'hooks')
 
        if not self.bare:
 
            loc = os.path.join(self.path, '.git', 'hooks')
 
        return loc
 

	
 
    @LazyProperty
 
    def name(self):
 
        return os.path.basename(self.path)
rhodecode/lib/vcs/backends/hg/changeset.py
Show inline comments
 
@@ -44,8 +44,8 @@ class MercurialChangeset(BaseChangeset):
 
        return safe_unicode(self._ctx.description())
 

	
 
    @LazyProperty
 
    def commiter(self):
 
        return safe_unicode(self.auhtor)
 
    def committer(self):
 
        return safe_unicode(self.author)
 

	
 
    @LazyProperty
 
    def author(self):
 
@@ -219,19 +219,23 @@ class MercurialChangeset(BaseChangeset):
 
        """
 
        Returns last commit of the file at the given ``path``.
 
        """
 
        node = self.get_node(path)
 
        return node.history[0]
 
        return self.get_file_history(path, limit=1)[0]
 

	
 
    def get_file_history(self, path):
 
    def get_file_history(self, path, limit=None):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 
        """
 
        fctx = self._get_filectx(path)
 
        nodes = [fctx.filectx(x).node() for x in fctx.filelog()]
 
        changesets = [self.repository.get_changeset(hex(node))
 
            for node in reversed(nodes)]
 
        return changesets
 
        hist = []
 
        cnt = 0
 
        for cs in reversed([x for x in fctx.filelog()]):
 
            cnt += 1
 
            hist.append(hex(fctx.filectx(cs).node()))
 
            if limit and cnt == limit:
 
                break
 

	
 
        return [self.repository.get_changeset(node) for node in hist]
 

	
 
    def get_file_annotate(self, path):
 
        """
rhodecode/lib/vcs/backends/hg/repository.py
Show inline comments
 
@@ -422,6 +422,12 @@ class MercurialRepository(BaseRepository
 
            url = "file:" + urllib.pathname2url(url)
 
        return url
 

	
 
    def get_hook_location(self):
 
        """
 
        returns absolute path to location where hooks are stored
 
        """
 
        return os.path.join(self.path, '.hg', '.hgrc')
 

	
 
    def get_changeset(self, revision=None):
 
        """
 
        Returns ``MercurialChangeset`` object representing repository's
 
@@ -492,7 +498,7 @@ class MercurialRepository(BaseRepository
 
        """
 
        return MercurialWorkdir(self)
 

	
 
    def get_config_value(self, section, name, config_file=None):
 
    def get_config_value(self, section, name=None, config_file=None):
 
        """
 
        Returns configuration value for a given [``section``] and ``name``.
 

	
rhodecode/lib/vcs/utils/lazy.py
Show inline comments
 
class _Missing(object):
 

	
 
    def __repr__(self):
 
        return 'no value'
 

	
 
    def __reduce__(self):
 
        return '_missing'
 

	
 
_missing = _Missing()
 

	
 

	
 
class LazyProperty(object):
 
    """
 
    Decorator for easier creation of ``property`` from potentially expensive to
 
@@ -24,8 +35,11 @@ class LazyProperty(object):
 
    def __get__(self, obj, klass=None):
 
        if obj is None:
 
            return self
 
        result = obj.__dict__[self.__name__] = self._func(obj)
 
        return result
 
        value = obj.__dict__.get(self.__name__, _missing)
 
        if value is _missing:
 
            value = self._func(obj)
 
            obj.__dict__[self.__name__] = value
 
        return value
 

	
 
import threading
 

	
 
@@ -41,5 +55,8 @@ class ThreadLocalLazyProperty(LazyProper
 
        if not hasattr(obj, '__tl_dict__'):
 
            obj.__tl_dict__ = threading.local().__dict__
 

	
 
        result = obj.__tl_dict__[self.__name__] = self._func(obj)
 
        return result
 
        value = obj.__tl_dict__.get(self.__name__, _missing)
 
        if value is _missing:
 
            value = self._func(obj)
 
            obj.__tl_dict__[self.__name__] = value
 
        return value
rhodecode/model/db.py
Show inline comments
 
@@ -47,7 +47,7 @@ from rhodecode.lib.vcs.utils.lazy import
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 
from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
 
    safe_unicode, remove_suffix, remove_prefix
 
    safe_unicode, remove_suffix, remove_prefix, time_to_datetime
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.caching_query import FromCache
 

	
 
@@ -938,15 +938,7 @@ class Repository(Base, BaseModel):
 

	
 
    @classmethod
 
    def inject_ui(cls, repo, extras={}):
 
        from rhodecode.lib.vcs.backends.hg import MercurialRepository
 
        from rhodecode.lib.vcs.backends.git import GitRepository
 
        required = (MercurialRepository, GitRepository)
 
        if not isinstance(repo, required):
 
            raise Exception('repo must be instance of %s' % required)
 

	
 
        # inject ui extra param to log this action via push logger
 
        for k, v in extras.items():
 
            repo._repo.ui.setconfig('rhodecode_extras', k, v)
 
        repo.inject_ui(extras)
 

	
 
    @classmethod
 
    def is_valid(cls, repo_name):
 
@@ -980,7 +972,11 @@ class Repository(Base, BaseModel):
 
            enable_statistics=repo.enable_statistics,
 
            enable_locking=repo.enable_locking,
 
            enable_downloads=repo.enable_downloads,
 
            last_changeset=repo.changeset_cache
 
            last_changeset=repo.changeset_cache,
 
            locked_by=User.get(self.locked[0]).get_api_data() \
 
                if self.locked[0] else None,
 
            locked_date=time_to_datetime(self.locked[1]) \
 
                if self.locked[1] else None
 
        )
 
        rc_config = RhodeCodeSetting.get_app_settings()
 
        repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
 
@@ -1002,6 +998,10 @@ class Repository(Base, BaseModel):
 
        Session().add(repo)
 
        Session().commit()
 

	
 
    @classmethod
 
    def getlock(cls, repo):
 
        return repo.locked
 

	
 
    @property
 
    def last_db_change(self):
 
        return self.updated_on
 
@@ -1341,15 +1341,13 @@ class RepoGroup(Base, BaseModel):
 

	
 
        return cnt + children_count(self)
 

	
 
    def recursive_groups_and_repos(self):
 
        """
 
        Recursive return all groups, with repositories in those groups
 
        """
 
    def _recursive_objects(self, include_repos=True):
 
        all_ = []
 

	
 
        def _get_members(root_gr):
 
            for r in root_gr.repositories:
 
                all_.append(r)
 
            if include_repos:
 
                for r in root_gr.repositories:
 
                    all_.append(r)
 
            childs = root_gr.children.all()
 
            if childs:
 
                for gr in childs:
 
@@ -1359,6 +1357,18 @@ class RepoGroup(Base, BaseModel):
 
        _get_members(self)
 
        return [self] + all_
 

	
 
    def recursive_groups_and_repos(self):
 
        """
 
        Recursive return all groups, with repositories in those groups
 
        """
 
        return self._recursive_objects()
 

	
 
    def recursive_groups(self):
 
        """
 
        Returns all children groups for this group including children of children
 
        """
 
        return self._recursive_objects(include_repos=False)
 

	
 
    def get_new_name(self, group_name):
 
        """
 
        returns new full group name based on parent and new name
 
@@ -1728,7 +1738,7 @@ class CacheInvalidation(Base, BaseModel)
 
            for inv_obj in inv_objs:
 
                inv_obj.cache_active = False
 
                log.debug('marking %s key for invalidation based on key=%s,repo_name=%s'
 
                  % (inv_obj, key, repo_name))
 
                  % (inv_obj, key, safe_str(repo_name)))
 
                invalidated_keys.append(inv_obj.cache_key)
 
                Session().add(inv_obj)
 
            Session().commit()
rhodecode/model/forms.py
Show inline comments
 
@@ -395,4 +395,7 @@ def PullRequestForm(repo_id):
 
        pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
 
        pullrequest_desc = v.UnicodeString(strip=True, required=False)
 

	
 
        ancestor_rev = v.UnicodeString(strip=True, required=True)
 
        merge_rev = v.UnicodeString(strip=True, required=True)
 

	
 
    return _PullRequestForm
rhodecode/model/pull_request.py
Show inline comments
 
@@ -161,7 +161,7 @@ class PullRequestModel(BaseModel):
 
        pull_request.updated_on = datetime.datetime.now()
 
        Session().add(pull_request)
 

	
 
    def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
 
    def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge):
 
        """
 
        Returns a list of changesets that can be merged from org_repo@org_ref
 
        to other_repo@other_ref ... and the ancestor that would be used for merge
 
@@ -211,16 +211,21 @@ class PullRequestModel(BaseModel):
 
            else:
 
                hgrepo = other_repo._repo
 

	
 
            revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
 
                    (other_rev, org_rev)]
 
            changesets = [other_repo.get_changeset(cs)
 
                          for cs in scmutil.revrange(hgrepo, revs)]
 
            if merge:
 
                revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" %
 
                        (other_rev, org_rev, org_rev)]
 

	
 
            if org_repo != other_repo:
 
                ancestors = scmutil.revrange(hgrepo,
 
                     ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
 
                if len(ancestors) == 1:
 
                    ancestor = hgrepo[ancestors[0]].hex()
 
            else:
 
                # TODO: have both + and - changesets
 
                revs = ["id('%s') :: id('%s') - id('%s')" %
 
                        (org_rev, other_rev, org_rev)]
 

	
 
            changesets = [other_repo.get_changeset(cs)
 
                          for cs in scmutil.revrange(hgrepo, revs)]
 

	
 
        elif alias == 'git':
 
            assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
 
@@ -233,7 +238,7 @@ class PullRequestModel(BaseModel):
 

	
 
        return changesets, ancestor
 

	
 
    def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
 
    def get_compare_data(self, org_repo, org_ref, other_repo, other_ref, merge):
 
        """
 
        Returns incoming changesets for mercurial repositories
 

	
 
@@ -251,5 +256,6 @@ class PullRequestModel(BaseModel):
 

	
 
        cs_ranges, ancestor = self._get_changesets(org_repo.scm_instance.alias,
 
                                                   org_repo.scm_instance, org_ref,
 
                                                   other_repo.scm_instance, other_ref)
 
                                                   other_repo.scm_instance, other_ref,
 
                                                   merge)
 
        return cs_ranges, ancestor
rhodecode/model/repo.py
Show inline comments
 
@@ -32,7 +32,7 @@ from datetime import datetime
 
from rhodecode.lib.vcs.backends import get_backend
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
 
    remove_prefix
 
    remove_prefix, obfuscate_url_pw
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.lib.hooks import log_create_repository, log_delete_repository
 

	
 
@@ -42,8 +42,6 @@ from rhodecode.model.db import Repositor
 
    RhodeCodeSetting, RepositoryField
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import HasRepoPermissionAny
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -640,7 +638,8 @@ class RepoModel(BaseModel):
 
            raise Exception('This path %s is a valid group' % repo_path)
 

	
 
        log.info('creating repo %s in %s @ %s' % (
 
                     repo_name, safe_unicode(repo_path), clone_uri
 
                     repo_name, safe_unicode(repo_path),
 
                     obfuscate_url_pw(clone_uri)
 
                )
 
        )
 
        backend = get_backend(alias)
rhodecode/model/repos_group.py
Show inline comments
 
@@ -249,27 +249,37 @@ class ReposGroupModel(BaseModel):
 

	
 
            # change properties
 
            repos_group.group_description = form_data['group_description']
 
            repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
 
            repos_group.group_parent_id = form_data['group_parent_id']
 
            repos_group.enable_locking = form_data['enable_locking']
 

	
 
            repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
 
            repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
 
            new_path = repos_group.full_path
 

	
 
            self.sa.add(repos_group)
 

	
 
            # iterate over all members of this groups and set the locking !
 
            # iterate over all members of this groups and do fixes
 
            # set locking if given
 
            # if obj is a repoGroup also fix the name of the group according
 
            # to the parent
 
            # if obj is a Repo fix it's name
 
            # this can be potentially heavy operation
 
            for obj in repos_group.recursive_groups_and_repos():
 
                #set the value from it's parent
 
                obj.enable_locking = repos_group.enable_locking
 
                if isinstance(obj, RepoGroup):
 
                    new_name = obj.get_new_name(obj.name)
 
                    log.debug('Fixing group %s to new name %s' \
 
                                % (obj.group_name, new_name))
 
                    obj.group_name = new_name
 
                elif isinstance(obj, Repository):
 
                    # we need to get all repositories from this new group and
 
                    # rename them accordingly to new group path
 
                    new_name = obj.get_new_name(obj.just_name)
 
                    log.debug('Fixing repo %s to new name %s' \
 
                                % (obj.repo_name, new_name))
 
                    obj.repo_name = new_name
 
                self.sa.add(obj)
 

	
 
            # we need to get all repositories from this new group and
 
            # rename them accordingly to new group path
 
            for r in repos_group.repositories:
 
                r.repo_name = r.get_new_name(r.just_name)
 
                self.sa.add(r)
 

	
 
            self.__rename_group(old_path, new_path)
 

	
 
            return repos_group
rhodecode/model/scm.py
Show inline comments
 
@@ -44,13 +44,14 @@ from rhodecode.lib.vcs.backends.base imp
 

	
 
from rhodecode import BACKENDS
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.utils2 import safe_str, safe_unicode
 
from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url
 
from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
 
from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
 
    action_logger, REMOVED_REPO_PAT
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
 
    UserFollowing, UserLog, User, RepoGroup, PullRequest
 
from rhodecode.lib.hooks import log_push_action
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -402,6 +403,60 @@ class ScmModel(BaseModel):
 
        self.sa.add(repo)
 
        return repo
 

	
 
    def _handle_push(self, repo, username, action, repo_name, revisions):
 
        """
 
        Triggers push action hooks
 

	
 
        :param repo: SCM repo
 
        :param username: username who pushes
 
        :param action: push/push_loca/push_remote
 
        :param repo_name: name of repo
 
        :param revisions: list of revisions that we pushed
 
        """
 
        from rhodecode import CONFIG
 
        from rhodecode.lib.base import _get_ip_addr
 
        try:
 
            from pylons import request
 
            environ = request.environ
 
        except TypeError:
 
            # we might use this outside of request context, let's fake the
 
            # environ data
 
            from webob import Request
 
            environ = Request.blank('').environ
 

	
 
        #trigger push hook
 
        extras = {
 
            'ip': _get_ip_addr(environ),
 
            'username': username,
 
            'action': 'push_local',
 
            'repository': repo_name,
 
            'scm': repo.alias,
 
            'config': CONFIG['__file__'],
 
            'server_url': get_server_url(environ),
 
            'make_lock': None,
 
            'locked_by': [None, None]
 
        }
 
        _scm_repo = repo._repo
 
        repo.inject_ui(**extras)
 
        if repo.alias == 'hg':
 
            log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0])
 
        elif repo.alias == 'git':
 
            log_push_action(_scm_repo.ui, _scm_repo, _git_revs=revisions)
 

	
 
    def _get_IMC_module(self, scm_type):
 
        """
 
        Returns InMemoryCommit class based on scm_type
 

	
 
        :param scm_type:
 
        """
 
        if scm_type == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import \
 
                MercurialInMemoryChangeset as IMC
 
        elif scm_type == 'git':
 
            from rhodecode.lib.vcs.backends.git import \
 
                GitInMemoryChangeset as IMC
 
        return IMC
 

	
 
    def pull_changes(self, repo, username):
 
        dbrepo = self.__get_repo(repo)
 
        clone_uri = dbrepo.clone_uri
 
@@ -409,26 +464,13 @@ class ScmModel(BaseModel):
 
            raise Exception("This repository doesn't have a clone uri")
 

	
 
        repo = dbrepo.scm_instance
 
        from rhodecode import CONFIG
 
        repo_name = dbrepo.repo_name
 
        try:
 
            extras = {
 
                'ip': '',
 
                'username': username,
 
                'action': 'push_remote',
 
                'repository': dbrepo.repo_name,
 
                'scm': repo.alias,
 
                'config': CONFIG['__file__'],
 
                'make_lock': None,
 
                'locked_by': [None, None]
 
            }
 

	
 
            Repository.inject_ui(repo, extras=extras)
 

	
 
            if repo.alias == 'git':
 
                repo.fetch(clone_uri)
 
            else:
 
                repo.pull(clone_uri)
 
            self.mark_for_invalidation(dbrepo.repo_name)
 
            self.mark_for_invalidation(repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 
@@ -441,13 +483,8 @@ class ScmModel(BaseModel):
 
        :param repo: SCM instance
 

	
 
        """
 

	
 
        if repo.alias == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import \
 
                MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from rhodecode.lib.vcs.backends.git import \
 
                GitInMemoryChangeset as IMC
 
        user = self._get_user(user)
 
        IMC = self._get_IMC_module(repo.alias)
 

	
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 
@@ -463,20 +500,21 @@ class ScmModel(BaseModel):
 
                       author=author,
 
                       parents=[cs], branch=cs.branch)
 

	
 
        action = 'push_local:%s' % tip.raw_id
 
        action_logger(user, action, repo_name)
 
        self.mark_for_invalidation(repo_name)
 
        self._handle_push(repo,
 
                          username=user.username,
 
                          action='push_local',
 
                          repo_name=repo_name,
 
                          revisions=[tip.raw_id])
 
        return tip
 

	
 
    def create_node(self, repo, repo_name, cs, user, author, message, content,
 
                      f_path):
 
        if repo.alias == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
 
        user = self._get_user(user)
 
        IMC = self._get_IMC_module(repo.alias)
 

	
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 

	
 
        if isinstance(content, (basestring,)):
 
            content = safe_str(content)
 
        elif isinstance(content, (file, cStringIO.OutputType,)):
 
@@ -502,9 +540,12 @@ class ScmModel(BaseModel):
 
                       author=author,
 
                       parents=parents, branch=cs.branch)
 

	
 
        action = 'push_local:%s' % tip.raw_id
 
        action_logger(user, action, repo_name)
 
        self.mark_for_invalidation(repo_name)
 
        self._handle_push(repo,
 
                          username=user.username,
 
                          action='push_local',
 
                          repo_name=repo_name,
 
                          revisions=[tip.raw_id])
 
        return tip
 

	
 
    def get_nodes(self, repo_name, revision, root_path='/', flat=True):
rhodecode/model/validators.py
Show inline comments
 
@@ -416,6 +416,8 @@ def ValidCloneUri():
 
                svnremoterepo(ui, url).capabilities
 
            elif url.startswith('git+http'):
 
                raise NotImplementedError()
 
            else:
 
                raise Exception('clone from URI %s not allowed' % (url))
 

	
 
        elif repo_type == 'git':
 
            from rhodecode.lib.vcs.backends.git.repository import GitRepository
 
@@ -427,6 +429,8 @@ def ValidCloneUri():
 
                raise NotImplementedError()
 
            elif url.startswith('hg+http'):
 
                raise NotImplementedError()
 
            else:
 
                raise Exception('clone from URI %s not allowed' % (url))
 

	
 
    class _validator(formencode.validators.FancyValidator):
 
        messages = {
rhodecode/public/css/codemirror.css
Show inline comments
 
@@ -171,4 +171,4 @@ div.CodeMirror span.CodeMirror-nonmatchi
 
    visibility: hidden;
 
  }
 

	
 
}
 
}
 
\ No newline at end of file
rhodecode/public/css/pygments.css
Show inline comments
 
@@ -14,7 +14,7 @@ div.codeblock {
 
div.codeblock .code-header {
 
    border-bottom: 1px solid #CCCCCC;
 
    background: #EEEEEE;
 
    padding:10px 0 10px 0;
 
    padding: 10px 0 10px 0;
 
}
 

	
 
div.codeblock .code-header .stats {
 
@@ -26,38 +26,38 @@ div.codeblock .code-header .stats {
 
}
 

	
 
div.codeblock .code-header .stats .left {
 
    float:left;
 
    float: left;
 
}
 
div.codeblock .code-header .stats .left.img {
 
    margin-top:-2px;
 
    margin-top: -2px;
 
}
 
div.codeblock .code-header .stats .left.item {
 
    float:left;
 
    float: left;
 
    padding: 0 9px 0 9px;
 
    border-right:1px solid #ccc;
 
    border-right: 1px solid #ccc;
 
}
 
div.codeblock .code-header .stats .left.item pre {
 
}
 
div.codeblock .code-header .stats .left.item.last {
 
    border-right:none;
 
    border-right: none;
 
}
 
div.codeblock .code-header .stats .buttons {
 
    float:right;
 
    padding-right:4px;
 
    float: right;
 
    padding-right: 4px;
 
}
 

	
 
div.codeblock .code-header .author {
 
    margin-left:25px;
 
    margin-left: 25px;
 
    font-weight: bold;
 
    height: 25px;
 
}
 
div.codeblock .code-header .author .user {
 
    padding-top:3px;
 
    padding-top: 3px;
 
}
 
div.codeblock .code-header .commit {
 
    margin-left:25px;
 
    margin-left: 25px;
 
    font-weight: normal;
 
    white-space:pre;
 
    white-space: pre;
 
}
 

	
 
div.codeblock .code-body table {
 
@@ -90,8 +90,8 @@ div.search-code-body pre .break {
 
    display: block;
 
}
 
div.annotatediv {
 
    margin-left:2px;
 
    margin-right:4px;
 
    margin-left: 2px;
 
    margin-right: 4px;
 
}
 
.code-highlight {
 
    padding: 0px;
 
@@ -170,4 +170,4 @@ div.annotatediv {
 
.code-highlight .vc, .codehilite .vc { color: #19177C } /* Name.Variable.Class */
 
.code-highlight .vg, .codehilite .vg { color: #19177C } /* Name.Variable.Global */
 
.code-highlight .vi, .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
 
.code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
 
.code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
 
\ No newline at end of file
rhodecode/public/css/style.css
Show inline comments
 
@@ -4143,11 +4143,11 @@ div.rst-block h2 {
 
    font-weight: normal;
 
}
 

	
 
div.rst-block  {
 
div.rst-block {
 
    background-color: #fafafa;
 
}
 

	
 
div.rst-block  {
 
div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
@@ -4420,7 +4420,7 @@ form.comment-inline-form {
 
    padding: 10px 20px;
 
}
 

	
 
.inline-comments div.rst-block  {
 
.inline-comments div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
@@ -4811,4 +4811,4 @@ div.comment:target>.comment-wrapp {
 
.lineno:target a {
 
    border: solid 2px #ee0 !important;
 
    margin: -2px;
 
}
 
}
 
\ No newline at end of file
rhodecode/public/js/graph.js
Show inline comments
 
@@ -26,7 +26,7 @@ function BranchRenderer() {
 
	
 
	this.canvas = document.getElementById("graph_canvas");
 
	
 
	if (!document.createElement("canvas").getContext) 
 
	if (!document.createElement("canvas").getContext)
 
		this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
 
	this.ctx = this.canvas.getContext('2d');
 
	this.ctx.strokeStyle = 'rgb(0, 0, 0)';
rhodecode/public/js/rhodecode.js
Show inline comments
 
@@ -86,19 +86,6 @@ var prevElementSibling = function( el ) 
 
    }
 
}
 

	
 
var setSelectValue = function(select, val){
 
	var selection =  YUD.get(select);
 
	
 
    // select element
 
    for(var i=0;i<selection.options.length;i++){
 
        if (selection.options[i].innerHTML == val) {
 
            selection.selectedIndex = i;
 
            break;
 
        }
 
    }	
 
}
 

	
 

	
 
/**
 
 * SmartColorGenerator
 
 *
 
@@ -577,7 +564,7 @@ var showRepoSize = function(target, repo
 
    var args= 'auth_token='+token;
 
    
 
    if(!YUD.hasClass(target, 'loaded')){
 
        YUD.get(target).innerHTML = _TM['loading...'];
 
        YUD.get(target).innerHTML = _TM['Loading ...'];
 
        var url = pyroutes.url('repo_size', {"repo_name":repo_name});
 
        YUC.asyncRequest('POST',url,{
 
            success:function(o){
 
@@ -910,7 +897,7 @@ var deleteComment = function(comment_id)
 

	
 
var createInlineAddButton = function(tr){
 

	
 
	var label = TRANSLATION_MAP['add another comment'];
 
	var label = TRANSLATION_MAP['Add another comment'];
 
	
 
	var html_el = document.createElement('div');
 
	YUD.addClass(html_el, 'add-comment');
 
@@ -1106,7 +1093,7 @@ var fileBrowserListeners = function(curr
 
	                    match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
 
	                }
 
	                if(match.length >= matches_max){
 
	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['search truncated']));
 
	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
 
	                }
 
	            }                       
 
	        }
 
@@ -1115,7 +1102,7 @@ var fileBrowserListeners = function(curr
 
	            YUD.setStyle('tbody_filtered','display','');
 
	            
 
	            if (match.length==0){
 
	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['no matching files']));
 
	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
 
	            }                           
 
	            
 
	            YUD.get('tbody_filtered').innerHTML = match.join("");   
 
@@ -2173,11 +2160,11 @@ YUE.onDOMReady(function(){
 
	    console.log(t);
 
		if(YUD.hasClass(t, 'hidden')){
 
			YUD.removeClass(t, 'hidden');
 
			YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['collapse diff']);
 
			YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['Collapse diff']);
 
		}
 
		else if(!YUD.hasClass(t, 'hidden')){
 
			YUD.addClass(t, 'hidden');
 
			YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['expand diff']);
 
			YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['Expand diff']);
 
		}
 
	});
 
	
rhodecode/templates/admin/users/user_edit.html
Show inline comments
 
@@ -43,11 +43,14 @@
 
                <label>${_('API key')}:</label> ${c.user.api_key}
 
            </div>
 
        </div>
 
        ##show current ip just if we show ourself
 
        %if c.rhodecode_user.username == c.user.username:
 
        <div class="field">
 
            <div class="label">
 
                <label>${_('Current IP')}:</label> ${c.perm_user.ip_addr or "?"}
 
            </div>
 
        </div>
 
        %endif
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
rhodecode/templates/admin/users/user_edit_my_account_form.html
Show inline comments
 
@@ -20,6 +20,11 @@
 
                    <label>${_('API key')}</label> ${c.user.api_key}
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label>${_('Current IP')}:</label> ${c.perm_user.ip_addr or "?"}
 
                </div>
 
            </div>
 
            <div class="fields">
 
                 <div class="field">
 
                    <div class="label">
rhodecode/templates/base/root.html
Show inline comments
 
@@ -41,21 +41,21 @@
 
            <script type="text/javascript">
 
            //JS translations map
 
            var TRANSLATION_MAP = {
 
                'add another comment':'${_("add another comment")}',
 
                'Add another comment':'${_("Add another comment")}',
 
                'Stop following this repository':"${_('Stop following this repository')}",
 
                'Start following this repository':"${_('Start following this repository')}",
 
                'Group':"${_('Group')}",
 
                'members':"${_('members')}",
 
                'loading...':"${_('loading...')}",
 
                'search truncated': "${_('search truncated')}",
 
                'no matching files': "${_('no matching files')}",
 
                'Loading ...':"${_('Loading ...')}",
 
                'Search truncated': "${_('Search truncated')}",
 
                'No matching files': "${_('No matching files')}",
 
                'Open new pull request': "${_('Open new pull request')}",
 
                'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
 
                'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
 
                'Show selected change __S': "${_('Show selected change __S')}",
 
                'Selection link': "${_('Selection link')}",
 
                'collapse diff': "${_('collapse diff')}",
 
                'expand diff': "${_('expand diff')}",
 
                'Collapse diff': "${_('Collapse diff')}",
 
                'Expand diff': "${_('Expand diff')}"
 
            };
 
            var _TM = TRANSLATION_MAP;
 

	
rhodecode/templates/changelog/changelog.html
Show inline comments
 
modified file chmod 100644 => 100755
 
@@ -25,15 +25,15 @@ ${self.context_bar('changelog')}
 
    <div class="table">
 
        % if c.pagination:
 
            <div id="graph">
 
                <div class="info_box" style="clear: both;padding: 10px 6px;text-align: right;">
 
                    <div class="info_box" style="clear: both;padding: 10px 6px;min-height: 12px;text-align: right;">
 
                    <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
 
                    <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
 

	
 
                    %if c.rhodecode_db_repo.fork:
 
                        <a title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default')}" class="ui-btn small">${_('Compare fork with parent')}</a>
 
                        <a id="compare_fork" title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default',merge=1)}" class="ui-btn small">${_('Compare fork with parent')}</a>
 
                    %endif
 
                    %if h.is_hg(c.rhodecode_repo):
 
                    <a id="open_new_pr" href="${h.url('pullrequest_form',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
 
                    <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
 
                    %endif
 
                </div>
 
                <div class="container_header">
 
@@ -125,8 +125,7 @@ ${self.context_bar('changelog')}
 
                var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
 
                var pr_tmpl = "${h.url('pullrequest_home',repo_name=c.repo_name)}";
 

	
 
                var checkbox_checker = function(e){
 
                    var clicked_cb = e.currentTarget;
 
                    var checkbox_checker = function(e){
 
                    var checked_checkboxes = [];
 
                    for (pos in checkboxes){
 
                        if(checkboxes[pos].checked){
 
@@ -134,13 +133,17 @@ ${self.context_bar('changelog')}
 
                        }
 
                    }
 
                    if(YUD.get('open_new_pr')){
 
                        if(checked_checkboxes.length>0){
 
                            // modify open pull request to show we have selected cs
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
 
                        }else{
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
 
                            if(checked_checkboxes.length>1){
 
                              YUD.setStyle('open_new_pr','display','none');
 
                            } else {
 
                               YUD.setStyle('open_new_pr','display','');
 
                            if(checked_checkboxes.length>0){
 
                              YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
 
                            }else{
 
                              YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
 
                            }
 
                          }
 
                        }
 
                    }
 

	
 
                    if(checked_checkboxes.length>0){
 
                        var rev_end = checked_checkboxes[0].name;
 
@@ -160,20 +163,25 @@ ${self.context_bar('changelog')}
 
                        YUD.setStyle('rev_range_clear','display','');
 

	
 
                        YUD.get('open_new_pr').href = pr_tmpl + '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
 

	
 
                            YUD.setStyle('compare_fork','display','none');
 
                    } else{
 
                        YUD.setStyle('rev_range_container','display','none');
 
                        YUD.setStyle('rev_range_clear','display','none');
 
                    }
 
                };
 
                YUE.onDOMReady(checkbox_checker);
 
                YUE.on(checkboxes,'click', checkbox_checker);
 
                            if (checkboxes){
 
                                YUD.get('open_new_pr').href = pr_tmpl + '?rev_end={0}'.format(checkboxes[0].name);
 
                            }
 
                            YUD.setStyle('compare_fork','display','');
 
                        }
 
                    };
 
                    YUE.onDOMReady(checkbox_checker);
 
                    YUE.on(checkboxes,'click', checkbox_checker);
 

	
 
                YUE.on('rev_range_clear','click',function(e){
 
                    for (var i=0; i<checkboxes.length; i++){
 
                        var cb = checkboxes[i];
 
                        cb.checked = false;
 
                    }
 
                        checkbox_checker();
 
                    YUE.preventDefault(e);
 
                });
 

	
rhodecode/templates/changeset/diff_block.html
Show inline comments
 
@@ -52,7 +52,7 @@
 
          <div class="changeset_header">
 
              <div class="changeset_file">
 
                  ${h.safe_unicode(filenode_path)} |
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.other_repo.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}" title="${_('show file at initial version in this repo')}">${c.other_ref_type}@${h.short_id(c.other_ref) if c.other_ref_type=='rev' else c.other_ref}</a>
 
              </div>
 
          </div>
rhodecode/templates/compare/compare_cs.html
Show inline comments
 
## Changesets table !
 
<div class="container">
 
  <table class="compare_view_commits noborder">
 
  %if not c.cs_ranges:
 
    <span class="empty_data">${_('No changesets')}</span>
 
  %else:
 
    %for cnt, cs in enumerate(c.cs_ranges):
 
    <table class="compare_view_commits noborder">
 
    %for cs in reversed(c.cs_ranges):
 
        <tr>
 
        <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
 
        <td>
 
@@ -22,7 +22,15 @@
 
        <td><div class="message tooltip" title="${h.tooltip(cs.message)}" style="white-space:normal">${h.urlify_commit(h.shorter(cs.message, 60),c.repo_name)}</div></td>
 
        </tr>
 
    %endfor
 

	
 
    </table>
 
    %if c.ancestor:
 
    <span class="ancestor">${_('Ancestor')}:
 
      ${h.link_to(h.short_id(c.ancestor),h.url('changeset_home',repo_name=c.repo_name,revision=c.ancestor))}
 
    </span>
 
    %endif
 
    %if c.as_form:
 
      ${h.hidden('ancestor_rev',c.ancestor)}
 
      ${h.hidden('merge_rev',c.cs_ranges[-1].raw_id)}
 
    %endif
 
  %endif
 
  </table>
 
</div>
rhodecode/templates/email_templates/pull_request.html
Show inline comments
 
@@ -10,10 +10,9 @@ ${body}
 
</p>
 

	
 
<div>${_('revisions for reviewing')}</div>
 
<pre>
 
<p style="white-space: pre-wrap;">
 
%for r,r_msg in pr_revisions:
 
${h.short_id(r)}:
 
    ${h.shorter(r_msg, 256)}
 

	
 
<b>${h.short_id(r)}</b>:
 
${h.shorter(r_msg, 256)}
 
%endfor
 
</pre>
 
</p>
rhodecode/templates/files/files_browser.html
Show inline comments
 
@@ -49,7 +49,7 @@
 
                    <th>${_('Mimetype')}</th>
 
                    <th>${_('Last Revision')}</th>
 
                    <th>${_('Last modified')}</th>
 
                    <th>${_('Last commiter')}</th>
 
                    <th>${_('Last committer')}</th>
 
                </tr>
 
            </thead>
 

	
 
@@ -89,8 +89,8 @@
 
                     <td>
 
                         %if node.is_file():
 
                             <div class="tooltip" title="${h.tooltip(node.last_changeset.message)}">
 
                             <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
 
                            </div>
 
                              <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
 
                             </div>
 
                         %endif
 
                     </td>
 
                     <td>
rhodecode/templates/pullrequests/pullrequest.html
Show inline comments
 
@@ -21,9 +21,6 @@
 
    </div>
 
    ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
 
    <div style="float:left;padding:0px 30px 30px 30px">
 
        <input type="hidden" name="rev_start" value="${request.GET.get('rev_start')}" />
 
        <input type="hidden" name="rev_end" value="${request.GET.get('rev_end')}" />
 

	
 
        ##ORG
 
        <div style="float:left">
 
            <div>
 
@@ -101,7 +98,7 @@
 

	
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="pullrequest_desc">${_('description')}:</label>
 
                    <label for="pullrequest_desc">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('pullrequest_desc',size=30)}
 
@@ -125,8 +122,31 @@
 

	
 
  var other_repos_info = ${c.other_repos_info|n};
 

	
 
  var otherrepoChanged = function(){
 
      var sel_box = YUQ('#pull_request_form #other_repo')[0];
 
      var repo_name = sel_box.options[sel_box.selectedIndex].value;
 

	
 
      YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
 
      // replace options of other_ref with the ones for the current other_repo
 
      var other_ref_selector = YUD.get('other_ref');
 
      var new_select = YUD.createElementFromMarkup(other_repos_info[repo_name]['revs']);
 
      var new_selectedIndex = new_select.selectedIndex;
 
      other_ref_selector.innerHTML = ""; // clear old options
 
      while (new_select.length > 0){ // children will be popped when appened to other_ref_selector
 
          other_ref_selector.appendChild(new_select.children[0]);
 
      }
 
      // browsers lost track of selected when appendChild was used
 
      other_ref_selector.selectedIndex = new_selectedIndex;
 

	
 
      // reset && add the reviewer based on selected repo
 
      var _data = other_repos_info[repo_name];
 
      YUD.get('review_members').innerHTML = '';
 
      addReviewMember(_data.user.user_id, _data.user.firstname,
 
                      _data.user.lastname, _data.user.username,
 
                      _data.user.gravatar_link);
 
  }
 

	
 
  var loadPreview = function(){
 
      YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
 
      //url template
 
      var url = "${h.url('compare_url',
 
                         repo_name='__other_repo__',
 
@@ -136,8 +156,8 @@
 
                         other_ref_type='__org_ref_type__',
 
                         other_ref='__org_ref__',
 
                         as_form=True,
 
                         rev_start=request.GET.get('rev_start',''),
 
                         rev_end=request.GET.get('rev_end',''))}";
 
                         merge=True,
 
                         )}";
 
      var org_repo = YUQ('#pull_request_form #org_repo')[0].value;
 
      var org_ref = YUQ('#pull_request_form #org_ref')[0].value.split(':');
 

	
 
@@ -159,22 +179,10 @@
 
      }
 

	
 
      YUD.get('pull_request_overview').innerHTML = "${_('Loading ...')}";
 
      ypjax(url,'pull_request_overview');
 

	
 
      YUD.get('pull_request_overview_url').href = url; // shouldn't have as_form ... but ...
 
      YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
 
      ypjax(url,'pull_request_overview', function(data){
 
          var sel_box = YUQ('#pull_request_form #other_repo')[0];
 
          var repo_name = sel_box.options[sel_box.selectedIndex].value;
 
          var _data = other_repos_info[repo_name];
 
          YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
 
          YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
          // select back the revision that was just compared
 
          setSelectValue(YUD.get('other_ref'), rev_data['other_ref']);
 
          // reset && add the reviewer based on selected repo
 
          YUD.get('review_members').innerHTML = '';
 
          addReviewMember(_data.user.user_id, _data.user.firstname,
 
                          _data.user.lastname, _data.user.username,
 
                          _data.user.gravatar_link);
 
      })
 
  }
 

	
 
  ## refresh automatically when something changes (org_repo can't change)
 
@@ -184,9 +192,7 @@
 
  });
 

	
 
  YUE.on('other_repo', 'change', function(e){
 
      var repo_name = e.currentTarget.value;
 
      // replace the <select> of changed repo
 
      YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
      otherrepoChanged();
 
      loadPreview();
 
  });
 

	
 
@@ -194,8 +200,9 @@
 
     loadPreview();
 
  });
 

	
 
  otherrepoChanged();
 
  //lazy load overview after 0.5s
 
  setTimeout(loadPreview, 500)
 
  setTimeout(loadPreview, 500);
 

	
 
</script>
 

	
rhodecode/templates/pullrequests/pullrequest_show.html
Show inline comments
 
@@ -161,7 +161,7 @@
 
               <div id="reviewers_container"></div>
 
            </div>
 
            <div style="padding:0px 10px">
 
             <span id="update_pull_request" class="ui-btn xsmall">${_('save changes')}</span>
 
             <span id="update_pull_request" class="ui-btn xsmall">${_('Save changes')}</span>
 
            </div>
 
            %endif
 
          </div>
rhodecode/tests/__init__.py
Show inline comments
 
@@ -47,7 +47,8 @@ __all__ = [
 
    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
 
    'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
 
    'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
 
    'GIT_REMOTE_REPO', 'SCM_TESTS', '_get_repo_create_params'
 
    'GIT_REMOTE_REPO', 'SCM_TESTS', '_get_repo_create_params',
 
    '_get_group_create_params'
 
]
 

	
 
# Invoke websetup with the current config file
 
@@ -183,3 +184,18 @@ def _get_repo_create_params(**custom):
 
        defs.update({'repo_name_full': defs['repo_name']})
 

	
 
    return defs
 

	
 

	
 
def _get_group_create_params(**custom):
 
    defs = dict(
 
        group_name=None,
 
        group_description='DESC',
 
        group_parent_id=None,
 
        perms_updates=[],
 
        perms_new=[],
 
        enable_locking=False,
 
        recursive=False
 
    )
 
    defs.update(custom)
 

	
 
    return defs
rhodecode/tests/api/api_base.py
Show inline comments
 
@@ -370,6 +370,17 @@ class BaseTestApi(object):
 
                   % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_lock_repo_lock_optional_locked(self):
 
        from rhodecode.lib.utils2 import  time_to_datetime
 
        _locked_since = json.dumps(time_to_datetime(Repository\
 
                                    .get_by_repo_name(self.REPO).locked[1]))
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  repoid=self.REPO)
 
        response = api_call(self, params)
 
        expected = ('Repo `%s` locked by `%s`. Locked=`True`. Locked since: `%s`'
 
                   % (self.REPO, TEST_USER_ADMIN_LOGIN, _locked_since))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(Repository, 'lock', crash)
 
    def test_api_lock_error(self):
 
        id_, params = _build_data(self.apikey, 'lock',
 
@@ -381,6 +392,32 @@ class BaseTestApi(object):
 
        expected = 'Error occurred locking repository `%s`' % self.REPO
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_regular_user(self):
 
        id_, params = _build_data(self.apikey_regular, 'get_locks')
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_with_userid_regular_user(self):
 
        id_, params = _build_data(self.apikey_regular, 'get_locks',
 
                                  userid=TEST_USER_ADMIN_LOGIN)
 
        response = api_call(self, params)
 
        expected = 'userid is not the same as your user'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks(self):
 
        id_, params = _build_data(self.apikey, 'get_locks')
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_with_userid(self):
 
        id_, params = _build_data(self.apikey, 'get_locks',
 
                                  userid=TEST_USER_REGULAR_LOGIN)
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_create_existing_user(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN,
rhodecode/tests/functional/test_compare.py
Show inline comments
 
@@ -106,6 +106,7 @@ class TestCompareController(TestControll
 
                                    other_repo=repo2.repo_name,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev1,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, rev2, repo2.repo_name, rev1))
 
@@ -118,9 +119,9 @@ class TestCompareController(TestControll
 
        response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (repo2.repo_name, cs1.raw_id, cs1.short_id))
 
        response.mustcontain("""<a href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=1#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        #swap
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 

	
 
    def test_compare_forks_on_branch_extra_commits_origin_has_incomming_hg(self):
 
        self.log_user()
 
@@ -160,6 +161,7 @@ class TestCompareController(TestControll
 
                                    other_repo=repo2.repo_name,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev1,
 
                                    merge='x',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, rev2, repo2.repo_name, rev1))
 
        response.mustcontain("""Showing 2 commits""")
 
@@ -171,9 +173,9 @@ class TestCompareController(TestControll
 
        response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (repo2.repo_name, cs1.raw_id, cs1.short_id))
 
        response.mustcontain("""<a href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=x#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        #swap
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 

	
 
    def test_compare_cherry_pick_changesets_from_bottom(self):
 

	
 
@@ -215,20 +217,16 @@ class TestCompareController(TestControll
 
        cs5 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\nline6\n',
 
                             message='commit6', vcs_type='hg', parent=cs4)
 

	
 
        rev1 = 'tip'
 
        rev2 = 'tip'
 

	
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=repo2.repo_name,
 
                                    org_ref_type="tag",
 
                                    org_ref=rev1,
 
                                    org_ref_type="rev",
 
                                    org_ref=cs1.short_id, # parent of cs2, in repo2
 
                                    other_repo=repo1.repo_name,
 
                                    other_ref_type="tag",
 
                                    other_ref=rev2,
 
                                    rev_start=cs2.raw_id,
 
                                    rev_end=cs4.raw_id,
 
                                    other_ref_type="rev",
 
                                    other_ref=cs4.short_id,
 
                                    merge='True',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs2.short_id, repo1.repo_name, cs4.short_id))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs1.short_id, repo1.repo_name, cs4.short_id))
 
        response.mustcontain("""Showing 3 commits""")
 
        response.mustcontain("""1 file changed with 3 insertions and 0 deletions""")
 

	
 
@@ -280,21 +278,16 @@ class TestCompareController(TestControll
 
                             message='commit5', vcs_type='hg', parent=cs3)
 
        cs5 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\nline6\n',
 
                             message='commit6', vcs_type='hg', parent=cs4)
 
        rev1 = 'tip'
 
        rev2 = 'tip'
 

	
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=repo2.repo_name,
 
                                    org_ref_type="tag",
 
                                    org_ref=rev1,
 
                                    other_repo=repo1.repo_name,
 
                                    other_ref_type="tag",
 
                                    other_ref=rev2,
 
                                    rev_start=cs3.raw_id,
 
                                    rev_end=cs5.raw_id,
 
                                    repo_name=repo1.repo_name,
 
                                    org_ref_type="rev",
 
                                    org_ref=cs2.short_id, # parent of cs3, not in repo2
 
                                    other_ref_type="rev",
 
                                    other_ref=cs5.short_id,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs3.short_id, repo1.repo_name, cs5.short_id))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, cs2.short_id, repo1.repo_name, cs5.short_id))
 
        response.mustcontain("""Showing 3 commits""")
 
        response.mustcontain("""1 file changed with 3 insertions and 0 deletions""")
 

	
 
@@ -330,6 +323,7 @@ class TestCompareController(TestControll
 
                                    other_ref_type="rev",
 
                                    other_ref=rev2,
 
                                    other_repo=HG_FORK,
 
                                    merge='1',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (HG_REPO, rev1, HG_FORK, rev2))
 
        ## outgoing changesets between those revisions
 
@@ -339,9 +333,9 @@ class TestCompareController(TestControll
 
        response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_FORK, rev2))
 

	
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 

	
 
    def test_org_repo_new_commits_after_forking_simple_diff(self):
 
        self.log_user()
 
@@ -412,6 +406,7 @@ class TestCompareController(TestControll
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    other_repo=r1_name,
 
                                    merge='1',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (r2_name, rev1, r1_name, rev2))
 
        response.mustcontain('No files')
 
@@ -436,6 +431,7 @@ class TestCompareController(TestControll
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    other_repo=r1_name,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (r2_name, rev1, r1_name, rev2))
rhodecode/tests/models/test_repos_groups.py
Show inline comments
 
@@ -21,6 +21,33 @@ def _make_group(path, desc='desc', paren
 
    return gr
 

	
 

	
 
def _update_group(id_, group_name, desc='desc', parent_id=None):
 
    form_data = _get_group_create_params(group_name=group_name,
 
                                         group_desc=desc,
 
                                         group_parent_id=parent_id)
 
    gr = ReposGroupModel().update(id_, form_data)
 
    return gr
 

	
 

	
 
def _make_repo(name, **kwargs):
 
    form_data = _get_repo_create_params(repo_name=name, **kwargs)
 
    cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
    r = RepoModel().create(form_data, cur_user)
 
    return r
 

	
 

	
 
def _update_repo(name, **kwargs):
 
    form_data = _get_repo_create_params(**kwargs)
 
    if not 'repo_name' in kwargs:
 
        form_data['repo_name'] = name
 
    if not 'perms_new' in kwargs:
 
        form_data['perms_new'] = []
 
    if not 'perms_updates' in kwargs:
 
        form_data['perms_updates'] = []
 
    r = RepoModel().update(name, **form_data)
 
    return r
 

	
 

	
 
class TestReposGroups(unittest.TestCase):
 

	
 
    def setUp(self):
 
@@ -32,7 +59,7 @@ class TestReposGroups(unittest.TestCase)
 
        Session().commit()
 

	
 
    def tearDown(self):
 
        print 'out'
 
        Session.remove()
 

	
 
    def __check_path(self, *path):
 
        """
 
@@ -48,21 +75,9 @@ class TestReposGroups(unittest.TestCase)
 
    def __delete_group(self, id_):
 
        ReposGroupModel().delete(id_)
 

	
 
    def __update_group(self, id_, path, desc='desc', parent_id=None):
 
        form_data = dict(
 
            group_name=path,
 
            group_description=desc,
 
            group_parent_id=parent_id,
 
            perms_updates=[],
 
            perms_new=[],
 
            enable_locking=False,
 
            recursive=False
 
        )
 
        gr = ReposGroupModel().update(id_, form_data)
 
        return gr
 

	
 
    def test_create_group(self):
 
        g = _make_group('newGroup')
 
        Session().commit()
 
        self.assertEqual(g.full_path, 'newGroup')
 

	
 
        self.assertTrue(self.__check_path('newGroup'))
 
@@ -73,23 +88,27 @@ class TestReposGroups(unittest.TestCase)
 

	
 
    def test_same_subgroup(self):
 
        sg1 = _make_group('sub1', parent_id=self.g1.group_id)
 
        Session().commit()
 
        self.assertEqual(sg1.parent_group, self.g1)
 
        self.assertEqual(sg1.full_path, 'test1/sub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1'))
 

	
 
        ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
 
        Session().commit()
 
        self.assertEqual(ssg1.parent_group, sg1)
 
        self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
 

	
 
    def test_remove_group(self):
 
        sg1 = _make_group('deleteme')
 
        Session().commit()
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(RepoGroup.get(sg1.group_id), None)
 
        self.assertFalse(self.__check_path('deteteme'))
 

	
 
        sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
 
        Session().commit()
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(RepoGroup.get(sg1.group_id), None)
 
@@ -97,24 +116,26 @@ class TestReposGroups(unittest.TestCase)
 

	
 
    def test_rename_single_group(self):
 
        sg1 = _make_group('initial')
 
        Session().commit()
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after')
 
        new_sg1 = _update_group(sg1.group_id, 'after')
 
        self.assertTrue(self.__check_path('after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
 

	
 
    def test_update_group_parent(self):
 

	
 
        sg1 = _make_group('initial', parent_id=self.g1.group_id)
 
        Session().commit()
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
 
        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
 
        self.assertTrue(self.__check_path('test1', 'after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
 
        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
 
        self.assertTrue(self.__check_path('test3', 'after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'hello')
 
        new_sg1 = _update_group(sg1.group_id, 'hello')
 
        self.assertTrue(self.__check_path('hello'))
 

	
 
        self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
 
@@ -123,23 +144,17 @@ class TestReposGroups(unittest.TestCase)
 

	
 
        g1 = _make_group('g1')
 
        g2 = _make_group('g2')
 

	
 
        Session().commit()
 
        # create new repo
 
        form_data = _get_repo_create_params(repo_name='john')
 
        cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
        r = RepoModel().create(form_data, cur_user)
 

	
 
        r = _make_repo('john')
 
        Session().commit()
 
        self.assertEqual(r.repo_name, 'john')
 

	
 
        # put repo into group
 
        form_data = form_data
 
        form_data['repo_group'] = g1.group_id
 
        form_data['perms_new'] = []
 
        form_data['perms_updates'] = []
 
        RepoModel().update(r.repo_name, **form_data)
 
        r = _update_repo('john', repo_group=g1.group_id)
 
        Session().commit()
 
        self.assertEqual(r.repo_name, 'g1/john')
 

	
 
        self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        _update_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        self.assertTrue(self.__check_path('g2', 'g1'))
 

	
 
        # test repo
 
@@ -155,7 +170,7 @@ class TestReposGroups(unittest.TestCase)
 
        self.assertEqual(g2.full_path, 't11/t22')
 
        self.assertTrue(self.__check_path('t11', 't22'))
 

	
 
        g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
 
        g2 = _update_group(g2.group_id, 'g22', parent_id=None)
 
        Session().commit()
 

	
 
        self.assertEqual(g2.group_name, 'g22')
 
@@ -163,3 +178,65 @@ class TestReposGroups(unittest.TestCase)
 
        self.assertEqual(g2.full_path, 'g22')
 
        self.assertFalse(self.__check_path('t11', 't22'))
 
        self.assertTrue(self.__check_path('g22'))
 

	
 
    def test_rename_top_level_group_in_nested_setup(self):
 
        g1 = _make_group('L1')
 
        Session().commit()
 
        g2 = _make_group('L2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('L3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        r = _make_repo('L1/L2/L3/L3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 

	
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'L1_NEW')
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'L1_NEW')
 
        self.assertEqual(g2.full_path, 'L1_NEW/L2')
 
        self.assertEqual(g3.full_path, 'L1_NEW/L2/L3')
 
        self.assertEqual(r.repo_name,  'L1_NEW/L2/L3/L3_REPO')
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup(self):
 
        g1 = _make_group('R1')
 
        Session().commit()
 
        g2 = _make_group('R2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('R3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        g4 = _make_group('R1_NEW')
 
        Session().commit()
 

	
 
        r = _make_repo('R1/R2/R3/R3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'R1', parent_id=g4.group_id)
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'R1_NEW/R1')
 
        self.assertEqual(g2.full_path, 'R1_NEW/R1/R2')
 
        self.assertEqual(g3.full_path, 'R1_NEW/R1/R2/R3')
 
        self.assertEqual(r.repo_name,  'R1_NEW/R1/R2/R3/R3_REPO')
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup_with_rename(self):
 
        g1 = _make_group('X1')
 
        Session().commit()
 
        g2 = _make_group('X2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('X3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        g4 = _make_group('X1_NEW')
 
        Session().commit()
 

	
 
        r = _make_repo('X1/X2/X3/X3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 

	
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'X1_PRIM', parent_id=g4.group_id)
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'X1_NEW/X1_PRIM')
 
        self.assertEqual(g2.full_path, 'X1_NEW/X1_PRIM/X2')
 
        self.assertEqual(g3.full_path, 'X1_NEW/X1_PRIM/X2/X3')
 
        self.assertEqual(r.repo_name,  'X1_NEW/X1_PRIM/X2/X3/X3_REPO')
rhodecode/tests/scripts/test_vcs_operations.py
Show inline comments
 
@@ -4,9 +4,10 @@
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Test suite for making push/pull operations.
 
    Run using::
 
    Run using after doing paster serve test.ini::
 
     RC_WHOOSH_TEST_DISABLE=1 RC_NO_TMP_PATH=1 nosetests rhodecode/tests/scripts/test_vcs_operations.py
 

	
 
     RC_WHOOSH_TEST_DISABLE=1 RC_NO_TMP_PATH=1 nosetests rhodecode/tests/scripts/test_vcs_operations.py
 
    You must have git > 1.8.1 for tests to work fine
 

	
 
    :created_on: Dec 30, 2010
 
    :author: marcink
 
@@ -107,13 +108,14 @@ def _add_files_and_push(vcs, DEST, **kwa
 
    for i in xrange(3):
 
        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
 
        Command(cwd).execute(cmd)
 
        author_str = 'Marcin Kuźminski <me@email.com>'
 
        if vcs == 'hg':
 
            cmd = """hg commit -m 'commited new %s' -u '%s' %s """ % (
 
                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
 
                i, author_str, added_file
 
            )
 
        elif vcs == 'git':
 
            cmd = """git commit -m 'commited new %s' --author '%s' %s """ % (
 
                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
 
                i, author_str, added_file
 
            )
 
        Command(cwd).execute(cmd)
 
    # PUSH it back
 
@@ -129,7 +131,7 @@ def _add_files_and_push(vcs, DEST, **kwa
 
    if vcs == 'hg':
 
        stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
 
    elif vcs == 'git':
 
        stdout, stderr = Command(cwd).execute('git push', clone_url + " master")
 
        stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
 

	
 
    return stdout, stderr
 

	
 
@@ -324,8 +326,7 @@ class TestVCSOperations(unittest.TestCas
 
        #pull fails since repo is locked
 
        clone_url = _construct_url(GIT_REPO)
 
        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
 
        msg = ("""423 Repository `%s` locked by user `%s`"""
 
                % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
 
        msg = ("""The requested URL returned error: 423""")
 
        assert msg in stderr
 

	
 
    def test_push_on_locked_repo_by_other_user_hg(self):
 
@@ -455,7 +456,8 @@ class TestVCSOperations(unittest.TestCas
 
            Session().commit()
 
            clone_url = _construct_url(GIT_REPO)
 
            stdout, stderr = Command('/tmp').execute('git clone', clone_url)
 
            assert 'error: The requested URL returned error: 403 Forbidden' in stderr
 
            msg = ("""The requested URL returned error: 403""")
 
            assert msg in stderr
 
        finally:
 
            #release IP restrictions
 
            for ip in UserIpMap.getAll():
rhodecode/tests/vcs/conf.py
Show inline comments
 
@@ -7,6 +7,7 @@ import time
 
import hashlib
 
import tempfile
 
import datetime
 
import shutil
 
from rhodecode.tests import *
 
from utils import get_normalized_path
 
from os.path import join as jn
 
@@ -58,5 +59,6 @@ THIS = os.path.abspath(os.path.dirname(_
 

	
 
PACKAGE_DIR = os.path.abspath(os.path.join(
 
    os.path.dirname(__file__), '..'))
 

	
 
TEST_USER_CONFIG_FILE = jn(THIS, 'aconfig')
 
_dest = jn(TESTS_TMP_PATH,'aconfig')
 
shutil.copy(jn(THIS, 'aconfig'), _dest)
 
TEST_USER_CONFIG_FILE = _dest
setup.py
Show inline comments
 
@@ -62,10 +62,10 @@ if sys.version_info < (2, 7):
 
    requirements.append("argparse")
 

	
 
if is_windows:
 
    requirements.append("mercurial==2.5.1")
 
    requirements.append("mercurial==2.5.2")
 
else:
 
    requirements.append("py-bcrypt")
 
    requirements.append("mercurial==2.5.1")
 
    requirements.append("mercurial==2.5.2")
 

	
 

	
 
dependency_links = [
test.ini
Show inline comments
 
@@ -31,22 +31,24 @@ pdebug = false
 
[server:main]
 
## PASTE
 
##nr of threads to spawn
 
threadpool_workers = 5
 
#threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 10
 
#threadpool_max_requests = 10
 

	
 
##option to use threads of process
 
use_threadpool = true
 
#use_threadpool = true
 

	
 
use = egg:Paste#http
 
#use = egg:Paste#http
 

	
 
#WAITRESS
 
threads = 5
 
#100GB
 
max_request_body_size = 107374182400
 
use = egg:waitress#main
 

	
 
host = 127.0.0.1
 
port = 8001
 
port = 5000
 

	
 
[filter:proxy-prefix]
 
# prefix middleware for rc
 
@@ -63,6 +65,8 @@ static_files = true
 
lang = en
 
cache_dir = /tmp/rc/data
 
index_dir = /tmp/rc/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = develop-test
 
cut_off_limit = 256000
 
vcs_full_cache = False
 
@@ -250,6 +254,87 @@ beaker.session.auto = False
 
#beaker.session.cookie_expires = 3600
 

	
 

	
 
############################
 
## ERROR HANDLING SYSTEMS ##
 
############################
 

	
 
####################
 
### [errormator] ###
 
####################
 

	
 
# Errormator is tailored to work with RhodeCode, see 
 
# http://errormator.com for details how to obtain an account
 
# you must install python package `errormator_client` to make it work
 

	
 
# errormator enabled
 
errormator = true
 

	
 
errormator.server_url = https://api.errormator.com
 
errormator.api_key = YOUR_API_KEY
 

	
 
# TWEAK AMOUNT OF INFO SENT HERE
 

	
 
# enables 404 error logging (default False)
 
errormator.report_404 = false
 

	
 
# time in seconds after request is considered being slow (default 1)
 
errormator.slow_request_time = 1
 

	
 
# record slow requests in application
 
# (needs to be enabled for slow datastore recording and time tracking)
 
errormator.slow_requests = true
 

	
 
# enable hooking to application loggers
 
# errormator.logging = true
 

	
 
# minimum log level for log capture
 
# errormator.logging.level = WARNING
 

	
 
# send logs only from erroneous/slow requests
 
# (saves API quota for intensive logging)
 
errormator.logging_on_error = false
 

	
 
# list of additonal keywords that should be grabbed from environ object 
 
# can be string with comma separated list of words in lowercase
 
# (by default client will always send following info:
 
# 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that 
 
# start with HTTP* this list be extended with additional keywords here
 
errormator.environ_keys_whitelist = 
 

	
 

	
 
# list of keywords that should be blanked from request object 
 
# can be string with comma separated list of words in lowercase
 
# (by default client will always blank keys that contain following words 
 
# 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
 
# this list be extended with additional keywords set here
 
errormator.request_keys_blacklist =
 

	
 

	
 
# list of namespaces that should be ignores when gathering log entries
 
# can be string with comma separated list of namespaces
 
# (by default the client ignores own entries: errormator_client.client)
 
errormator.log_namespace_blacklist =  
 

	
 

	
 
################
 
### [sentry] ###
 
################
 

	
 
# sentry is a alternative open source error aggregator
 
# you must install python packages `sentry` and `raven` to enable 
 

	
 
sentry.dsn = YOUR_DNS
 
sentry.servers =
 
sentry.name =
 
sentry.key =
 
sentry.public_key =
 
sentry.secret_key =
 
sentry.project =
 
sentry.site =
 
sentry.include_paths =
 
sentry.exclude_paths =
 

	
 

	
 
################################################################################
 
## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*  ##
 
## Debug mode will enable the interactive debugging tool, allowing ANYONE to  ##
 
@@ -270,7 +355,6 @@ logview.pylons.util = #eee
 
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.sqlite
 
#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_test
 
#sqlalchemy.db1.url = mysql://root:qwe@localhost/rhodecode_test
 

	
 
sqlalchemy.db1.echo = false
 
sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.db1.convert_unicode = true
0 comments (0 inline, 0 general)