Commit c28b044d authored by Eric Davis's avatar Eric Davis

Added branch and tag support to the git repository viewer. (#1406)

Many thanks to Adam Soltys and everyone else who tested this patch.

* Updated git test repository so it has a branch with some differences from the master branch
* Moved redmine diff class into a module so as not to clash with diff-lcs gem which is required by grit
* Find changesets from all branches, not just master
* Got revision browsing working
* Got file actions working properly
* Allow browsing by short form of commit identifier
* Added a method to retrieve repository branches
* Allow browsing by branch names as well as commit numbers
* Handle the case where a git repository has no master branch
* Expand revision box and handle finding revisions by first 8 characters
* Added branches dropdown to repository show page
* Combined repository browse and show into a single action.  Moved branch/revision navigation into a partial.
* Renamed partial navigation -> breadcrumbs
* Made it so latest revisions list uses branch and path context
* Preserve current path when changing branch or revision
* Perform slightly more graceful error handling in the case of invalid repository URLs
* Allow branch names to contain periods
* Allow dashes in branch names
* Sort branches by name
* Adding tags dropdown
* Need to disable both branches and tags dropdowns before submitting revision form
* Support underscores in revision (branch/tag) names
* Making file history sensitive to current branch/tag/revision, adding common navigation to changes page
* Updated translation files to include labels for 'branch', 'tag', and 'view all revisions'
* Reenable fields after submit so they don't look disabled and don't stay disabled on browser back button
* Instead of dashes just use empty string for default dropdown value
* Individual entry views now sport the upgraded revision navigation
* Don't display dropdowns with no entries
* Consider all revisions when doing initial load
* Fixed bug grabbing changesets.  Thanks to Bernhard Furtmueller for catching.
* Always check the entire log to find new revisions, rather than trying to go forward from the latest known one
* Added some cleverness to avoid selecting the whole changesets table any time someone views the repository root
* File copies and renames being detected properly
* Return gracefully if no revisions are found in the git log
* Applied patch from Babar Le Lapin to improve Windows compatibility

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2840 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent a39bc8f1
...@@ -64,31 +64,26 @@ class RepositoriesController < ApplicationController ...@@ -64,31 +64,26 @@ class RepositoriesController < ApplicationController
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository' redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
end end
def show def show
# check if new revisions have been committed in the repository @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
@repository.fetch_changesets if Setting.autofetch_changesets?
# root entries
@entries = @repository.entries('', @rev)
# latest changesets
@changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC")
show_error_not_found unless @entries || @changesets.any?
end
def browse
@entries = @repository.entries(@path, @rev) @entries = @repository.entries(@path, @rev)
if request.xhr? if request.xhr?
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true) @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
else else
show_error_not_found and return unless @entries show_error_not_found and return unless @entries
@changesets = @repository.latest_changesets(@path, @rev)
@properties = @repository.properties(@path, @rev) @properties = @repository.properties(@path, @rev)
render :action => 'browse' render :action => 'show'
end end
end end
alias_method :browse, :show
def changes def changes
@entry = @repository.entry(@path, @rev) @entry = @repository.entry(@path, @rev)
show_error_not_found and return unless @entry show_error_not_found and return unless @entry
@changesets = @repository.changesets_for_path(@path, :limit => Setting.repository_log_display_limit.to_i) @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
@properties = @repository.properties(@path, @rev) @properties = @repository.properties(@path, @rev)
end end
...@@ -135,7 +130,7 @@ class RepositoriesController < ApplicationController ...@@ -135,7 +130,7 @@ class RepositoriesController < ApplicationController
end end
def revision def revision
@changeset = @repository.changesets.find_by_revision(@rev) @changeset = @repository.changesets.find(:first, :conditions => ["revision LIKE ?", @rev + '%'])
raise ChangesetNotFound unless @changeset raise ChangesetNotFound unless @changeset
respond_to do |format| respond_to do |format|
...@@ -199,17 +194,14 @@ private ...@@ -199,17 +194,14 @@ private
render_404 render_404
end end
REV_PARAM_RE = %r{^[a-f0-9]*$}
def find_repository def find_repository
@project = Project.find(params[:id]) @project = Project.find(params[:id])
@repository = @project.repository @repository = @project.repository
render_404 and return false unless @repository render_404 and return false unless @repository
@path = params[:path].join('/') unless params[:path].nil? @path = params[:path].join('/') unless params[:path].nil?
@path ||= '' @path ||= ''
@rev = params[:rev] @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
@rev_to = params[:rev_to] @rev_to = params[:rev_to]
raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
rescue InvalidRevisionParam rescue InvalidRevisionParam
......
...@@ -62,6 +62,18 @@ class Repository < ActiveRecord::Base ...@@ -62,6 +62,18 @@ class Repository < ActiveRecord::Base
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
scm.entries(path, identifier) scm.entries(path, identifier)
end end
def branches
scm.branches
end
def tags
scm.tags
end
def default_branch
scm.default_branch
end
def properties(path, identifier=nil) def properties(path, identifier=nil)
scm.properties(path, identifier) scm.properties(path, identifier)
...@@ -92,11 +104,15 @@ class Repository < ActiveRecord::Base ...@@ -92,11 +104,15 @@ class Repository < ActiveRecord::Base
def latest_changeset def latest_changeset
@latest_changeset ||= changesets.find(:first) @latest_changeset ||= changesets.find(:first)
end end
def latest_changesets(path,rev,limit=10)
@latest_changesets ||= changesets.find(:all, limit, :order => "committed_on DESC")
end
def scan_changesets_for_issue_ids def scan_changesets_for_issue_ids
self.changesets.each(&:scan_comment_for_issue_ids) self.changesets.each(&:scan_comment_for_issue_ids)
end end
# Returns an array of committers usernames and associated user_id # Returns an array of committers usernames and associated user_id
def committers def committers
@committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
......
...@@ -29,43 +29,60 @@ class Repository::Git < Repository ...@@ -29,43 +29,60 @@ class Repository::Git < Repository
'Git' 'Git'
end end
def branches
scm.branches
end
def tags
scm.tags
end
def changesets_for_path(path, options={}) def changesets_for_path(path, options={})
Change.find(:all, :include => {:changeset => :user}, Change.find(
:conditions => ["repository_id = ? AND path = ?", id, path], :all,
:order => "committed_on DESC, #{Changeset.table_name}.revision DESC", :include => {:changeset => :user},
:limit => options[:limit]).collect(&:changeset) :conditions => ["repository_id = ? AND path = ?", id, path],
:order => "committed_on DESC, #{Changeset.table_name}.revision DESC",
:limit => options[:limit]
).collect(&:changeset)
end end
# With SCM's that have a sequential commit numbering, redmine is able to be
# clever and only fetch changesets going forward from the most recent one
# it knows about. However, with git, you never know if people have merged
# commits into the middle of the repository history, so we always have to
# parse the entire log.
def fetch_changesets def fetch_changesets
scm_info = scm.info # Save ourselves an expensive operation if we're already up to date
if scm_info return if scm.num_revisions == changesets.count
# latest revision found in database
db_revision = latest_changeset ? latest_changeset.revision : nil revisions = scm.revisions('', nil, nil, :all => true)
# latest revision in the repository return if revisions.nil? || revisions.empty?
scm_revision = scm_info.lastrev.scmid
# Find revisions that redmine knows about already
existing_revisions = changesets.find(:all).map!{|c| c.scmid}
# Clean out revisions that are no longer in git
Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id])
# Subtract revisions that redmine already knows about
revisions.reject!{|r| existing_revisions.include?(r.scmid)}
# Save the remaining ones to the database
revisions.each{|r| r.save(self)} unless revisions.nil?
end
def latest_changesets(path,rev,limit=10)
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
return [] if revisions.nil? || revisions.empty?
unless changesets.find_by_scmid(scm_revision) changesets.find(
scm.revisions('', db_revision, nil, :reverse => true) do |revision| :all,
if changesets.find_by_scmid(revision.scmid.to_s).nil? :conditions => [
transaction do "scmid IN (?)",
changeset = Changeset.create!(:repository => self, revisions.map!{|c| c.scmid}
:revision => revision.identifier, ],
:scmid => revision.scmid, :order => 'committed_on DESC'
:committer => revision.author, )
:committed_on => revision.time,
:comments => revision.message)
revision.paths.each do |change|
Change.create!(:changeset => changeset,
:action => change[:action],
:path => change[:path],
:from_path => change[:from_path],
:from_revision => change[:from_revision])
end
end
end
end
end
end
end end
end end
<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %>
<%
dirs = path.split('/')
if 'file' == kind
filename = dirs.pop
end
link_path = ''
dirs.each do |dir|
next if dir.blank?
link_path << '/' unless link_path.empty?
link_path << "#{dir}"
%>
/ <%= link_to h(dir), :action => 'show', :id => @project, :path => to_path_param(link_path), :rev => @rev %>
<% end %>
<% if filename %>
/ <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
<% end %>
<%= "@ #{revision}" if revision %>
<% html_title(with_leading_slash(path)) -%>
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<tr id="<%= tr_id %>" class="<%= params[:parent_id] %> entry <%= entry.kind %>"> <tr id="<%= tr_id %>" class="<%= params[:parent_id] %> entry <%= entry.kind %>">
<td style="padding-left: <%=18 * depth%>px;" class="filename"> <td style="padding-left: <%=18 * depth%>px;" class="filename">
<% if entry.is_dir? %> <% if entry.is_dir? %>
<span class="expander" onclick="<%= remote_function :url => {:action => 'browse', :id => @project, :path => to_path_param(entry.path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id}, <span class="expander" onclick="<%= remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(entry.path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id},
:method => :get, :method => :get,
:update => { :success => tr_id }, :update => { :success => tr_id },
:position => :after, :position => :after,
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
:condition => "scmEntryClick('#{tr_id}')"%>">&nbsp</span> :condition => "scmEntryClick('#{tr_id}')"%>">&nbsp</span>
<% end %> <% end %>
<%= link_to h(entry.name), <%= link_to h(entry.name),
{:action => (entry.is_dir? ? 'browse' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev}, {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev},
:class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(entry.name)}")%> :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(entry.name)}")%>
</td> </td>
<td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td> <td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td>
......
<%= link_to 'root', :action => 'browse', :id => @project, :path => '', :rev => @rev %> <% content_for :header_tags do %>
<% <%= javascript_include_tag 'repository_navigation' %>
dirs = path.split('/')
if 'file' == kind
filename = dirs.pop
end
link_path = ''
dirs.each do |dir|
next if dir.blank?
link_path << '/' unless link_path.empty?
link_path << "#{dir}"
%>
/ <%= link_to h(dir), :action => 'browse', :id => @project, :path => to_path_param(link_path), :rev => @rev %>
<% end %>
<% if filename %>
/ <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
<% end %> <% end %>
<%= "@ #{revision}" if revision %> <%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %>
<% form_tag({:action => controller.action_name, :id => @project, :path => @path, :rev => ''}, {:method => :get, :id => 'revision_selector'}) do -%>
<!-- Branches Dropdown -->
<% if !@repository.branches.nil? && @repository.branches.length > 0 -%>
| <%= l(:label_branch) %>:
<%= select_tag :branch, options_for_select([''] + @repository.branches,@rev), :id => 'branch' %>
<% end -%>
<% if !@repository.tags.nil? && @repository.tags.length > 0 -%>
| <%= l(:label_tag) %>:
<%= select_tag :tag, options_for_select([''] + @repository.tags,@rev), :id => 'tag' %>
<% end -%>
<% html_title(with_leading_slash(path)) -%> | <%= l(:label_revision) %>:
<%= text_field_tag 'rev', @rev, :size => 8 %>
<% end -%>
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2> <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
<div class="contextual">
<%= render :partial => 'navigation' %>
</div>
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
<p><%= render :partial => 'link_to_functions' %></p> <p><%= render :partial => 'link_to_functions' %></p>
......
<div class="contextual"> <div class="contextual">
<% form_tag({}, :method => :get) do %> <%= render :partial => 'navigation' %>
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
<% end %>
</div> </div>
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2> <h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
<%= render :partial => 'dir_list' %> <%= render :partial => 'dir_list' %>
<%= render_properties(@properties) %> <%= render_properties(@properties) %>
......
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2> <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
<div class="contextual">
<%= render :partial => 'navigation' %>
</div>
<h2>
<%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %>
</h2>
<p><%= render :partial => 'link_to_functions' %></p> <p><%= render :partial => 'link_to_functions' %></p>
......
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2> <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
<div class="contextual">
<%= render :partial => 'navigation' %>
</div>
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
<p><%= render :partial => 'link_to_functions' %></p> <p><%= render :partial => 'link_to_functions' %></p>
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
&#187;&nbsp; &#187;&nbsp;
<% form_tag({:controller => 'repositories', :action => 'revision', :id => @project, :rev => nil}, :method => :get) do %> <% form_tag({:controller => 'repositories', :action => 'revision', :id => @project, :rev => nil}, :method => :get) do %>
<%= text_field_tag 'rev', @rev, :size => 5 %> <%= text_field_tag 'rev', @rev[0,8], :size => 8 %>
<%= submit_tag 'OK', :name => nil %> <%= submit_tag 'OK', :name => nil %>
<% end %> <% end %>
</div> </div>
......
<div class="contextual"> <div class="contextual">
<% form_tag({:action => 'revision', :id => @project}) do %> <% form_tag({:action => 'revision', :id => @project}) do %>
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %> <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %>
<%= submit_tag 'OK' %> <%= submit_tag 'OK' %>
<% end %> <% end %>
</div> </div>
......
<div class="contextual">
<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %>
<% if !@entries.nil? && authorize_for('repositories', 'browse') -%> <div class="contextual">
<% form_tag({:action => 'browse', :id => @project}, :method => :get) do -%> <%= render :partial => 'navigation' %>
| <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
<% end -%>
<% end -%>
</div> </div>
<h2><%= l(:label_repository) %> (<%= @repository.scm_name %>)</h2> <h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
<% if !@entries.nil? && authorize_for('repositories', 'browse') %> <% if !@entries.nil? && authorize_for('repositories', 'browse') %>
<%= render :partial => 'dir_list' %> <%= render :partial => 'dir_list' %>
...@@ -18,7 +13,7 @@ ...@@ -18,7 +13,7 @@
<% if !@changesets.empty? && authorize_for('repositories', 'revisions') %> <% if !@changesets.empty? && authorize_for('repositories', 'revisions') %>
<h3><%= l(:label_latest_revision_plural) %></h3> <h3><%= l(:label_latest_revision_plural) %></h3>
<%= render :partial => 'revisions', :locals => {:project => @project, :path => '', :revisions => @changesets, :entry => nil }%> <%= render :partial => 'revisions', :locals => {:project => @project, :path => '', :revisions => @changesets, :entry => nil }%>
<p><%= link_to l(:label_view_revisions), :action => 'revisions', :id => @project %></p> <p><%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project %></p>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :action => 'revisions', :id => @project, :page => nil, :key => User.current.rss_key})) %> <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :action => 'revisions', :id => @project, :page => nil, :key => User.current.rss_key})) %>
<% end %> <% end %>
......
...@@ -798,3 +798,6 @@ bg: ...@@ -798,3 +798,6 @@ bg:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -831,3 +831,6 @@ bs: ...@@ -831,3 +831,6 @@ bs:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -801,3 +801,6 @@ ca: ...@@ -801,3 +801,6 @@ ca:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -804,3 +804,6 @@ cs: ...@@ -804,3 +804,6 @@ cs:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -831,3 +831,6 @@ da: ...@@ -831,3 +831,6 @@ da:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -830,3 +830,6 @@ de: ...@@ -830,3 +830,6 @@ de:
mail_body_wiki_content_updated: "Die Wiki-Seite '{{page}}' wurde von {{author}} aktualisiert." mail_body_wiki_content_updated: "Die Wiki-Seite '{{page}}' wurde von {{author}} aktualisiert."
permission_add_project: Erstelle Projekt permission_add_project: Erstelle Projekt
setting_new_project_user_role_id: Rolle einem Nicht-Administrator zugeordnet, welcher ein Projekt erstellt setting_new_project_user_role_id: Rolle einem Nicht-Administrator zugeordnet, welcher ein Projekt erstellt
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -543,6 +543,8 @@ en: ...@@ -543,6 +543,8 @@ en:
label_browse: Browse label_browse: Browse
label_modification: "{{count}} change" label_modification: "{{count}} change"
label_modification_plural: "{{count}} changes" label_modification_plural: "{{count}} changes"
label_branch: Branch
label_tag: Tag
label_revision: Revision label_revision: Revision
label_revision_plural: Revisions label_revision_plural: Revisions
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
...@@ -554,6 +556,7 @@ en: ...@@ -554,6 +556,7 @@ en:
label_latest_revision: Latest revision label_latest_revision: Latest revision
label_latest_revision_plural: Latest revisions label_latest_revision_plural: Latest revisions
label_view_revisions: View revisions label_view_revisions: View revisions
label_view_all_revisions: View all revisions
label_max_size: Maximum size label_max_size: Maximum size
label_sort_highest: Move to top label_sort_highest: Move to top
label_sort_higher: Move up label_sort_higher: Move up
......
...@@ -851,3 +851,6 @@ es: ...@@ -851,3 +851,6 @@ es:
mail_body_wiki_content_updated: La página wiki '{{page}}' ha sido actualizada por {{author}}. mail_body_wiki_content_updated: La página wiki '{{page}}' ha sido actualizada por {{author}}.
permission_add_project: Crear proyecto permission_add_project: Crear proyecto
setting_new_project_user_role_id: Permiso asignado a un usuario no-administrador para crear proyectos setting_new_project_user_role_id: Permiso asignado a un usuario no-administrador para crear proyectos
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -841,3 +841,6 @@ fi: ...@@ -841,3 +841,6 @@ fi:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -832,4 +832,7 @@ fr: ...@@ -832,4 +832,7 @@ fr:
enumeration_doc_categories: Catégories des documents enumeration_doc_categories: Catégories des documents
enumeration_activities: Activités (suivi du temps) enumeration_activities: Activités (suivi du temps)
label_greater_or_equal: ">=" label_greater_or_equal: ">="
label_less_or_equal: <= label_less_or_equal: "<="
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -830,3 +830,6 @@ gl: ...@@ -830,3 +830,6 @@ gl:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -813,3 +813,6 @@ he: ...@@ -813,3 +813,6 @@ he:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -836,3 +836,6 @@ ...@@ -836,3 +836,6 @@
mail_body_wiki_content_updated: A '{{page}}' wiki oldalt {{author}} frissítette. mail_body_wiki_content_updated: A '{{page}}' wiki oldalt {{author}} frissítette.
permission_add_project: Projekt létrehozása permission_add_project: Projekt létrehozása
setting_new_project_user_role_id: Projekt létrehozási jog nem adminisztrátor felhasználóknak setting_new_project_user_role_id: Projekt létrehozási jog nem adminisztrátor felhasználóknak
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -816,3 +816,6 @@ it: ...@@ -816,3 +816,6 @@ it:
mail_body_wiki_content_updated: La pagina '{{page}}' wiki è stata aggiornata da{{author}}. mail_body_wiki_content_updated: La pagina '{{page}}' wiki è stata aggiornata da{{author}}.
permission_add_project: Crea progetto permission_add_project: Crea progetto
setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -838,3 +838,6 @@ ja: ...@@ -838,3 +838,6 @@ ja:
enumeration_issue_priorities: チケットの優先度 enumeration_issue_priorities: チケットの優先度
enumeration_doc_categories: 文書カテゴリ enumeration_doc_categories: 文書カテゴリ
enumeration_activities: 作業分類 (時間トラッキング) enumeration_activities: 作業分類 (時間トラッキング)
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -869,3 +869,6 @@ ko: ...@@ -869,3 +869,6 @@ ko:
# by Kihyun Yoon(ddumbugie@gmail.com) # by Kihyun Yoon(ddumbugie@gmail.com)
# by John Hwang (jhwang@tavon.org),http://github.com/tavon # by John Hwang (jhwang@tavon.org),http://github.com/tavon
field_issue_to: Related issue field_issue_to: Related issue
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -841,3 +841,6 @@ lt: ...@@ -841,3 +841,6 @@ lt:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -786,3 +786,6 @@ nl: ...@@ -786,3 +786,6 @@ nl:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -803,3 +803,6 @@ ...@@ -803,3 +803,6 @@
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -834,3 +834,6 @@ pl: ...@@ -834,3 +834,6 @@ pl:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -836,3 +836,6 @@ pt-BR: ...@@ -836,3 +836,6 @@ pt-BR:
mail_body_wiki_content_updated: A página wiki '{{page}}' foi atualizada por {{author}}. mail_body_wiki_content_updated: A página wiki '{{page}}' foi atualizada por {{author}}.
permission_add_project: Criar projeto permission_add_project: Criar projeto
setting_new_project_user_role_id: Papel dado a um usuário não administrador que crie um projeto setting_new_project_user_role_id: Papel dado a um usuário não administrador que crie um projeto
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -822,3 +822,6 @@ pt: ...@@ -822,3 +822,6 @@ pt:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -801,3 +801,6 @@ ro: ...@@ -801,3 +801,6 @@ ro:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -928,3 +928,6 @@ ru: ...@@ -928,3 +928,6 @@ ru:
mail_body_wiki_content_updated: "{{author}} обновил(а) wiki-страницу '{{page}}'." mail_body_wiki_content_updated: "{{author}} обновил(а) wiki-страницу '{{page}}'."
permission_add_project: Создание проекта permission_add_project: Создание проекта
setting_new_project_user_role_id: Роль, назначаемая пользователю, создавшему проект setting_new_project_user_role_id: Роль, назначаемая пользователю, создавшему проект
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -802,4 +802,7 @@ sk: ...@@ -802,4 +802,7 @@ sk:
label_wiki_content_updated: Wiki stránka aktualizovaná label_wiki_content_updated: Wiki stránka aktualizovaná
mail_body_wiki_content_updated: Wiki stránka '{{page}}' bola aktualizovaná užívateľom {{author}}. mail_body_wiki_content_updated: Wiki stránka '{{page}}' bola aktualizovaná užívateľom {{author}}.
setting_repositories_encodings: Kódovanie repozitára setting_repositories_encodings: Kódovanie repozitára
setting_new_project_user_role_id: Rola dána non-admin užívateľovi, ktorý vytvorí projekt setting_new_project_user_role_id: Rola dána non-admin užívateľovi, ktorý vytvorí projekt
\ No newline at end of file label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -800,3 +800,6 @@ sl: ...@@ -800,3 +800,6 @@ sl:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -824,3 +824,6 @@ ...@@ -824,3 +824,6 @@
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -858,3 +858,6 @@ sv: ...@@ -858,3 +858,6 @@ sv:
enumeration_issue_priorities: Ärendeprioriteter enumeration_issue_priorities: Ärendeprioriteter
enumeration_doc_categories: Dokumentkategorier enumeration_doc_categories: Dokumentkategorier
enumeration_activities: Aktiviteter (tidsuppföljning) enumeration_activities: Aktiviteter (tidsuppföljning)
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -801,3 +801,6 @@ th: ...@@ -801,3 +801,6 @@ th:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -837,3 +837,6 @@ tr: ...@@ -837,3 +837,6 @@ tr:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -800,3 +800,6 @@ uk: ...@@ -800,3 +800,6 @@ uk:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -870,3 +870,6 @@ vi: ...@@ -870,3 +870,6 @@ vi:
mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}.
permission_add_project: Create project permission_add_project: Create project
setting_new_project_user_role_id: Role given to a non-admin user who creates a project setting_new_project_user_role_id: Role given to a non-admin user who creates a project
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -908,3 +908,6 @@ ...@@ -908,3 +908,6 @@
enumeration_issue_priorities: 項目優先權 enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類 enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤) enumeration_activities: 活動 (時間追蹤)
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -833,3 +833,6 @@ zh: ...@@ -833,3 +833,6 @@ zh:
enumeration_issue_priorities: 问题优先级 enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别 enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪) enumeration_activities: 活动(时间跟踪)
label_view_all_revisions: View all revisions
label_tag: Tag
label_branch: Branch
...@@ -218,7 +218,7 @@ ActionController::Routing::Routes.draw do |map| ...@@ -218,7 +218,7 @@ ActionController::Routing::Routes.draw do |map|
repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision' repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff' repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff' repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path' repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
repository_views.connect 'projects/:id/repository/:action/*path' repository_views.connect 'projects/:id/repository/:action/*path'
end end
......
class Diff module RedmineDiff
class Diff
VERSION = 0.3 VERSION = 0.3
def Diff.lcs(a, b) def Diff.lcs(a, b)
astart = 0 astart = 0
bstart = 0 bstart = 0
afinish = a.length-1 afinish = a.length-1
bfinish = b.length-1 bfinish = b.length-1
mvector = [] mvector = []
# First we prune off any common elements at the beginning # First we prune off any common elements at the beginning
while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart]) while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart])
mvector[astart] = bstart mvector[astart] = bstart
astart += 1 astart += 1
bstart += 1 bstart += 1
end end
# now the end # now the end
while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish]) while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish])
mvector[afinish] = bfinish mvector[afinish] = bfinish
afinish -= 1 afinish -= 1
bfinish -= 1 bfinish -= 1
end end
bmatches = b.reverse_hash(bstart..bfinish) bmatches = b.reverse_hash(bstart..bfinish)
thresh = [] thresh = []
links = [] links = []
(astart..afinish).each { |aindex| (astart..afinish).each { |aindex|
aelem = a[aindex] aelem = a[aindex]
next unless bmatches.has_key? aelem next unless bmatches.has_key? aelem
k = nil k = nil
bmatches[aelem].reverse.each { |bindex| bmatches[aelem].reverse.each { |bindex|
if k && (thresh[k] > bindex) && (thresh[k-1] < bindex) if k && (thresh[k] > bindex) && (thresh[k-1] < bindex)
thresh[k] = bindex thresh[k] = bindex
else else
k = thresh.replacenextlarger(bindex, k) k = thresh.replacenextlarger(bindex, k)
end end
links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k
}
} }
}
if !thresh.empty? if !thresh.empty?
link = links[thresh.length-1] link = links[thresh.length-1]
while link while link
mvector[link[1]] = link[2] mvector[link[1]] = link[2]
link = link[0] link = link[0]
end
end end
end
return mvector return mvector
end
def makediff(a, b)
mvector = Diff.lcs(a, b)
ai = bi = 0
while ai < mvector.length
bline = mvector[ai]
if bline
while bi < bline
discardb(bi, b[bi])
bi += 1
end
match(ai, bi)
bi += 1
else
discarda(ai, a[ai])
end
ai += 1
end
while ai < a.length
discarda(ai, a[ai])
ai += 1
end end
while bi < b.length
def makediff(a, b)
mvector = Diff.lcs(a, b)
ai = bi = 0
while ai < mvector.length
bline = mvector[ai]
if bline
while bi < bline
discardb(bi, b[bi]) discardb(bi, b[bi])
bi += 1 bi += 1
end end
match(ai, bi) match(ai, bi)
1 bi += 1
end else
discarda(ai, a[ai])
def compactdiffs end
diffs = [] ai += 1
@diffs.each { |df|
i = 0
curdiff = []
while i < df.length
whot = df[i][0]
s = @isstring ? df[i][2].chr : [df[i][2]]
p = df[i][1]
last = df[i][1]
i += 1
while df[i] && df[i][0] == whot && df[i][1] == last+1
s << df[i][2]
last = df[i][1]
i += 1
end
curdiff.push [whot, p, s]
end end
diffs.push curdiff while ai < a.length
} discarda(ai, a[ai])
return diffs ai += 1
end end
while bi < b.length
discardb(bi, b[bi])
bi += 1
end
match(ai, bi)
1
end
attr_reader :diffs, :difftype def compactdiffs
diffs = []
@diffs.each { |df|
i = 0
curdiff = []
while i < df.length
whot = df[i][0]
s = @isstring ? df[i][2].chr : [df[i][2]]
p = df[i][1]
last = df[i][1]
i += 1
while df[i] && df[i][0] == whot && df[i][1] == last+1
s << df[i][2]
last = df[i][1]
i += 1
end
curdiff.push [whot, p, s]
end
diffs.push curdiff
}
return diffs
end
def initialize(diffs_or_a, b = nil, isstring = nil) attr_reader :diffs, :difftype
if b.nil?
@diffs = diffs_or_a def initialize(diffs_or_a, b = nil, isstring = nil)
@isstring = isstring if b.nil?
else @diffs = diffs_or_a
@diffs = [] @isstring = isstring
else
@diffs = []
@curdiffs = []
makediff(diffs_or_a, b)
@difftype = diffs_or_a.class
end
end
def match(ai, bi)
@diffs.push @curdiffs unless @curdiffs.empty?
@curdiffs = [] @curdiffs = []
makediff(diffs_or_a, b)
@difftype = diffs_or_a.class
end end
end
def match(ai, bi)
@diffs.push @curdiffs unless @curdiffs.empty?
@curdiffs = []
end
def discarda(i, elem) def discarda(i, elem)
@curdiffs.push ['-', i, elem] @curdiffs.push ['-', i, elem]
end end
def discardb(i, elem) def discardb(i, elem)
@curdiffs.push ['+', i, elem] @curdiffs.push ['+', i, elem]
end end
def compact def compact
return Diff.new(compactdiffs) return Diff.new(compactdiffs)
end end
def compact! def compact!
@diffs = compactdiffs @diffs = compactdiffs
end end
def inspect def inspect
@diffs.inspect @diffs.inspect
end end
end
end end
module Diffable module Diffable
def diff(b) def diff(b)
Diff.new(self, b) RedmineDiff::Diff.new(self, b)
end end
# Create a hash that maps elements of the array to arrays of indices # Create a hash that maps elements of the array to arrays of indices
...@@ -158,9 +160,9 @@ module Diffable ...@@ -158,9 +160,9 @@ module Diffable
range.each { |i| range.each { |i|
elem = self[i] elem = self[i]
if revmap.has_key? elem if revmap.has_key? elem
revmap[elem].push i revmap[elem].push i
else else
revmap[elem] = [i] revmap[elem] = [i]
end end
} }
return revmap return revmap
...@@ -179,9 +181,9 @@ module Diffable ...@@ -179,9 +181,9 @@ module Diffable
found = self[index] found = self[index]
return nil if value == found return nil if value == found
if value > found if value > found
low = index + 1 low = index + 1
else else
high = index high = index
end end
end end
...@@ -204,25 +206,25 @@ module Diffable ...@@ -204,25 +206,25 @@ module Diffable
bi = 0 bi = 0
diff.diffs.each { |d| diff.diffs.each { |d|
d.each { |mod| d.each { |mod|
case mod[0] case mod[0]
when '-' when '-'
while ai < mod[1] while ai < mod[1]
newary << self[ai] newary << self[ai]
ai += 1 ai += 1
bi += 1 bi += 1
end end
ai += 1 ai += 1
when '+' when '+'
while bi < mod[1] while bi < mod[1]
newary << self[ai] newary << self[ai]
ai += 1 ai += 1
bi += 1 bi += 1
end end
newary << mod[2] newary << mod[2]
bi += 1 bi += 1
else else
raise "Unknown diff action" raise "Unknown diff action"
end end
} }
} }
while ai < self.length while ai < self.length
...@@ -243,38 +245,38 @@ class String ...@@ -243,38 +245,38 @@ class String
end end
=begin =begin
= Diff = Diff
(({diff.rb})) - computes the differences between two arrays or (({diff.rb})) - computes the differences between two arrays or
strings. Copyright (C) 2001 Lars Christensen strings. Copyright (C) 2001 Lars Christensen
== Synopsis == Synopsis
diff = Diff.new(a, b) diff = Diff.new(a, b)
b = a.patch(diff) b = a.patch(diff)
== Class Diff == Class Diff
=== Class Methods === Class Methods
--- Diff.new(a, b) --- Diff.new(a, b)
--- a.diff(b) --- a.diff(b)
Creates a Diff object which represent the differences between Creates a Diff object which represent the differences between
((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays ((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays
of any objects, strings, or object of any class that include of any objects, strings, or object of any class that include
module ((|Diffable|)) module ((|Diffable|))
== Module Diffable == Module Diffable
The module ((|Diffable|)) is intended to be included in any class for The module ((|Diffable|)) is intended to be included in any class for
which differences are to be computed. Diffable is included into String which differences are to be computed. Diffable is included into String
and Array when (({diff.rb})) is (({require}))'d. and Array when (({diff.rb})) is (({require}))'d.
Classes including Diffable should implement (({[]})) to get element at Classes including Diffable should implement (({[]})) to get element at
integer indices, (({<<})) to append elements to the object and integer indices, (({<<})) to append elements to the object and
(({ClassName#new})) should accept 0 arguments to create a new empty (({ClassName#new})) should accept 0 arguments to create a new empty
object. object.
=== Instance Methods === Instance Methods
--- Diffable#patch(diff) --- Diffable#patch(diff)
Applies the differences from ((|diff|)) to the object ((|obj|)) Applies the differences from ((|diff|)) to the object ((|obj|))
and return the result. ((|obj|)) is not changed. ((|obj|)) and and return the result. ((|obj|)) is not changed. ((|obj|)) and
can be either an array or a string, but must match the object can be either an array or a string, but must match the object
from which the ((|diff|)) was created. from which the ((|diff|)) was created.
=end =end
...@@ -100,6 +100,18 @@ module Redmine ...@@ -100,6 +100,18 @@ module Redmine
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
return nil return nil
end end
def branches
return nil
end
def tags
return nil
end
def default_branch
return nil
end
def properties(path, identifier=nil) def properties(path, identifier=nil)
return nil return nil
...@@ -260,6 +272,7 @@ module Redmine ...@@ -260,6 +272,7 @@ module Redmine
class Revision class Revision
attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch
def initialize(attributes={}) def initialize(attributes={})
self.identifier = attributes[:identifier] self.identifier = attributes[:identifier]
self.scmid = attributes[:scmid] self.scmid = attributes[:scmid]
...@@ -271,7 +284,25 @@ module Redmine ...@@ -271,7 +284,25 @@ module Redmine
self.revision = attributes[:revision] self.revision = attributes[:revision]
self.branch = attributes[:branch] self.branch = attributes[:branch]
end end
def save(repo)
if repo.changesets.find_by_scmid(scmid.to_s).nil?
changeset = Changeset.create!(
:repository => repo,
:revision => identifier,
:scmid => scmid,
:committer => author,
:committed_on => time,
:comments => message)
paths.each do |file|
Change.create!(
:changeset => changeset,
:action => file[:action],
:path => file[:path])
end
end
end
end end
class Annotate class Annotate
......
This diff is collapsed.
Event.observe(window,'load',function() {
/*
If we're viewing a tag or branch, don't display it in the
revision box
*/
var branch_selected = $('branch') && $('rev').getValue() == $('branch').getValue();
var tag_selected = $('tag') && $('rev').getValue() == $('tag').getValue();
if (branch_selected || tag_selected) {
$('rev').setValue('');
}
/*
Copy the branch/tag value into the revision box, then disable
the dropdowns before submitting the form
*/
$$('#branch,#tag').each(function(e) {
e.observe('change',function(e) {
$('rev').setValue(e.element().getValue());
$$('#branch,#tag').invoke('disable');
e.element().parentNode.submit();
$$('#branch,#tag').invoke('enable');
});
});
/*
Disable the branch/tag dropdowns before submitting the revision form
*/
$('rev').observe('keydown', function(e) {
if (e.keyCode == 13) {
$$('#branch,#tag').invoke('disable');
e.element().parentNode.submit();
$$('#branch,#tag').invoke('enable');
}
});
})
...@@ -181,7 +181,7 @@ div.square { ...@@ -181,7 +181,7 @@ div.square {
width: .6em; height: .6em; width: .6em; height: .6em;
} }
.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
.contextual input {font-size:0.9em;} .contextual input,select {font-size:0.9em;}
.message .contextual { margin-top: 0; } .message .contextual { margin-top: 0; }
.splitcontentleft{float:left; width:49%;} .splitcontentleft{float:left; width:49%;}
......
...@@ -45,9 +45,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase ...@@ -45,9 +45,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase
end end
def test_browse_root def test_browse_root
get :browse, :id => 3 get :show, :id => 3
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal 2, assigns(:entries).size assert_equal 2, assigns(:entries).size
assert assigns(:entries).detect {|e| e.name == 'directory' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'directory' && e.kind == 'dir'}
...@@ -55,9 +55,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase ...@@ -55,9 +55,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase
end end
def test_browse_directory def test_browse_directory
get :browse, :id => 3, :path => ['directory'] get :show, :id => 3, :path => ['directory']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['doc-ls.txt', 'document.txt', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['doc-ls.txt', 'document.txt', 'edit.png'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
...@@ -67,9 +67,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase ...@@ -67,9 +67,9 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase
end end
def test_browse_at_given_revision def test_browse_at_given_revision
get :browse, :id => 3, :path => [], :rev => 3 get :show, :id => 3, :path => [], :rev => 3
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], assigns(:entries).collect(&:name) assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], assigns(:entries).collect(&:name)
end end
...@@ -102,7 +102,7 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase ...@@ -102,7 +102,7 @@ class RepositoriesBazaarControllerTest < Test::Unit::TestCase
def test_directory_entry def test_directory_entry
get :entry, :id => 3, :path => ['directory'] get :entry, :id => 3, :path => ['directory']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entry) assert_not_nil assigns(:entry)
assert_equal 'directory', assigns(:entry).name assert_equal 'directory', assigns(:entry).name
end end
......
...@@ -51,9 +51,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase ...@@ -51,9 +51,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase
end end
def test_browse_root def test_browse_root
get :browse, :id => 1 get :show, :id => 1
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal 3, assigns(:entries).size assert_equal 3, assigns(:entries).size
...@@ -65,9 +65,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase ...@@ -65,9 +65,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase
end end
def test_browse_directory def test_browse_directory
get :browse, :id => 1, :path => ['images'] get :show, :id => 1, :path => ['images']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
...@@ -78,9 +78,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase ...@@ -78,9 +78,9 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase
def test_browse_at_given_revision def test_browse_at_given_revision
Project.find(1).repository.fetch_changesets Project.find(1).repository.fetch_changesets
get :browse, :id => 1, :path => ['images'], :rev => 1 get :show, :id => 1, :path => ['images'], :rev => 1
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
end end
...@@ -118,7 +118,7 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase ...@@ -118,7 +118,7 @@ class RepositoriesCvsControllerTest < Test::Unit::TestCase
def test_directory_entry def test_directory_entry
get :entry, :id => 1, :path => ['sources'] get :entry, :id => 1, :path => ['sources']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entry) assert_not_nil assigns(:entry)
assert_equal 'sources', assigns(:entry).name assert_equal 'sources', assigns(:entry).name
end end
......
...@@ -45,9 +45,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase ...@@ -45,9 +45,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase
end end
def test_browse_root def test_browse_root
get :browse, :id => 3 get :show, :id => 3
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal 3, assigns(:entries).size assert_equal 3, assigns(:entries).size
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
...@@ -56,9 +56,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase ...@@ -56,9 +56,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase
end end
def test_browse_directory def test_browse_directory
get :browse, :id => 3, :path => ['images'] get :show, :id => 3, :path => ['images']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
...@@ -69,9 +69,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase ...@@ -69,9 +69,9 @@ class RepositoriesDarcsControllerTest < Test::Unit::TestCase
def test_browse_at_given_revision def test_browse_at_given_revision
Project.find(3).repository.fetch_changesets Project.find(3).repository.fetch_changesets
get :browse, :id => 3, :path => ['images'], :rev => 1 get :show, :id => 3, :path => ['images'], :rev => 1
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png'], assigns(:entries).collect(&:name)
end end
......
...@@ -46,22 +46,37 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase ...@@ -46,22 +46,37 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase
end end
def test_browse_root def test_browse_root
get :browse, :id => 3 get :show, :id => 3
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal 3, assigns(:entries).size assert_equal 6, assigns(:entries).size
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
end end
def test_browse_branch
get :show, :id => 3, :rev => 'test_branch'
assert_response :success
assert_template 'show'
assert_not_nil assigns(:entries)
assert_equal 4, assigns(:entries).size
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
end
def test_browse_directory def test_browse_directory
get :browse, :id => 3, :path => ['images'] get :show, :id => 3, :path => ['images']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['edit.png'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
assert_not_nil entry assert_not_nil entry
assert_equal 'file', entry.kind assert_equal 'file', entry.kind
...@@ -69,9 +84,9 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase ...@@ -69,9 +84,9 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase
end end
def test_browse_at_given_revision def test_browse_at_given_revision
get :browse, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518' get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png'], assigns(:entries).collect(&:name)
end end
...@@ -89,7 +104,7 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase ...@@ -89,7 +104,7 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase
assert_template 'entry' assert_template 'entry'
# Line 19 # Line 19
assert_tag :tag => 'th', assert_tag :tag => 'th',
:content => /10/, :content => /11/,
:attributes => { :class => /line-num/ }, :attributes => { :class => /line-num/ },
:sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
end end
...@@ -104,7 +119,7 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase ...@@ -104,7 +119,7 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase
def test_directory_entry def test_directory_entry
get :entry, :id => 3, :path => ['sources'] get :entry, :id => 3, :path => ['sources']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entry) assert_not_nil assigns(:entry)
assert_equal 'sources', assigns(:entry).name assert_equal 'sources', assigns(:entry).name
end end
...@@ -127,14 +142,14 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase ...@@ -127,14 +142,14 @@ class RepositoriesGitControllerTest < Test::Unit::TestCase
assert_response :success assert_response :success
assert_template 'annotate' assert_template 'annotate'
# Line 23, changeset 2f9c0091 # Line 23, changeset 2f9c0091
assert_tag :tag => 'th', :content => /23/, assert_tag :tag => 'th', :content => /24/,
:sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } }, :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } },
:sibling => { :tag => 'td', :content => /jsmith/ }, :sibling => { :tag => 'td', :content => /jsmith/ },
:sibling => { :tag => 'td', :content => /watcher =/ } :sibling => { :tag => 'td', :content => /watcher =/ }
end end
def test_annotate_binary_file def test_annotate_binary_file
get :annotate, :id => 3, :path => ['images', 'delete.png'] get :annotate, :id => 3, :path => ['images', 'edit.png']
assert_response 500 assert_response 500
assert_tag :tag => 'div', :attributes => { :class => /error/ }, assert_tag :tag => 'div', :attributes => { :class => /error/ },
:content => /can not be annotated/ :content => /can not be annotated/
......
...@@ -44,10 +44,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase ...@@ -44,10 +44,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase
assert_not_nil assigns(:changesets) assert_not_nil assigns(:changesets)
end end
def test_browse_root def test_show_root
get :browse, :id => 3 get :show, :id => 3
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal 3, assigns(:entries).size assert_equal 3, assigns(:entries).size
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
...@@ -55,10 +55,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase ...@@ -55,10 +55,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
end end
def test_browse_directory def test_show_directory
get :browse, :id => 3, :path => ['images'] get :show, :id => 3, :path => ['images']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
...@@ -67,10 +67,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase ...@@ -67,10 +67,10 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase
assert_equal 'images/edit.png', entry.path assert_equal 'images/edit.png', entry.path
end end
def test_browse_at_given_revision def test_show_at_given_revision
get :browse, :id => 3, :path => ['images'], :rev => 0 get :show, :id => 3, :path => ['images'], :rev => 0
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['delete.png'], assigns(:entries).collect(&:name) assert_equal ['delete.png'], assigns(:entries).collect(&:name)
end end
...@@ -103,7 +103,7 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase ...@@ -103,7 +103,7 @@ class RepositoriesMercurialControllerTest < Test::Unit::TestCase
def test_directory_entry def test_directory_entry
get :entry, :id => 3, :path => ['sources'] get :entry, :id => 3, :path => ['sources']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entry) assert_not_nil assigns(:entry)
assert_equal 'sources', assigns(:entry).name assert_equal 'sources', assigns(:entry).name
end end
......
...@@ -47,18 +47,18 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase ...@@ -47,18 +47,18 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase
end end
def test_browse_root def test_browse_root
get :browse, :id => 1 get :show, :id => 1
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
entry = assigns(:entries).detect {|e| e.name == 'subversion_test'} entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
assert_equal 'dir', entry.kind assert_equal 'dir', entry.kind
end end
def test_browse_directory def test_browse_directory
get :browse, :id => 1, :path => ['subversion_test'] get :show, :id => 1, :path => ['subversion_test']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name) assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'} entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
...@@ -68,9 +68,9 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase ...@@ -68,9 +68,9 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase
end end
def test_browse_at_given_revision def test_browse_at_given_revision
get :browse, :id => 1, :path => ['subversion_test'], :rev => 4 get :show, :id => 1, :path => ['subversion_test'], :rev => 4
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entries) assert_not_nil assigns(:entries)
assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name) assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
end end
...@@ -131,7 +131,7 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase ...@@ -131,7 +131,7 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase
def test_directory_entry def test_directory_entry
get :entry, :id => 1, :path => ['subversion_test', 'folder'] get :entry, :id => 1, :path => ['subversion_test', 'folder']
assert_response :success assert_response :success
assert_template 'browse' assert_template 'show'
assert_not_nil assigns(:entry) assert_not_nil assigns(:entry)
assert_equal 'folder', assigns(:entry).name assert_equal 'folder', assigns(:entry).name
end end
......
require File.dirname(__FILE__) + '/../test_helper'
class GitAdapterTest < Test::Unit::TestCase
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
end
def test_branches
assert_equal @adapter.branches, ['master', 'test_branch']
end
def test_getting_all_revisions
assert_equal 12, @adapter.revisions('',nil,nil,:all => true).length
end
else
puts "Git test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end
...@@ -34,8 +34,8 @@ class RepositoryGitTest < Test::Unit::TestCase ...@@ -34,8 +34,8 @@ class RepositoryGitTest < Test::Unit::TestCase
@repository.fetch_changesets @repository.fetch_changesets
@repository.reload @repository.reload
assert_equal 6, @repository.changesets.count assert_equal 12, @repository.changesets.count
assert_equal 11, @repository.changes.count assert_equal 20, @repository.changes.count
commit = @repository.changesets.find(:first, :order => 'committed_on ASC') commit = @repository.changesets.find(:first, :order => 'committed_on ASC')
assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
...@@ -57,10 +57,10 @@ class RepositoryGitTest < Test::Unit::TestCase ...@@ -57,10 +57,10 @@ class RepositoryGitTest < Test::Unit::TestCase
# Remove the 3 latest changesets # Remove the 3 latest changesets
@repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy) @repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy)
@repository.reload @repository.reload
assert_equal 3, @repository.changesets.count assert_equal 9, @repository.changesets.count
@repository.fetch_changesets @repository.fetch_changesets
assert_equal 6, @repository.changesets.count assert_equal 12, @repository.changesets.count
end end
else else
puts "Git test repository NOT FOUND. Skipping unit tests !!!" puts "Git test repository NOT FOUND. Skipping unit tests !!!"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment