def test_push_unlocks_repository_hg(self, rc_web_server, tmpdir): # enable locking r = Repository.get_by_repo_name(HG_REPO) r.enable_locking = True Session().add(r) Session().commit() clone_url = rc_web_server.repo_clone_url(HG_REPO) stdout, stderr = Command('/tmp').execute( 'hg clone', clone_url, tmpdir.strpath) _check_proper_clone(stdout, stderr, 'hg') # check for lock repo after clone r = Repository.get_by_repo_name(HG_REPO) uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id assert r.locked[0] == uid # push is ok and repo is now unlocked stdout, stderr = _add_files_and_push( 'hg', tmpdir.strpath, clone_url=clone_url) assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout # we need to cleanup the Session Here ! Session.remove() r = Repository.get_by_repo_name(HG_REPO) assert r.locked == [None, None, None]
def test_push_on_locked_repo_by_other_user_git( self, rc_web_server, tmpdir): clone_url = rc_web_server.repo_clone_url(GIT_REPO) stdout, stderr = Command('/tmp').execute( 'git clone', clone_url, tmpdir.strpath) # lock repo r = Repository.get_by_repo_name(GIT_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # push fails repo is locked by other user! push_url = rc_web_server.repo_clone_url( GIT_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) stdout, stderr = _add_files_and_push( 'git', tmpdir.strpath, clone_url=push_url) err = 'Repository `%s` locked by user `%s`' % ( GIT_REPO, TEST_USER_ADMIN_LOGIN) # err = 'RPC failed; result=22, HTTP code = 423' assert err in stderr
def test_push_unlocks_repository_git(self, rc_web_server, tmpdir): # Note: Did a first debugging session. Seems that # Repository.get_locking_state is called twice. The second call # has the action "pull" and does not reset the lock. # enable locking r = Repository.get_by_repo_name(GIT_REPO) r.enable_locking = True Session().add(r) Session().commit() clone_url = rc_web_server.repo_clone_url(GIT_REPO) stdout, stderr = Command('/tmp').execute( 'git clone', clone_url, tmpdir.strpath) _check_proper_clone(stdout, stderr, 'git') # check for lock repo after clone r = Repository.get_by_repo_name(GIT_REPO) assert r.locked[0] == User.get_by_username( TEST_USER_ADMIN_LOGIN).user_id # push is ok and repo is now unlocked stdout, stderr = _add_files_and_push( 'git', tmpdir.strpath, clone_url=clone_url) _check_proper_git_push(stdout, stderr) # assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout # we need to cleanup the Session Here ! Session.remove() r = Repository.get_by_repo_name(GIT_REPO) assert r.locked == [None, None, None]
def test_api_lock_repo_lock_optional_locked(self, backend): # TODO: Provide a fixture locked_repository or similar repo = Repository.get_by_repo_name(backend.repo_name) user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) Repository.lock(repo, user.user_id, lock_reason=Repository.LOCK_API) id_, params = build_data(self.apikey, 'lock', repoid=backend.repo_name) response = api_call(self.app, params) time_ = response.json['result']['locked_since'] expected = { 'repo': backend.repo_name, 'locked': True, 'locked_since': time_, 'locked_by': TEST_USER_ADMIN_LOGIN, 'lock_state_changed': False, 'lock_reason': Repository.LOCK_API, 'msg': ('Repo `%s` locked by `%s` on `%s`.' % (backend.repo_name, TEST_USER_ADMIN_LOGIN, json.dumps(time_to_datetime(time_)))) } assert_ok(id_, expected, given=response.body)
def test_remove_repo_detach_forks(self): repo = fixture.create_repo(name='test-repo-1') Session().commit() fork = fixture.create_fork(repo.repo_name, 'test-repo-fork-1') Session().commit() #fork of fork fixture.create_fork(fork.repo_name, 'test-repo-fork-fork-1') Session().commit() RepoModel().delete(repo=repo, forks='detach') Session().commit() try: self.assertEqual( None, Repository.get_by_repo_name(repo_name='test-repo-1')) self.assertNotEqual( None, Repository.get_by_repo_name(repo_name='test-repo-fork-1')) self.assertNotEqual( None, Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1')) finally: RepoModel().delete(repo='test-repo-fork-fork-1') RepoModel().delete(repo='test-repo-fork-1') Session().commit()
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users :param user: user that made this action, can be a unique username string or object containing user_id attribute :param action: action to log, should be on of predefined unique actions for easy translations :param repo: string name of repository or object containing repo_id, that action was made on :param ipaddr: optional ip address from what the action was made :param sa: optional sqlalchemy session """ if not sa: sa = meta.Session() # if we don't get explicit IP address try to get one from registered user # in tmpl context var if not ipaddr: ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '') try: if getattr(user, 'user_id', None): user_obj = User.get(user.user_id) elif isinstance(user, basestring): user_obj = User.get_by_username(user) else: raise Exception('You have to provide a user object or a username') if getattr(repo, 'repo_id', None): repo_obj = Repository.get(repo.repo_id) repo_name = repo_obj.repo_name elif isinstance(repo, basestring): repo_name = repo.lstrip('/') repo_obj = Repository.get_by_repo_name(repo_name) else: repo_obj = None repo_name = '' user_log = UserLog() user_log.user_id = user_obj.user_id user_log.username = user_obj.username action = safe_unicode(action) user_log.action = action[:1200000] user_log.repository = repo_obj user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr sa.add(user_log) log.info('Logging action:`%s` on repo:`%s` by user:%s ip:%s', action, safe_unicode(repo), user_obj, ipaddr) if commit: sa.commit() except Exception: log.error(traceback.format_exc()) raise
def log_pull_action(ui, repo, **kwargs): """ Logs user last pull action :param ui: :param repo: """ ex = _extract_extras() user = User.get_by_username(ex.username) action = 'pull' action_logger(user, action, ex.repository, ex.ip, commit=True) # extension hook call from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PULL_HOOK', None) if isfunction(callback): kw = {} kw.update(ex) callback(**kw) if ex.make_lock is not None and ex.make_lock: Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id) #msg = 'Made lock on repo `%s`' % repository #sys.stdout.write(msg) if ex.locked_by[0]: locked_by = User.get(ex.locked_by[0]).username _http_ret = HTTPLockedRC(ex.repository, locked_by) if str(_http_ret.code).startswith('2'): #2xx Codes don't raise exceptions sys.stdout.write(_http_ret.title) return 0
def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir): clone_url = rc_web_server.repo_clone_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url, tmpdir.strpath) # lock repo r = Repository.get_by_repo_name(HG_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # push fails repo is locked by other user ! push_url = rc_web_server.repo_clone_url(HG_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) stdout, stderr = _add_files_and_push('hg', tmpdir.strpath, clone_url=push_url) msg = ( """abort: HTTP Error 400: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def validate_python(self, value, state): repo_name = value.get("repo_name") repo_name_full = value.get("repo_name_full") group_path = value.get("group_path") group_name = value.get("group_name") if repo_name in [ADMIN_PREFIX, ""]: msg = M(self, "invalid_repo_name", state, repo=repo_name) raise formencode.Invalid(msg, value, state, error_dict=dict(repo_name=msg)) rename = old_data.get("repo_name") != repo_name_full create = not edit if rename or create: if group_path != "": if Repository.get_by_repo_name(repo_name_full): msg = M(self, "repository_in_group_exists", state, repo=repo_name, group=group_name) raise formencode.Invalid(msg, value, state, error_dict=dict(repo_name=msg)) elif RepoGroup.get_by_group_name(repo_name_full): msg = M(self, "same_group_exists", state, repo=repo_name) raise formencode.Invalid(msg, value, state, error_dict=dict(repo_name=msg)) elif Repository.get_by_repo_name(repo_name_full): msg = M(self, "repository_exists", state, repo=repo_name) raise formencode.Invalid(msg, value, state, error_dict=dict(repo_name=msg)) return value
def toggle_locking(self, repo_name): """ Toggle locking of repository by simple GET call to url :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if repo.enable_locking: if repo.locked[0]: Repository.unlock(repo) action = _('Unlocked') else: Repository.lock(repo, c.rhodecode_user.user_id, lock_reason=Repository.LOCK_WEB) action = _('Locked') h.flash(_('Repository has been %s') % action, category='success') except Exception: log.exception("Exception during unlocking") h.flash(_('An error occurred during unlocking'), category='error') return redirect(url('summary_home', repo_name=repo_name))
def pull_changes(self, repo, username): dbrepo = self.__get_repo(repo) clone_uri = dbrepo.clone_uri if not clone_uri: raise Exception("This repository doesn't have a clone uri") repo = dbrepo.scm_instance try: extras = { 'ip': '', 'username': username, 'action': 'push_remote', 'repository': dbrepo.repo_name, 'scm': repo.alias, } 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) except: log.error(traceback.format_exc()) raise
def post_pull(extras): """Hook executed after client pulls the code.""" user = User.get_by_username(extras.username) action = 'pull' action_logger(user, action, extras.repository, extras.ip, commit=True) # extension hook call post_pull_extension(**extras) output = '' # make lock is a tri state False, True, None. We only make lock on True if extras.make_lock is True: Repository.lock(Repository.get_by_repo_name(extras.repository), user.user_id, lock_reason=Repository.LOCK_PULL) msg = 'Made lock on repo `%s`' % (extras.repository, ) output += msg if extras.locked_by[0]: locked_by = User.get(extras.locked_by[0]).username reason = extras.locked_by[2] _http_ret = HTTPLockedRC( _locked_by_explanation(extras.repository, locked_by, reason)) if str(_http_ret.code).startswith('2'): # 2xx Codes don't raise exceptions output += _http_ret.title return HookResponse(0, output)
def _fork_repo(fork_name, vcs_type, parent=None): if vcs_type =='hg': _REPO = HG_REPO elif vcs_type == 'git': _REPO = GIT_REPO if parent: _REPO = parent form_data = dict( repo_name=fork_name, repo_name_full=fork_name, repo_group=None, repo_type=vcs_type, description='', private=False, copy_permissions=False, landing_rev='tip', update_after_clone=False, fork_parent_id=Repository.get_by_repo_name(_REPO), ) repo = RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN) Session().commit() return Repository.get_by_repo_name(fork_name)
def lock(self, apiuser, repoid, userid, locked): """ Set locking state on particular repository by given user :param apiuser: :param repoid: :param userid: :param locked: """ repo = get_repo_or_error(repoid) user = get_user_or_error(userid) locked = bool(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 )
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users :param user: user that made this action, can be a unique username string or object containing user_id attribute :param action: action to log, should be on of predefined unique actions for easy translations :param repo: string name of repository or object containing repo_id, that action was made on :param ipaddr: optional ip address from what the action was made :param sa: optional sqlalchemy session """ if not sa: sa = meta.Session() # if we don't get explicit IP address try to get one from registered user # in tmpl context var if not ipaddr: ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '') try: if hasattr(user, 'user_id'): user_obj = User.get(user.user_id) elif isinstance(user, basestring): user_obj = User.get_by_username(user) else: raise Exception('You have to provide a user object or a username') if hasattr(repo, 'repo_id'): repo_obj = Repository.get(repo.repo_id) repo_name = repo_obj.repo_name elif isinstance(repo, basestring): repo_name = repo.lstrip('/') repo_obj = Repository.get_by_repo_name(repo_name) else: repo_obj = None repo_name = '' user_log = UserLog() user_log.user_id = user_obj.user_id user_log.username = user_obj.username user_log.action = safe_unicode(action) user_log.repository = repo_obj user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr sa.add(user_log) log.info('Logging action:%s on %s by user:%s ip:%s' % (action, safe_unicode(repo), user_obj, ipaddr)) if commit: sa.commit() except Exception: log.error(traceback.format_exc()) raise
def log_push_action(ui, repo, **kwargs): """ Maps user last push action to new changeset id, from mercurial :param ui: :param repo: repo object containing the `ui` object """ ex = _extract_extras() action = ex.action + ':%s' if ex.scm == 'hg': node = kwargs['node'] def get_revs(repo, rev_opt): if rev_opt: revs = revrange(repo, rev_opt) if len(revs) == 0: return (nullrev, nullrev) return (max(revs), min(revs)) else: return (len(repo) - 1, 0) stop, start = get_revs(repo, [node + ':']) h = binascii.hexlify revs = [h(repo[r].node()) for r in xrange(start, stop + 1)] elif ex.scm == 'git': revs = kwargs.get('_git_revs', []) if '_git_revs' in kwargs: kwargs.pop('_git_revs') action = action % ','.join(revs) action_logger(ex.username, action, ex.repository, ex.ip, commit=True) # extension hook call from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PUSH_HOOK', None) if isfunction(callback): kw = {'pushed_revs': revs} kw.update(ex) callback(**kw) if ex.make_lock is not None and not ex.make_lock: Repository.unlock(Repository.get_by_repo_name(ex.repository)) msg = 'Released lock on repo `%s`\n' % ex.repository sys.stdout.write(msg) if ex.locked_by[0]: locked_by = User.get(ex.locked_by[0]).username _http_ret = HTTPLockedRC(ex.repository, locked_by) if str(_http_ret.code).startswith('2'): #2xx Codes don't raise exceptions sys.stdout.write(_http_ret.title) return 0
def test_clone_after_repo_was_locked_git(self): #lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) msg = ("""The requested URL returned error: 423""") assert msg in stderr
def test_clone_after_repo_was_locked_hg(self): #lock repo r = Repository.get_by_repo_name(HG_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users :param user: user that made this action, can be a unique username string or object containing user_id attribute :param action: action to log, should be on of predefined unique actions for easy translations :param repo: string name of repository or object containing repo_id, that action was made on :param ipaddr: optional ip address from what the action was made :param sa: optional sqlalchemy session """ if not sa: sa = meta.Session try: if hasattr(user, 'user_id'): user_obj = user elif isinstance(user, basestring): user_obj = User.get_by_username(user) else: raise Exception('You have to provide user object or username') if hasattr(repo, 'repo_id'): repo_obj = Repository.get(repo.repo_id) repo_name = repo_obj.repo_name elif isinstance(repo, basestring): repo_name = repo.lstrip('/') repo_obj = Repository.get_by_repo_name(repo_name) else: raise Exception('You have to provide repository to action logger') user_log = UserLog() user_log.user_id = user_obj.user_id user_log.action = safe_unicode(action) user_log.repository_id = repo_obj.repo_id user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr sa.add(user_log) log.info( 'Adding user %s, action %s on %s' % (user_obj, action, safe_unicode(repo)) ) if commit: sa.commit() except: log.error(traceback.format_exc()) raise
def test_api_get_user_locks_with_one_locked_repo_for_specific_user( self, backend): repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) Repository.lock(repo, User.get_by_username( self.TEST_USER_LOGIN).user_id) id_, params = build_data( self.apikey, 'get_user_locks', userid=self.TEST_USER_LOGIN) response = api_call(self.app, params) expected = [repo.get_api_data(include_secrets=True)] assert_ok(id_, expected, given=response.body)
def test_clone_after_repo_was_locked_hg(self): #lock repo r = Repository.get_by_repo_name(HG_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) msg = ( """abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def __load_data(self, repo_name=None): """ Load defaults settings for edit, and update :param repo_name: """ self.__load_defaults() c.repo_info = db_repo = Repository.get_by_repo_name(repo_name) repo = db_repo.scm_instance if c.repo_info is None: h.not_mapped_error(repo_name) return redirect(url('repos')) ##override defaults for exact repo info here git/hg etc choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info) c.landing_revs_choices = choices c.default_user_id = User.get_by_username('default').user_id c.in_public_journal = UserFollowing.query()\ .filter(UserFollowing.user_id == c.default_user_id)\ .filter(UserFollowing.follows_repository == c.repo_info).scalar() if c.repo_info.stats: # this is on what revision we ended up so we add +1 for count last_rev = c.repo_info.stats.stat_on_revision + 1 else: last_rev = 0 c.stats_revision = last_rev c.repo_last_rev = repo.count() if repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: c.stats_percentage = 0 else: c.stats_percentage = '%.2f' % ((float( (last_rev)) / c.repo_last_rev) * 100) c.repo_fields = RepositoryField.query()\ .filter(RepositoryField.repository == db_repo).all() defaults = RepoModel()._get_defaults(repo_name) c.repos_list = [('', _('--REMOVE FORK--'))] c.repos_list += [ (x.repo_id, x.repo_name) for x in Repository.query().order_by(Repository.repo_name).all() if x.repo_id != c.repo_info.repo_id ] defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else '' return defaults
def __load_data(self, repo_name=None): """ Load defaults settings for edit, and update :param repo_name: """ self.__load_defaults() c.repo_info = db_repo = Repository.get_by_repo_name(repo_name) repo = db_repo.scm_instance if c.repo_info is None: h.not_mapped_error(repo_name) return redirect(url('repos')) ##override defaults for exact repo info here git/hg etc choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info) c.landing_revs_choices = choices c.default_user_id = User.get_default_user().user_id c.in_public_journal = UserFollowing.query()\ .filter(UserFollowing.user_id == c.default_user_id)\ .filter(UserFollowing.follows_repository == c.repo_info).scalar() if c.repo_info.stats: # this is on what revision we ended up so we add +1 for count last_rev = c.repo_info.stats.stat_on_revision + 1 else: last_rev = 0 c.stats_revision = last_rev c.repo_last_rev = repo.count() if repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: c.stats_percentage = 0 else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) c.repo_fields = RepositoryField.query()\ .filter(RepositoryField.repository == db_repo).all() defaults = RepoModel()._get_defaults(repo_name) _repos = Repository.query().order_by(Repository.repo_name).all() read_access_repos = RepoList(_repos) c.repos_list = [('', _('--REMOVE FORK--'))] c.repos_list += [(x.repo_id, x.repo_name) for x in read_access_repos if x.repo_id != c.repo_info.repo_id] defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else '' return defaults
def __load_data(self, repo_name=None): """ Load defaults settings for edit, and update :param repo_name: """ self.__load_defaults() c.repo_info = db_repo = Repository.get_by_repo_name(repo_name) repo = db_repo.scm_instance if c.repo_info is None: h.flash(_('%s repository is not mapped to db perhaps' ' it was created or renamed from the filesystem' ' please run the application again' ' in order to rescan repositories') % repo_name, category='error') return redirect(url('repos')) choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info) c.landing_revs_choices = choices c.default_user_id = User.get_by_username('default').user_id c.in_public_journal = UserFollowing.query()\ .filter(UserFollowing.user_id == c.default_user_id)\ .filter(UserFollowing.follows_repository == c.repo_info).scalar() if c.repo_info.stats: # this is on what revision we ended up so we add +1 for count last_rev = c.repo_info.stats.stat_on_revision + 1 else: last_rev = 0 c.stats_revision = last_rev c.repo_last_rev = repo.count() if repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: c.stats_percentage = 0 else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) defaults = RepoModel()._get_defaults(repo_name) c.repos_list = [('', _('--REMOVE FORK--'))] c.repos_list += [(x.repo_id, x.repo_name) for x in Repository.query().order_by(Repository.repo_name).all() if x.repo_id != c.repo_info.repo_id] defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else '' return defaults
def test_clone_after_repo_was_locked_git(self): #lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (GIT_REPO, TEST_USER_ADMIN_LOGIN)) #TODO: fix this somehow later on GIT, GIT is stupid and even if we throw # back 423 to it, it makes ANOTHER request and we fail there with 405 :/ msg = "405 Method Not Allowed" assert msg in stderr
def test_clone_and_create_lock_git(self): # enable locking r = Repository.get_by_repo_name(GIT_REPO) r.enable_locking = True Session().add(r) Session().commit() # clone clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) #check if lock was made r = Repository.get_by_repo_name(GIT_REPO) assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
def test_clone_and_create_lock_git(self): # enable locking r = Repository.get_by_repo_name(GIT_REPO) r.enable_locking = True Session().add(r) Session().commit() # clone clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) #check if lock was made r = Repository.get_by_repo_name(GIT_REPO) assert r.locked[0] == User.get_by_username( TEST_USER_ADMIN_LOGIN).user_id
def test_fork_create_into_group(self): self.log_user() group = fixture.create_repo_group('vc') group_id = group.group_id fork_name = self.REPO_FORK fork_name_full = 'vc/%s' % fork_name description = 'fork of vcs test' repo_name = self.REPO source_repo = Repository.get_by_repo_name(repo_name) creation_args = { 'repo_name': fork_name, 'repo_group': group_id, 'fork_parent_id': source_repo.repo_id, 'repo_type': self.REPO_TYPE, 'description': description, 'private': 'False', 'landing_rev': 'rev:tip', 'csrf_token': self.csrf_token, } self.app.post( url(controller='forks', action='fork_create', repo_name=repo_name), creation_args) repo = Repository.get_by_repo_name(fork_name_full) assert repo.fork.repo_name == self.REPO # run the check page that triggers the flash message response = self.app.get( url('repo_check_home', repo_name=fork_name_full)) # test if we have a message that fork is ok assert_session_flash( response, 'Forked repository %s as <a href="/%s">%s</a>' % (repo_name, fork_name_full, fork_name_full)) # test if the fork was created in the database fork_repo = Session().query(Repository)\ .filter(Repository.repo_name == fork_name_full).one() assert fork_repo.repo_name == fork_name_full assert fork_repo.fork.repo_name == repo_name # test if the repository is visible in the list ? response = self.app.get(url('summary_home', repo_name=fork_name_full)) response.mustcontain(fork_name_full) response.mustcontain(self.REPO_TYPE) response.mustcontain('Fork of') response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name)) fixture.destroy_repo(fork_name_full) fixture.destroy_repo_group(group_id)
def create_repo(self, apiuser, repo_name, owner_name, description='', repo_type='hg', private=False, clone_uri=None): """ Create repository, if clone_url is given it makes a remote clone :param apiuser: :param repo_name: :param owner_name: :param description: :param repo_type: :param private: :param clone_uri: """ try: owner = User.get_by_username(owner_name) if owner is None: raise JSONRPCError('unknown user %s' % owner_name) if Repository.get_by_repo_name(repo_name): raise JSONRPCError("repo %s already exist" % repo_name) groups = repo_name.split(Repository.url_sep()) real_name = groups[-1] # create structure of groups group = map_groups(repo_name) repo = RepoModel().create( dict( repo_name=real_name, repo_name_full=repo_name, description=description, private=private, repo_type=repo_type, repo_group=group.group_id if group else None, clone_uri=clone_uri ), owner ) Session.commit() return dict( id=repo.repo_id, msg="Created new repository %s" % repo.repo_name ) except Exception: log.error(traceback.format_exc()) raise JSONRPCError('failed to create repository %s' % repo_name)
def to_python(self, value, state): repo_name = value.get('repo_name') slug = repo_name_slug(repo_name) if slug in [ADMIN_PREFIX, '']: e_dict = {'repo_name': _('This repository name is disallowed')} raise formencode.Invalid('', value, state, error_dict=e_dict) if value.get('repo_group'): gr = RepoGroup.get(value.get('repo_group')) group_path = gr.full_path # value needs to be aware of group name in order to check # db key This is an actual just the name to store in the # database repo_name_full = group_path + RepoGroup.url_sep() + repo_name else: group_path = '' repo_name_full = repo_name value['repo_name_full'] = repo_name_full rename = old_data.get('repo_name') != repo_name_full create = not edit if rename or create: if group_path != '': if Repository.get_by_repo_name(repo_name_full): e_dict = { 'repo_name': _('This repository already exists in ' 'a group "%s"') % gr.group_name } raise formencode.Invalid('', value, state, error_dict=e_dict) elif RepoGroup.get_by_group_name(repo_name_full): e_dict = { 'repo_name': _('There is a group with this name ' 'already "%s"') % repo_name_full } raise formencode.Invalid('', value, state, error_dict=e_dict) elif Repository.get_by_repo_name(repo_name_full): e_dict = {'repo_name': _('This repository ' 'already exists')} raise formencode.Invalid('', value, state, error_dict=e_dict) return value
def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir): # lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # pull fails since repo is locked clone_url = rc_web_server.repo_clone_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url, tmpdir.strpath) lock_msg = ( 'remote: ERROR: Repository `vcs_test_git` locked by user ' + '`test_admin`. Reason:`lock_auto`') assert lock_msg in stderr assert 'remote: Pre pull hook failed: aborting' in stderr assert 'fatal: remote did not send all necessary objects' in stderr
def test_clone_and_create_lock_hg(self, rc_web_server, tmpdir): # enable locking r = Repository.get_by_repo_name(HG_REPO) r.enable_locking = True Session().add(r) Session().commit() # clone clone_url = rc_web_server.repo_clone_url(HG_REPO) stdout, stderr = Command('/tmp').execute( 'hg clone', clone_url, tmpdir.strpath) # check if lock was made r = Repository.get_by_repo_name(HG_REPO) assert r.locked[0] == User.get_by_username( TEST_USER_ADMIN_LOGIN).user_id
def index(self, repo_name): c.compare_home = True c.commit_ranges = [] c.files = [] c.limited_diff = False source_repo = c.rhodecode_db_repo.repo_name target_repo = request.GET.get('target_repo', source_repo) c.source_repo = Repository.get_by_repo_name(source_repo) c.target_repo = Repository.get_by_repo_name(target_repo) c.source_ref = c.target_ref = _('Select commit') c.source_ref_type = "" c.target_ref_type = "" c.commit_statuses = ChangesetStatus.STATUSES c.preview_mode = False return render('compare/compare_diff.html')
def revoke_users_group_permission(self, apiuser, repo_name, group_name): """ Revoke permission for users group on given repository :param repo_name: :param group_name: """ try: repo = Repository.get_by_repo_name(repo_name) if repo is None: raise JSONRPCError('unknown repository %s' % repo) user_group = UsersGroup.get_by_group_name(group_name) if user_group is None: raise JSONRPCError('unknown users group %s' % user_group) RepoModel().revoke_users_group_permission(repo=repo_name, group_name=group_name) Session.commit() return dict( msg='Revoked perm for group: %s in repo: %s' % ( group_name, repo_name ) ) except Exception: log.error(traceback.format_exc()) raise JSONRPCError( 'failed to edit permission %(repo)s for %(usersgr)s' % dict( usersgr=group_name, repo=repo_name ) )
def repo_public_journal(self, repo_name): """ Set's this repository to be visible in public journal, in other words assing default user to follow this repo :param repo_name: """ cur_token = request.POST.get('auth_token') token = get_token() if cur_token == token: try: repo_id = Repository.get_by_repo_name(repo_name).repo_id user_id = User.get_by_username('default').user_id self.scm_model.toggle_following_repo(repo_id, user_id) h.flash(_('Updated repository visibility in public journal'), category='success') Session().commit() except Exception: h.flash(_('An error occurred during setting this' ' repository in public journal'), category='error') else: h.flash(_('Token mismatch'), category='error') return redirect(url('edit_repo', repo_name=repo_name))
def repo_locking(self, repo_name): """ Unlock repository when it is locked ! :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if request.POST.get('set_lock'): Repository.lock(repo, c.rhodecode_user.user_id) elif request.POST.get('set_unlock'): Repository.unlock(repo) except Exception, e: log.error(traceback.format_exc()) h.flash(_('An error occurred during unlocking'), category='error')
def pull_changes(self, repo_name, username): dbrepo = Repository.get_by_repo_name(repo_name) clone_uri = dbrepo.clone_uri if not clone_uri: raise Exception("This repository doesn't have a clone uri") repo = dbrepo.scm_instance try: extras = { 'ip': '', 'username': username, 'action': 'push_remote', 'repository': repo_name, 'scm': repo.alias, } # 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.pull(clone_uri) self.mark_for_invalidation(repo_name) except: log.error(traceback.format_exc()) raise
def _get_permission_for_user(user, repo): perm = UserRepoToPerm.query()\ .filter(UserRepoToPerm.repository == Repository.get_by_repo_name(repo))\ .filter(UserRepoToPerm.user == User.get_by_username(user))\ .all() return perm
def test_index_with_fork(self): self.log_user() # create a fork fork_name = HG_FORK description = 'fork of vcs test' repo_name = HG_REPO org_repo = Repository.get_by_repo_name(repo_name) response = self.app.post( url(controller='forks', action='fork_create', repo_name=repo_name), { 'repo_name': fork_name, 'repo_group': '', 'fork_parent_id': org_repo.repo_id, 'repo_type': 'hg', 'description': description, 'private': 'False' }) response = self.app.get( url(controller='forks', action='forks', repo_name=repo_name)) self.assertTrue("""<a href="/%s/summary">""" """vcs_test_hg_fork</a>""" % fork_name in response.body) #remove this fork response = self.app.delete(url('repo', repo_name=fork_name))
def test_index_with_fork_git(self): self.log_user() # create a fork fork_name = GIT_FORK description = 'fork of vcs test' repo_name = GIT_REPO org_repo = Repository.get_by_repo_name(repo_name) response = self.app.post(url(controller='forks', action='fork_create', repo_name=repo_name), {'repo_name': fork_name, 'repo_group': '', 'fork_parent_id': org_repo.repo_id, 'repo_type': 'git', 'description': description, 'private': 'False', 'landing_rev': 'tip'}) response = self.app.get(url(controller='forks', action='forks', repo_name=repo_name)) response.mustcontain( """<a href="/%s">%s</a>""" % (fork_name, fork_name) ) #remove this fork response = self.app.delete(url('repo', repo_name=fork_name))
def repo_scan(self, repos_path=None): """ Listing of repositories in given path. This path should not be a repository itself. Return a dictionary of repository objects :param repos_path: path to directory containing repositories """ if repos_path is None: repos_path = self.repos_path log.info('scanning for repositories in %s', repos_path) config = make_db_config() config.set('extensions', 'largefiles', '') repos = {} for name, path in get_filesystem_repos(repos_path, recursive=True): # name need to be decomposed and put back together using the / # since this is internal storage separator for rhodecode name = Repository.normalize_repo_name(name) try: if name in repos: raise RepositoryError('Duplicate repository name %s ' 'found in %s' % (name, path)) elif path[0] in rhodecode.BACKENDS: klass = get_backend(path[0]) repos[name] = klass(path[1], config=config) except OSError: continue log.debug('found %s paths with repositories', len(repos)) return repos
def _commit_change( repo, filename, content, message, vcs_type, parent=None, newfile=False): repo = Repository.get_by_repo_name(repo) _commit = parent if not parent: _commit = EmptyCommit(alias=vcs_type) if newfile: nodes = { filename: { 'content': content } } commit = ScmModel().create_nodes( user=TEST_USER_ADMIN_LOGIN, repo=repo, message=message, nodes=nodes, parent_commit=_commit, author=TEST_USER_ADMIN_LOGIN, ) else: commit = ScmModel().commit_change( repo=repo.scm_instance(), repo_name=repo.repo_name, commit=parent, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message=message, content=content, f_path=filename ) return commit
def show(self, group_name, format='html'): """GET /repos_groups/group_name: Show a specific item""" # url('repos_group', group_name=GROUP_NAME) c.group = c.repos_group = ReposGroupModel()._get_repo_group(group_name) c.group_repos = c.group.repositories.all() #overwrite our cached list with current filter gr_filter = c.group_repos c.repo_cnt = 0 groups = RepoGroup.query().order_by(RepoGroup.group_name)\ .filter(RepoGroup.group_parent_id == c.group.group_id).all() c.groups = self.scm_model.get_repos_groups(groups) c.repos_list = Repository.query()\ .filter(Repository.group_id == c.group.group_id)\ .order_by(func.lower(Repository.repo_name))\ .all() repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, admin=False) #json used to render the grid c.data = json.dumps(repos_data) return render('admin/repos_groups/repos_groups.html')
def create_test_user(force=True): print '\tcreating test user' user = User.get_by_username(USER) if force and user is not None: print '\tremoving current user' for repo in Repository.query().filter(Repository.user == user).all(): sa.delete(repo) sa.delete(user) sa.commit() if user is None or force: print '\tcreating new one' new_usr = User() new_usr.username = USER new_usr.password = get_crypt_password(PASS) new_usr.email = '*****@*****.**' new_usr.name = 'test' new_usr.lastname = 'lasttestname' new_usr.active = True new_usr.admin = True sa.add(new_usr) sa.commit() print '\tdone'
def fork_create(self, repo_name): self.__load_defaults() c.repo_info = Repository.get_by_repo_name(repo_name) _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type}, repo_groups=c.repo_groups_choices, landing_revs=c.landing_revs_choices)() form_result = {} try: form_result = _form.to_python(dict(request.POST)) # an approximation that is better than nothing if not RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE).ui_active: form_result['update_after_clone'] = False # create fork is done sometimes async on celery, db transaction # management is handled there. RepoModel().create_fork(form_result, self.rhodecode_user.user_id) fork_url = h.link_to(form_result['repo_name_full'], h.url('summary_home', repo_name=form_result['repo_name_full'])) h.flash(h.literal(_('Forked repository %s as %s') \ % (repo_name, fork_url)), category='success') except formencode.Invalid, errors: c.new_repo = errors.value['repo_name'] return htmlfill.render( render('forks/fork.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8")
def _commit_change(repo, filename, content, message, vcs_type, parent=None, newfile=False): repo = Repository.get_by_repo_name(repo) _cs = parent if not parent: _cs = EmptyChangeset(alias=vcs_type) if newfile: nodes = { filename: { 'content': content } } cs = ScmModel().create_nodes( user=TEST_USER_ADMIN_LOGIN, repo=repo, message=message, nodes=nodes, parent_cs=_cs, author=TEST_USER_ADMIN_LOGIN, ) else: cs = ScmModel().commit_change( repo=repo.scm_instance, repo_name=repo.repo_name, cs=parent, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message=message, content=content, f_path=filename ) return cs
def test_z_fork_create(self): self.log_user() fork_name = HG_FORK description = 'fork of vcs test' repo_name = HG_REPO org_repo = Repository.get_by_repo_name(repo_name) response = self.app.post(url(controller='forks', action='fork_create', repo_name=repo_name), {'repo_name': fork_name, 'repo_group':'', 'fork_parent_id':org_repo.repo_id, 'repo_type':'hg', 'description':description, 'private':'False', 'landing_rev': 'tip'}) #test if we have a message that fork is ok self.checkSessionFlash(response, 'Forked repository %s as <a href="/%s">%s</a>' % (repo_name, fork_name, fork_name)) #test if the fork was created in the database fork_repo = Session().query(Repository)\ .filter(Repository.repo_name == fork_name).one() self.assertEqual(fork_repo.repo_name, fork_name) self.assertEqual(fork_repo.fork.repo_name, repo_name) #test if fork is visible in the list ? response = response.follow() response = self.app.get(url(controller='summary', action='index', repo_name=fork_name)) response.mustcontain('Fork of %s' % repo_name)
def map_groups(path): """ Given a full path to a repository, create all nested groups that this repo is inside. This function creates parent-child relationships between groups and creates default perms for all new groups. :param paths: full path to repository """ sa = meta.Session() groups = path.split(Repository.url_sep()) parent = None group = None # last element is repo in nested groups structure groups = groups[:-1] rgm = ReposGroupModel(sa) for lvl, group_name in enumerate(groups): group_name = '/'.join(groups[:lvl] + [group_name]) group = RepoGroup.get_by_group_name(group_name) desc = '%s group' % group_name # skip folders that are now removed repos if REMOVED_REPO_PAT.match(group_name): break if group is None: log.debug('creating group level: %s group_name: %s' % (lvl, group_name)) group = RepoGroup(group_name, parent) group.group_description = desc sa.add(group) rgm._create_default_perms(group) sa.flush() parent = group return group
def fork_create(self, repo_name): self.__load_defaults() c.repo_info = Repository.get_by_repo_name(repo_name) _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type}, repo_groups=c.repo_groups_choices, landing_revs=c.landing_revs_choices)() form_result = {} try: form_result = _form.to_python(dict(request.POST)) # create fork is done sometimes async on celery, db transaction # management is handled there. RepoModel().create_fork(form_result, self.rhodecode_user.user_id) h.flash(_('forked %s repository as %s') \ % (repo_name, form_result['repo_name']), category='success') except formencode.Invalid, errors: c.new_repo = errors.value['repo_name'] return htmlfill.render( render('forks/fork.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8")
def repo_public_journal(self, repo_name): """ Set's this repository to be visible in public journal, in other words assing default user to follow this repo :param repo_name: """ cur_token = request.POST.get('auth_token') token = get_token() if cur_token == token: try: repo_id = Repository.get_by_repo_name(repo_name).repo_id user_id = User.get_by_username('default').user_id self.scm_model.toggle_following_repo(repo_id, user_id) h.flash(_('Updated repository visibility in public journal'), category='success') Session.commit() except: h.flash(_('An error occurred during setting this' ' repository in public journal'), category='error') else: h.flash(_('Token mismatch'), category='error') return redirect(url('edit_repo', repo_name=repo_name))
def branch_tag_switcher(self, repo_name): if request.is_xhr: c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name) if c.rhodecode_db_repo: c.rhodecode_repo = c.rhodecode_db_repo.scm_instance return render('/switch_to_list.html') raise HTTPBadRequest()
def add_user_to_repo(self, apiuser, repo_name, user_name, perm): """ Add permission for a user to a repository :param apiuser :param repo_name :param user_name :param perm """ try: try: repo = Repository.get_by_repo_name(repo_name) except NoResultFound: raise JSONRPCError('unknown repository %s' % repo) try: user = User.get_by_username(user_name) except NoResultFound: raise JSONRPCError('unknown user %s' % user) RepositoryPermissionModel()\ .update_or_delete_user_permission(repo, user, perm) except Exception: log.error(traceback.format_exc()) raise JSONRPCError('failed to edit permission %(repo)s for %(user)s' % dict(user=user_name, repo=repo_name))