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 __init__(self, name, url=None, changeset=None, alias=None): self.path = name self.kind = NodeKind.SUBMODULE self.alias = alias # we have to use emptyChangeset here since this can point to svn/git/hg # submodules we cannot get from repository self.changeset = EmptyChangeset(str(changeset), alias=alias) self.url = url or self._extract_submodule_url()
def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None, ignore_whitespace=True, line_context=3, enable_comments=False): """ returns a wrapped diff into a table, checks for cut_off_limit and presents proper message """ if filenode_old is None: filenode_old = FileNode(filenode_new.path, '', EmptyChangeset()) if filenode_old.is_binary or filenode_new.is_binary: diff = wrap_to_table(_('Binary file')) stats = (0, 0) size = 0 elif cut_off_limit != -1 and (cut_off_limit is None or (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)): f_gitdiff = get_gitdiff(filenode_old, filenode_new, ignore_whitespace=ignore_whitespace, context=line_context) diff_processor = DiffProcessor(f_gitdiff, format='gitdiff') diff = diff_processor.as_html(enable_comments=enable_comments) stats = diff_processor.stat() size = len(diff or '') else: diff = wrap_to_table( _('Changeset was too big and was cut off, use ' 'diff menu to display this diff')) stats = (0, 0) size = 0 if not diff: submodules = filter(lambda o: isinstance(o, SubModuleNode), [filenode_new, filenode_old]) if submodules: diff = wrap_to_table(escape('Submodule %r' % submodules[0])) else: diff = wrap_to_table(_('No changes detected')) cs1 = filenode_old.changeset.raw_id cs2 = filenode_new.changeset.raw_id return size, cs1, cs2, diff, stats
def get_changeset_safe(repo, rev): """ Safe version of get_changeset if this changeset doesn't exists for a repo it returns a Dummy one instead :param repo: :param rev: """ from rhodecode.lib.vcs.backends.base import BaseRepository from rhodecode.lib.vcs.exceptions import RepositoryError from rhodecode.lib.vcs.backends.base import EmptyChangeset if not isinstance(repo, BaseRepository): raise Exception('You must pass an Repository ' 'object as first argument got %s', type(repo)) try: cs = repo.get_changeset(rev) except RepositoryError: cs = EmptyChangeset(requested_revision=rev) return cs
def _changes_cache(self): added = set() modified = set() deleted = set() _r = self.repository._repo parents = self.parents if not self.parents: parents = [EmptyChangeset()] for parent in parents: if isinstance(parent, EmptyChangeset): oid = None else: oid = _r[parent.raw_id].tree changes = _r.object_store.tree_changes(oid, _r[self.raw_id].tree) for (oldpath, newpath), (_, _), (_, _) in changes: if newpath and oldpath: modified.add(newpath) elif newpath and not oldpath: added.add(newpath) elif not newpath and oldpath: deleted.add(oldpath) return added, modified, deleted
def diff(self, repo_name, f_path): ignore_whitespace = request.GET.get('ignorews') == '1' line_context = request.GET.get('context', 3) diff1 = request.GET.get('diff1', '') diff2 = request.GET.get('diff2', '') c.action = request.GET.get('diff') c.no_changes = diff1 == diff2 c.f_path = f_path c.big_diff = False c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url c.changes = OrderedDict() c.changes[diff2] = [] #special case if we want a show rev only, it's impl here #to reduce JS and callbacks if request.GET.get('show_rev'): if str2bool(request.GET.get('annotate', 'False')): _url = url('files_annotate_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) else: _url = url('files_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) return redirect(_url) try: if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) try: node1 = c.changeset_1.get_node(f_path) if node1.is_dir(): raise NodeError('%s path is a %s not a file' % (node1, type(node1))) except NodeDoesNotExistError: c.changeset_1 = EmptyChangeset(cs=diff1, revision=c.changeset_1.revision, repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) else: c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_2 = c.rhodecode_repo.get_changeset(diff2) try: node2 = c.changeset_2.get_node(f_path) if node2.is_dir(): raise NodeError('%s path is a %s not a file' % (node2, type(node2))) except NodeDoesNotExistError: c.changeset_2 = EmptyChangeset(cs=diff2, revision=c.changeset_2.revision, repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) else: c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) except (RepositoryError, NodeError): log.error(traceback.format_exc()) return redirect(url('files_home', repo_name=c.repo_name, f_path=f_path)) if c.action == 'download': _diff = diffs.get_gitdiff(node1, node2, ignore_whitespace=ignore_whitespace, context=line_context) diff = diffs.DiffProcessor(_diff, format='gitdiff') diff_name = '%s_vs_%s.diff' % (diff1, diff2) response.content_type = 'text/plain' response.content_disposition = ( 'attachment; filename=%s' % diff_name ) return diff.as_raw() elif c.action == 'raw': _diff = diffs.get_gitdiff(node1, node2, ignore_whitespace=ignore_whitespace, context=line_context) diff = diffs.DiffProcessor(_diff, format='gitdiff') response.content_type = 'text/plain' return diff.as_raw() else: fid = h.FID(diff2, node2.path) line_context_lcl = get_line_ctx(fid, request.GET) ign_whitespace_lcl = get_ignore_ws(fid, request.GET) lim = request.GET.get('fulldiff') or self.cut_off_limit _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1, filenode_new=node2, cut_off_limit=lim, ignore_whitespace=ign_whitespace_lcl, line_context=line_context_lcl, enable_comments=False) op = '' filename = node1.path cs_changes = { 'fid': [cs1, cs2, op, filename, diff, st] } c.changes = cs_changes return render('files/file_diff.html')
def add(self, repo_name, revision, f_path): repo = Repository.get_by_repo_name(repo_name) if repo.enable_locking and repo.locked[0]: h.flash(_('This repository is has been locked by %s on %s') % (h.person_by_id(repo.locked[0]), h.fmt_date(h.time_to_datetime(repo.locked[1]))), 'warning') return redirect(h.url('files_home', repo_name=repo_name, revision='tip')) r_post = request.POST c.cs = self.__get_cs_or_redirect(revision, repo_name, redirect_after=False) if c.cs is None: c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias) c.default_message = (_('Added file via RhodeCode')) c.f_path = f_path if r_post: unix_mode = 0 content = convert_line_endings(r_post.get('content'), unix_mode) message = r_post.get('message') or c.default_message filename = r_post.get('filename') location = r_post.get('location') file_obj = r_post.get('upload_file', None) if file_obj is not None and hasattr(file_obj, 'filename'): filename = file_obj.filename content = file_obj.file if not content: h.flash(_('No content'), category='warning') return redirect(url('changeset_home', repo_name=c.repo_name, revision='tip')) if not filename: h.flash(_('No filename'), category='warning') return redirect(url('changeset_home', repo_name=c.repo_name, revision='tip')) if location.startswith('/') or location.startswith('.') or '../' in location: h.flash(_('Location must be relative path and must not ' 'contain .. in path'), category='warning') return redirect(url('changeset_home', repo_name=c.repo_name, revision='tip')) if location: location = os.path.normpath(location) filename = os.path.basename(filename) node_path = os.path.join(location, filename) author = self.rhodecode_user.full_contact try: self.scm_model.create_node(repo=c.rhodecode_repo, repo_name=repo_name, cs=c.cs, user=self.rhodecode_user.user_id, author=author, message=message, content=content, f_path=node_path) h.flash(_('Successfully committed to %s') % node_path, category='success') except (NodeError, NodeAlreadyExistsError), e: h.flash(_(e), category='error') except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during commit'), category='error')
def changeset_info(self, repo_name, revision): if request.is_xhr: try: return c.rhodecode_repo.get_changeset(revision) except ChangesetDoesNotExistError, e: return EmptyChangeset(message=str(e))
class ChangesetController(BaseRepoController): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def __before__(self): super(ChangesetController, self).__before__() c.affected_files_cut_off = 60 repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() def index(self, revision, method='show'): c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = fulldiff = request.GET.get('fulldiff') #get ranges of revisions if preset rev_range = revision.split('...')[:2] enable_comments = True try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start, end=rev_end) else: rev_ranges = [c.rhodecode_repo.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (RepositoryError, ChangesetDoesNotExistError, Exception), e: log.error(traceback.format_exc()) h.flash(str(e), category='error') raise HTTPNotFound() c.changes = OrderedDict() c.lines_added = 0 # count of lines added c.lines_deleted = 0 # count of lines removes c.changeset_statuses = ChangesetStatus.STATUSES c.comments = [] c.statuses = [] c.inline_comments = [] c.inline_cnt = 0 # Iterate over ranges (default changeset view is always one changeset) for changeset in c.cs_ranges: inlines = [] if method == 'show': c.statuses.extend([ChangesetStatusModel().get_status( c.rhodecode_db_repo.repo_id, changeset.raw_id)]) c.comments.extend(ChangesetCommentsModel()\ .get_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id)) #comments from PR st = ChangesetStatusModel().get_statuses( c.rhodecode_db_repo.repo_id, changeset.raw_id, with_revisions=True) # from associated statuses, check the pull requests, and # show comments from them prs = set([x.pull_request for x in filter(lambda x: x.pull_request != None, st)]) for pr in prs: c.comments.extend(pr.comments) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id) c.inline_comments.extend(inlines) c.changes[changeset.raw_id] = [] cs2 = changeset.raw_id cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset() context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.rhodecode_repo.get_diff(cs1, cs2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) diff_limit = self.cut_off_limit if not fulldiff else None diff_processor = diffs.DiffProcessor(_diff, vcs=c.rhodecode_repo.alias, format='gitdiff', diff_limit=diff_limit) cs_changes = OrderedDict() if method == 'show': _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True for f in _parsed: st = f['stats'] if st[0] != 'b': c.lines_added += st[0] c.lines_deleted += st[1] fid = h.FID(changeset.raw_id, f['filename']) diff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'], diff, st] else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() cs_changes[''] = [None, None, None, None, diff, None] c.changes[changeset.raw_id] = cs_changes #sort comments by how they were generated c.comments = sorted(c.comments, key=lambda x: x.comment_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) if len(c.cs_ranges) == 1: c.changeset = c.cs_ranges[0] c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in c.changeset.parents]) if method == 'download': response.content_type = 'text/plain' response.content_disposition = 'attachment; filename=%s.diff' \ % revision[:12] return diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_unicode(diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return diff elif method == 'show': if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: return render('changeset/changeset_range.html')
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 :param org_repo: :param org_ref: :param other_repo: :param other_ref: :param tmp: """ ancestor = None if alias == 'hg': # lookup up the exact node id _revset_predicates = { 'branch': 'branch', 'book': 'bookmark', 'tag': 'tag', 'rev': 'id', } org_rev_spec = "%s('%s')" % (_revset_predicates[org_ref[0]], safe_str(org_ref[1])) if org_ref[1] == EmptyChangeset().raw_id: org_rev = org_ref[1] else: org_rev = org_repo._repo[scmutil.revrange(org_repo._repo, [org_rev_spec])[-1]] other_rev_spec = "%s('%s')" % (_revset_predicates[other_ref[0]], safe_str(other_ref[1])) if other_ref[1] == EmptyChangeset().raw_id: other_rev = other_ref[1] else: other_rev = other_repo._repo[scmutil.revrange(other_repo._repo, [other_rev_spec])[-1]] #case two independent repos if org_repo != other_repo: hgrepo = unionrepo.unionrepository(other_repo.baseui, other_repo.path, org_repo.path) # all the changesets we are looking for will be in other_repo, # so rev numbers from hgrepo can be used in other_repo #no remote compare do it on the same repository else: hgrepo = other_repo._repo if merge: revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" % (other_rev, org_rev, org_rev)] 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 so, se = org_repo.run_git_command( 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1], other_ref[1]) ) changesets = [org_repo.get_changeset(cs) for cs in re.findall(r'[0-9a-fA-F]{40}', so)] return changesets, ancestor
def index(self, repo_name): c.dbrepo = dbrepo = c.rhodecode_db_repo def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) page_revisions = [x.raw_id for x in list(c.repo_changesets)] c.statuses = c.rhodecode_db_repo.statuses(page_revisions) if self.rhodecode_user.username == 'default': # for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' parsed_url = urlparse(url.current(qualified=True)) default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}' uri_tmpl = config.get('clone_uri', default_clone_uri) uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s') decoded_path = safe_unicode(urllib.unquote(parsed_url.path)) uri_dict = { 'user': urllib.quote(username), 'pass': password, 'scheme': parsed_url.scheme, 'netloc': parsed_url.netloc, 'path': urllib.quote(safe_str(decoded_path)) } uri = (uri_tmpl % uri_dict) # generate another clone url by id uri_dict.update({ 'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id) }) uri_id = uri_tmpl % uri_dict c.clone_repo_url = uri c.clone_repo_url_id = uri_id c.repo_tags = OrderedDict() for name, hash_ in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash_) c.repo_branches = OrderedDict() for name, hash_ in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash_) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') recurse_limit = 500 # don't recurse more than 500 times when parsing run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y, recurse_limit) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, { "count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x) }) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float( (last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) c.readme_data, c.readme_file = \ self.__get_readme_data(c.rhodecode_db_repo) return render('summary/summary.html')
def diff_2way(self, repo_name, f_path): diff1 = request.GET.get('diff1', '') diff2 = request.GET.get('diff2', '') try: if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) try: node1 = c.changeset_1.get_node(f_path) if node1.is_dir(): raise NodeError('%s path is a %s not a file' % (node1, type(node1))) except NodeDoesNotExistError: c.changeset_1 = EmptyChangeset( cs=diff1, revision=c.changeset_1.revision, repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) else: c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_2 = c.rhodecode_repo.get_changeset(diff2) try: node2 = c.changeset_2.get_node(f_path) if node2.is_dir(): raise NodeError('%s path is a %s not a file' % (node2, type(node2))) except NodeDoesNotExistError: c.changeset_2 = EmptyChangeset( cs=diff2, revision=c.changeset_2.revision, repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) else: c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) except (RepositoryError, NodeError): log.error(traceback.format_exc()) return redirect( url('files_home', repo_name=c.repo_name, f_path=f_path)) if node2.is_binary: node2_content = 'binary file' else: node2_content = node2.content if node1.is_binary: node1_content = 'binary file' else: node1_content = node1.content html_escape_table = { "&": "\u0026", '"': "\u0022", "'": "\u0027", ">": "\u003e", "<": "\u003c", '\\': "\u005c", '\n': '\\n' } c.orig1 = h.html_escape((node1_content), html_escape_table) c.orig2 = h.html_escape((node2_content), html_escape_table) c.node1 = node1 c.node2 = node2 c.cs1 = c.changeset_1 c.cs2 = c.changeset_2 return render('files/diff_2way.html')
def add(self, repo_name, revision, f_path): repo = Repository.get_by_repo_name(repo_name) if repo.enable_locking and repo.locked[0]: h.flash( _('This repository is has been locked by %s on %s') % (h.person_by_id(repo.locked[0]), h.fmt_date(h.time_to_datetime(repo.locked[1]))), 'warning') return redirect( h.url('files_home', repo_name=repo_name, revision='tip')) r_post = request.POST c.cs = self.__get_cs_or_redirect(revision, repo_name, redirect_after=False) if c.cs is None: c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias) c.default_message = (_('Added file via RhodeCode')) c.f_path = f_path if r_post: unix_mode = 0 content = convert_line_endings(r_post.get('content', ''), unix_mode) message = r_post.get('message') or c.default_message filename = r_post.get('filename') location = r_post.get('location', '') file_obj = r_post.get('upload_file', None) if file_obj is not None and hasattr(file_obj, 'filename'): filename = file_obj.filename content = file_obj.file if hasattr(content, 'file'): # non posix systems store real file under file attr content = content.file if not content: h.flash(_('No content'), category='warning') return redirect( url('changeset_home', repo_name=c.repo_name, revision='tip')) if not filename: h.flash(_('No filename'), category='warning') return redirect( url('changeset_home', repo_name=c.repo_name, revision='tip')) #strip all crap out of file, just leave the basename filename = os.path.basename(filename) node_path = os.path.join(location, filename) author = self.rhodecode_user.full_contact try: nodes = {node_path: {'content': content}} self.scm_model.create_nodes( user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo, message=message, nodes=nodes, parent_cs=c.cs, author=author, ) h.flash(_('Successfully committed to %s') % node_path, category='success') except NonRelativePathError, e: h.flash(_('Location must be relative path and must not ' 'contain .. in path'), category='warning') return redirect( url('changeset_home', repo_name=c.repo_name, revision='tip')) except (NodeError, NodeAlreadyExistsError), e: h.flash(_(e), category='error')
def handle_git_receive(repo_path, revs, env, hook_type='post'): """ A really hacky method that is runned by git post-receive hook and logs an push action together with pushed revisions. It's executed by subprocess thus needs all info to be able to create a on the fly pylons enviroment, connect to database and run the logging code. Hacky as sh*t but works. :param repo_path: :param revs: :param env: """ from paste.deploy import appconfig from sqlalchemy import engine_from_config from rhodecode.config.environment import load_environment from rhodecode.model import init_model from rhodecode.model.db import RhodeCodeUi from rhodecode.lib.utils import make_ui extras = _extract_extras(env) path, ini_name = os.path.split(extras['config']) conf = appconfig('config:%s' % ini_name, relative_to=path) load_environment(conf.global_conf, conf.local_conf) engine = engine_from_config(conf, 'sqlalchemy.db1.') init_model(engine) baseui = make_ui('db') # fix if it's not a bare repo if repo_path.endswith(os.sep + '.git'): repo_path = repo_path[:-5] repo = Repository.get_by_full_path(repo_path) if not repo: raise OSError('Repository %s not found in database' % (safe_str(repo_path))) _hooks = dict(baseui.configitems('hooks')) or {} if hook_type == 'pre': repo = repo.scm_instance else: #post push shouldn't use the cached instance never repo = repo.scm_instance_no_cache() if hook_type == 'pre': pre_push(baseui, repo) # if push hook is enabled via web interface elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH): rev_data = [] for l in revs: old_rev, new_rev, ref = l.split(' ') _ref_data = ref.split('/') if _ref_data[1] in ['tags', 'heads']: rev_data.append({ 'old_rev': old_rev, 'new_rev': new_rev, 'ref': ref, 'type': _ref_data[1], 'name': _ref_data[2].strip() }) git_revs = [] for push_ref in rev_data: _type = push_ref['type'] if _type == 'heads': if push_ref['old_rev'] == EmptyChangeset().raw_id: cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'" heads = repo.run_git_command(cmd)[0] heads = heads.replace(push_ref['ref'], '') heads = ' '.join( map(lambda c: c.strip('\n').strip(), heads.splitlines())) cmd = (('log %(new_rev)s' % push_ref) + ' --reverse --pretty=format:"%H" --not ' + heads) git_revs += repo.run_git_command(cmd)[0].splitlines() elif push_ref['new_rev'] == EmptyChangeset().raw_id: #delete branch case git_revs += ['delete_branch=>%s' % push_ref['name']] else: cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) + ' --reverse --pretty=format:"%H"') git_revs += repo.run_git_command(cmd)[0].splitlines() elif _type == 'tags': git_revs += ['tag=>%s' % push_ref['name']] log_push_action(baseui, repo, _git_revs=git_revs)
def test_org_repo_new_commits_after_forking_simple_diff(self): self.log_user() repo1 = fixture.create_repo('one', repo_type='hg', repo_description='diff-test', cur_user=TEST_USER_ADMIN_LOGIN) self.r1_id = repo1.repo_id r1_name = repo1.repo_name #commit something initially ! cs0 = ScmModel().create_node(repo=repo1.scm_instance, repo_name=r1_name, cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message='commit1', content='line1', f_path='file1') Session().commit() self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id]) #fork the repo1 repo2 = fixture.create_repo('one-fork', repo_type='hg', repo_description='diff-test', cur_user=TEST_USER_ADMIN_LOGIN, clone_uri=repo1.repo_full_path, fork_of='one') Session().commit() self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id]) self.r2_id = repo2.repo_id r2_name = repo2.repo_name #make 3 new commits in fork cs1 = ScmModel().create_node(repo=repo2.scm_instance, repo_name=r2_name, cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message='commit1-fork', content='file1-line1-from-fork', f_path='file1-fork') cs2 = ScmModel().create_node(repo=repo2.scm_instance, repo_name=r2_name, cs=cs1, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message='commit2-fork', content='file2-line1-from-fork', f_path='file2-fork') cs3 = ScmModel().create_node(repo=repo2.scm_instance, repo_name=r2_name, cs=cs2, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message='commit3-fork', content='file3-line1-from-fork', f_path='file3-fork') #compare ! rev1 = 'default' rev2 = 'default' response = self.app.get( url( controller='compare', action='index', repo_name=r2_name, org_ref_type="branch", org_ref=rev1, other_ref_type="branch", other_ref=rev2, other_repo=r1_name, merge='1', )) response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2)) response.mustcontain('No files') response.mustcontain('No changesets') #add new commit into parent ! cs0 = ScmModel().create_node(repo=repo1.scm_instance, repo_name=r1_name, cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, message='commit2-parent', content='line1-added-after-fork', f_path='file2') #compare ! rev1 = 'default' rev2 = 'default' response = self.app.get( url( controller='compare', action='index', repo_name=r2_name, org_ref_type="branch", org_ref=rev1, other_ref_type="branch", other_ref=rev2, other_repo=r1_name, merge='1', )) response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2)) response.mustcontain("""commit2-parent""") response.mustcontain( """1 file changed with 1 insertions and 0 deletions""") response.mustcontain("""line1-added-after-fork""")