changeset 3039:a520d542697e beta

Implemented file history page for showing detailed changelog for a given file - fixed git detection of filenode history when executed on directory - shortlog uses urlify_commit function now
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 28 Nov 2012 01:27:21 +0100
parents 16456e7b2231
children ec483ce69ad9
files rhodecode/config/routing.py rhodecode/controllers/shortlog.py rhodecode/lib/vcs/backends/git/changeset.py rhodecode/lib/vcs/backends/hg/changeset.py rhodecode/public/css/style.css rhodecode/templates/files/files_history_box.html rhodecode/templates/shortlog/shortlog.html rhodecode/templates/shortlog/shortlog_data.html rhodecode/tests/functional/test_shortlog.py
diffstat 9 files changed, 126 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/config/routing.py	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/config/routing.py	Wed Nov 28 01:27:21 2012 +0100
@@ -514,6 +514,10 @@
     rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
                 controller='shortlog', conditions=dict(function=check_repo))
 
+    rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
+                controller='shortlog', f_path=None,
+                conditions=dict(function=check_repo))
+
     rmap.connect('branches_home', '/{repo_name:.*?}/branches',
                 controller='branches', conditions=dict(function=check_repo))
 
--- a/rhodecode/controllers/shortlog.py	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/controllers/shortlog.py	Wed Nov 28 01:27:21 2012 +0100
@@ -26,12 +26,16 @@
 import logging
 
 from pylons import tmpl_context as c, request, url
+from pylons.i18n.translation import _
 
+from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.helpers import RepoPage
 from pylons.controllers.util import redirect
 from rhodecode.lib.utils2 import safe_int
+from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError, ChangesetError,\
+    RepositoryError
 
 log = logging.getLogger(__name__)
 
@@ -44,19 +48,53 @@
     def __before__(self):
         super(ShortlogController, self).__before__()
 
-    def index(self, repo_name):
+    def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
+        """
+        Safe way to get changeset if error occur it redirects to tip with
+        proper message
+
+        :param rev: revision to fetch
+        :param repo_name: repo name to redirect after
+        """
+
+        try:
+            return c.rhodecode_repo.get_changeset(rev)
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('shortlog_home', repo_name=repo_name))
+
+    def index(self, repo_name, revision=None, f_path=None):
         p = safe_int(request.params.get('page', 1), 1)
         size = safe_int(request.params.get('size', 20), 20)
 
         def url_generator(**kw):
             return url('shortlog_home', repo_name=repo_name, size=size, **kw)
 
-        c.repo_changesets = RepoPage(c.rhodecode_repo, page=p,
+        collection = c.rhodecode_repo
+        c.file_history = f_path
+        if f_path:
+            f_path = f_path.lstrip('/')
+            # get the history for the file !
+            tip_cs = c.rhodecode_repo.get_changeset()
+            try:
+                collection = tip_cs.get_file_history(f_path)
+            except (NodeDoesNotExistError, ChangesetError):
+                #this node is not present at tip !
+                try:
+                    cs = self.__get_cs_or_redirect(revision, repo_name)
+                    collection = cs.get_file_history(f_path)
+                except RepositoryError, e:
+                    h.flash(str(e), category='warning')
+                    redirect(h.url('shortlog_home', repo_name=repo_name))
+            collection = list(reversed(collection))
+
+        c.repo_changesets = RepoPage(collection, page=p,
                                     items_per_page=size, url=url_generator)
-        page_revisions = [x.raw_id for x in list(c.repo_changesets)]
+        page_revisions = [x.raw_id for x in list(collection)]
         c.statuses = c.rhodecode_db_repo.statuses(page_revisions)
 
         if not c.repo_changesets:
+            h.flash(_('There are no changesets yet'), category='warning')
             return redirect(url('summary_home', repo_name=repo_name))
 
         c.shortlog_data = render('shortlog/shortlog_data.html')
--- a/rhodecode/lib/vcs/backends/git/changeset.py	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/lib/vcs/backends/git/changeset.py	Wed Nov 28 01:27:21 2012 +0100
@@ -162,6 +162,13 @@
         elif isinstance(obj, objects.Tree):
             return NodeKind.DIR
 
+    def _get_filectx(self, path):
+        path = self._fix_path(path)
+        if self._get_kind(path) != NodeKind.FILE:
+            raise ChangesetError("File does not exist for revision %r at "
+                " %r" % (self.raw_id, path))
+        return path
+
     def _get_file_nodes(self):
         return chain(*(t[2] for t in self.walk()))
 
@@ -264,6 +271,7 @@
         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
                )
--- a/rhodecode/lib/vcs/backends/hg/changeset.py	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/lib/vcs/backends/hg/changeset.py	Wed Nov 28 01:27:21 2012 +0100
@@ -181,7 +181,7 @@
         path = self._fix_path(path)
         if self._get_kind(path) != NodeKind.FILE:
             raise ChangesetError("File does not exist for revision %r at "
-                " %r" % (self.revision, path))
+                " %r" % (self.raw_id, path))
         return self._ctx.filectx(path)
 
     def _extract_submodules(self):
--- a/rhodecode/public/css/style.css	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/public/css/style.css	Wed Nov 28 01:27:21 2012 +0100
@@ -2650,15 +2650,14 @@
 #graph_content .container .mid .message a:hover{
 	text-decoration: none;
 }
-#content #graph_content .message .revision-link,
-#changeset_content .container .message .revision-link
+
+.revision-link
  {
 	color:#3F6F9F;
     font-weight: bold !important;
 }
 
-#content #graph_content .message .issue-tracker-link,
-#changeset_content .container .message .issue-tracker-link{
+.issue-tracker-link{
     color:#3F6F9F;
     font-weight: bold !important;
 }
--- a/rhodecode/templates/files/files_history_box.html	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/templates/files/files_history_box.html	Wed Nov 28 01:27:21 2012 +0100
@@ -8,6 +8,7 @@
             ${h.select('diff1',c.file_changeset.raw_id,c.file_history)}
             ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
             ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
+            ${h.link_to(_('show full history'),h.url('shortlog_file_home',repo_name=c.repo_name, revision=c.file_changeset.raw_id, f_path=c.f_path),class_="ui-btn")}
             ${h.hidden('annotate', c.annotate)}
             ${h.end_form()}
             </div>
--- a/rhodecode/templates/shortlog/shortlog.html	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/templates/shortlog/shortlog.html	Wed Nov 28 01:27:21 2012 +0100
@@ -11,7 +11,13 @@
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
-    ${_('shortlog')}
+    %if c.file_history:
+        ${h.link_to(_('shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
+        &raquo;
+        ${c.file_history}
+    %else:
+        ${_('shortlog')}
+    %endif
 </%def>
 
 <%def name="page_nav()">
--- a/rhodecode/templates/shortlog/shortlog_data.html	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/templates/shortlog/shortlog_data.html	Wed Nov 28 01:27:21 2012 +0100
@@ -30,9 +30,7 @@
          </div>
         </td>
         <td>
-            ${h.link_to(h.truncate(cs.message,50) or _('No commit message'),
-            h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
-            title=cs.message)}
+            ${h.urlify_commit(h.truncate(cs.message,50),c.repo_name, h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
         </td>
         <td><span class="tooltip" title="${h.tooltip(h.fmt_date(cs.date))}">
                       ${h.age(cs.date)}</span>
--- a/rhodecode/tests/functional/test_shortlog.py	Tue Nov 27 23:57:00 2012 +0100
+++ b/rhodecode/tests/functional/test_shortlog.py	Wed Nov 28 01:27:21 2012 +0100
@@ -1,8 +1,65 @@
 from rhodecode.tests import *
 
+
 class TestShortlogController(TestController):
 
-    def test_index(self):
+    def test_index_hg(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    repo_name=HG_REPO))
+        # Test response...
+
+    def test_index_git(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    repo_name=GIT_REPO))
+        # Test response...
+
+    def test_index_hg_with_filenode(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/vcs/exceptions.py',
+                                    repo_name=HG_REPO))
+        #history commits messages
+        response.mustcontain('Added exceptions module, this time for real')
+        response.mustcontain('Added not implemented hg backend test case')
+        response.mustcontain('Added BaseChangeset class')
+        # Test response...
+
+    def test_index_git_with_filenode(self):
         self.log_user()
-        response = self.app.get(url(controller='shortlog', action='index',repo_name=HG_REPO))
-        # Test response...
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/vcs/exceptions.py',
+                                    repo_name=GIT_REPO))
+        #history commits messages
+        response.mustcontain('Added exceptions module, this time for real')
+        response.mustcontain('Added not implemented hg backend test case')
+        response.mustcontain('Added BaseChangeset class')
+
+    def test_index_hg_with_filenode_that_is_dirnode(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/tests',
+                                    repo_name=HG_REPO))
+        self.assertEqual(response.status, '302 Found')
+
+    def test_index_git_with_filenode_that_is_dirnode(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/tests',
+                                    repo_name=GIT_REPO))
+        self.assertEqual(response.status, '302 Found')
+
+    def test_index_hg_with_filenode_not_existing(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/wrong_path',
+                                    repo_name=HG_REPO))
+        self.assertEqual(response.status, '302 Found')
+
+    def test_index_git_with_filenode_not_existing(self):
+        self.log_user()
+        response = self.app.get(url(controller='shortlog', action='index',
+                                    revision='tip', f_path='/wrong_path',
+                                    repo_name=GIT_REPO))
+        self.assertEqual(response.status, '302 Found')