Feature #1406 » branch_support.diff
app/controllers/repositories_controller.rb | ||
---|---|---|
64 | 64 |
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository' |
65 | 65 |
end |
66 | 66 |
|
67 |
def show |
|
68 |
# check if new revisions have been committed in the repository |
|
69 |
@repository.fetch_changesets if Setting.autofetch_changesets? |
|
70 |
# root entries |
|
71 |
@entries = @repository.entries('', @rev) |
|
72 |
# latest changesets |
|
73 |
@changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC") |
|
74 |
show_error_not_found unless @entries || @changesets.any? |
|
75 |
end |
|
76 |
|
|
77 |
def browse |
|
67 |
def show |
|
68 |
@repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? |
|
69 | ||
78 | 70 |
@entries = @repository.entries(@path, @rev) |
79 | 71 |
if request.xhr? |
80 | 72 |
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true) |
81 | 73 |
else |
82 | 74 |
show_error_not_found and return unless @entries |
75 |
@changesets = @repository.latest_changesets(@path, @branch) |
|
83 | 76 |
@properties = @repository.properties(@path, @rev) |
84 |
render :action => 'browse'
|
|
77 |
render :action => 'show'
|
|
85 | 78 |
end |
86 | 79 |
end |
80 | ||
81 |
alias_method :browse, :show |
|
87 | 82 |
|
88 | 83 |
def changes |
89 | 84 |
@entry = @repository.entry(@path, @rev) |
... | ... | |
135 | 130 |
end |
136 | 131 |
|
137 | 132 |
def revision |
138 |
@changeset = @repository.changesets.find_by_revision(@rev)
|
|
133 |
@changeset = @repository.changesets.find(:first, :conditions => ["revision LIKE ?", @rev + '%'])
|
|
139 | 134 |
raise ChangesetNotFound unless @changeset |
140 | 135 | |
141 | 136 |
respond_to do |format| |
... | ... | |
199 | 194 |
render_404 |
200 | 195 |
end |
201 | 196 |
|
202 |
REV_PARAM_RE = %r{^[a-f0-9]*$} |
|
203 |
|
|
204 | 197 |
def find_repository |
205 | 198 |
@project = Project.find(params[:id]) |
206 | 199 |
@repository = @project.repository |
207 | 200 |
render_404 and return false unless @repository |
208 | 201 |
@path = params[:path].join('/') unless params[:path].nil? |
209 | 202 |
@path ||= '' |
210 |
@rev = params[:rev] |
|
203 |
@rev = params[:rev].nil? || params[:rev].empty? ? nil : params[:rev] |
|
204 |
@branch = @rev.nil? ? @repository.default_branch : @rev |
|
211 | 205 |
@rev_to = params[:rev_to] |
212 |
raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE) |
|
213 | 206 |
rescue ActiveRecord::RecordNotFound |
214 | 207 |
render_404 |
215 | 208 |
rescue InvalidRevisionParam |
app/models/repository.rb | ||
---|---|---|
62 | 62 |
def entries(path=nil, identifier=nil) |
63 | 63 |
scm.entries(path, identifier) |
64 | 64 |
end |
65 | ||
66 |
def branches |
|
67 |
scm.branches |
|
68 |
end |
|
69 | ||
70 |
def default_branch |
|
71 |
scm.default_branch |
|
72 |
end |
|
65 | 73 |
|
66 | 74 |
def properties(path, identifier=nil) |
67 | 75 |
scm.properties(path, identifier) |
... | ... | |
92 | 100 |
def latest_changeset |
93 | 101 |
@latest_changeset ||= changesets.find(:first) |
94 | 102 |
end |
103 | ||
104 |
def latest_changesets(rev, path) |
|
105 |
@latest_changesets ||= changesets.find(:all, :limit => 10, :order => "committed_on DESC") |
|
106 |
end |
|
95 | 107 |
|
96 | 108 |
def scan_changesets_for_issue_ids |
97 | 109 |
self.changesets.each(&:scan_comment_for_issue_ids) |
98 | 110 |
end |
99 |
|
|
111 | ||
100 | 112 |
# Returns an array of committers usernames and associated user_id |
101 | 113 |
def committers |
102 | 114 |
@committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") |
app/models/repository/git.rb | ||
---|---|---|
37 | 37 |
end |
38 | 38 | |
39 | 39 |
def fetch_changesets |
40 |
scm_info = scm.info |
|
41 |
if scm_info |
|
42 |
# latest revision found in database |
|
43 |
db_revision = latest_changeset ? latest_changeset.revision : nil |
|
44 |
# latest revision in the repository |
|
45 |
scm_revision = scm_info.lastrev.scmid |
|
40 |
# latest revision found in database |
|
41 |
db_revision = latest_changeset ? latest_changeset.revision : nil |
|
46 | 42 | |
47 |
unless changesets.find_by_scmid(scm_revision) |
|
48 |
scm.revisions('', db_revision, nil, :reverse => true) do |revision| |
|
49 |
if changesets.find_by_scmid(revision.scmid.to_s).nil? |
|
50 |
transaction do |
|
51 |
changeset = Changeset.create!(:repository => self, |
|
52 |
:revision => revision.identifier, |
|
53 |
:scmid => revision.scmid, |
|
54 |
:committer => revision.author, |
|
55 |
:committed_on => revision.time, |
|
56 |
:comments => revision.message) |
|
57 |
|
|
58 |
revision.paths.each do |change| |
|
59 |
Change.create!(:changeset => changeset, |
|
60 |
:action => change[:action], |
|
61 |
:path => change[:path], |
|
62 |
:from_path => change[:from_path], |
|
63 |
:from_revision => change[:from_revision]) |
|
64 |
end |
|
65 |
end |
|
66 |
end |
|
67 |
end |
|
43 |
# latest revision in the repository |
|
44 |
if scm.info.nil? || scm.info.lastrev.nil? |
|
45 |
scm_revision = nil |
|
46 |
else |
|
47 |
scm_revision = scm.info.lastrev.scmid |
|
48 |
end |
|
49 | ||
50 |
unless scm_revision.nil? || changesets.find_by_scmid(scm_revision) |
|
51 |
scm.revisions('', db_revision, nil, :reverse => true).each do |revision| |
|
52 |
revision.save(self) |
|
68 | 53 |
end |
69 | 54 |
end |
70 | 55 |
end |
56 | ||
57 |
def branches |
|
58 |
scm.branches |
|
59 |
end |
|
60 | ||
61 |
def latest_changesets(path,rev) |
|
62 |
@latest_changesets ||= changesets.find( |
|
63 |
:all, |
|
64 |
:conditions => ["scmid IN (?)", scm.repo.log(rev,path, :n => 10).collect{|c| c.id}], |
|
65 |
:order => 'committed_on DESC' |
|
66 |
) |
|
67 |
end |
|
71 | 68 |
end |
app/views/repositories/_breadcrumbs.rhtml | ||
---|---|---|
1 |
<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %> |
|
2 |
<% |
|
3 |
dirs = path.split('/') |
|
4 |
if 'file' == kind |
|
5 |
filename = dirs.pop |
|
6 |
end |
|
7 |
link_path = '' |
|
8 |
dirs.each do |dir| |
|
9 |
next if dir.blank? |
|
10 |
link_path << '/' unless link_path.empty? |
|
11 |
link_path << "#{dir}" |
|
12 |
%> |
|
13 |
/ <%= link_to h(dir), :action => 'show', :id => @project, :path => to_path_param(link_path), :rev => @rev %> |
|
14 |
<% end %> |
|
15 |
<% if filename %> |
|
16 |
/ <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> |
|
17 |
<% end %> |
|
18 | ||
19 |
<%= "@ #{revision}" if revision %> |
|
20 | ||
21 |
<% html_title(with_leading_slash(path)) -%> |
app/views/repositories/_dir_list_content.rhtml | ||
---|---|---|
4 | 4 |
<tr id="<%= tr_id %>" class="<%= params[:parent_id] %> entry <%= entry.kind %>"> |
5 | 5 |
<td style="padding-left: <%=18 * depth%>px;" class="filename"> |
6 | 6 |
<% if entry.is_dir? %> |
7 |
<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},
|
|
7 |
<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},
|
|
8 | 8 |
:method => :get, |
9 | 9 |
:update => { :success => tr_id }, |
10 | 10 |
:position => :after, |
... | ... | |
12 | 12 |
:condition => "scmEntryClick('#{tr_id}')"%>"> </span> |
13 | 13 |
<% end %> |
14 | 14 |
<%= link_to h(entry.name), |
15 |
{:action => (entry.is_dir? ? 'browse' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev},
|
|
15 |
{:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(entry.path), :rev => @rev},
|
|
16 | 16 |
:class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(entry.name)}")%> |
17 | 17 |
</td> |
18 | 18 |
<td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td> |
app/views/repositories/_navigation.rhtml | ||
---|---|---|
1 |
<%= link_to 'root', :action => 'browse', :id => @project, :path => '', :rev => @rev %> |
|
2 |
<% |
|
3 |
dirs = path.split('/') |
|
4 |
if 'file' == kind |
|
5 |
filename = dirs.pop |
|
6 |
end |
|
7 |
link_path = '' |
|
8 |
dirs.each do |dir| |
|
9 |
next if dir.blank? |
|
10 |
link_path << '/' unless link_path.empty? |
|
11 |
link_path << "#{dir}" |
|
12 |
%> |
|
13 |
/ <%= link_to h(dir), :action => 'browse', :id => @project, :path => to_path_param(link_path), :rev => @rev %> |
|
14 |
<% end %> |
|
15 |
<% if filename %> |
|
16 |
/ <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> |
|
17 |
<% end %> |
|
1 |
<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> |
|
18 | 2 | |
19 |
<%= "@ #{revision}" if revision %> |
|
3 |
<% if !@entries.nil? && authorize_for('repositories', 'browse') -%> |
|
4 |
<% form_tag({:action => 'show', :id => @project, :path => @path}, :method => :get, :id => 'revision_selector') do -%> |
|
5 |
<!-- Branches Dropdown --> |
|
6 |
<% if !@repository.branches.nil? -%> |
|
7 |
| |
|
8 |
<% content_for :header_tags do %> |
|
9 |
<%= javascript_include_tag 'repository_navigation' %> |
|
10 |
<% end %> |
|
20 | 11 | |
21 |
<% html_title(with_leading_slash(path)) -%> |
|
12 |
<%= l(:label_branch) %>: |
|
13 |
<%= select_tag :rev, options_for_select(@repository.branches.map{|b| b.name},@branch), :id => 'branch' %> |
|
14 |
<% end -%> |
|
15 | ||
16 |
| <%= l(:label_revision) %>: |
|
17 |
<%= text_field_tag 'rev', @rev, :size => 8 %> |
|
18 |
<% end -%> |
|
19 |
<% end -%> |
app/views/repositories/browse.rhtml | ||
---|---|---|
1 | 1 |
<div class="contextual"> |
2 |
<% form_tag({}, :method => :get) do %> |
|
3 |
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %> |
|
4 |
<% end %> |
|
2 |
<%= render :partial => 'navigation' %> |
|
5 | 3 |
</div> |
6 | 4 | |
7 |
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
|
|
5 |
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
|
|
8 | 6 | |
9 | 7 |
<%= render :partial => 'dir_list' %> |
10 | 8 |
<%= render_properties(@properties) %> |
app/views/repositories/changes.rhtml | ||
---|---|---|
1 |
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2>
|
|
1 |
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2>
|
|
2 | 2 | |
3 | 3 |
<p><%= render :partial => 'link_to_functions' %></p> |
4 | 4 |
app/views/repositories/entry.rhtml | ||
---|---|---|
1 |
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
|
|
1 |
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
|
|
2 | 2 | |
3 | 3 |
<p><%= render :partial => 'link_to_functions' %></p> |
4 | 4 |
app/views/repositories/revision.rhtml | ||
---|---|---|
14 | 14 |
» |
15 | 15 | |
16 | 16 |
<% form_tag({:controller => 'repositories', :action => 'revision', :id => @project, :rev => nil}, :method => :get) do %> |
17 |
<%= text_field_tag 'rev', @rev, :size => 5 %>
|
|
17 |
<%= text_field_tag 'rev', @rev[0,8], :size => 8 %>
|
|
18 | 18 |
<%= submit_tag 'OK', :name => nil %> |
19 | 19 |
<% end %> |
20 | 20 |
</div> |
app/views/repositories/revisions.rhtml | ||
---|---|---|
1 | 1 |
<div class="contextual"> |
2 | 2 |
<% form_tag({:action => 'revision', :id => @project}) do %> |
3 |
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
|
|
3 |
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %>
|
|
4 | 4 |
<%= submit_tag 'OK' %> |
5 | 5 |
<% end %> |
6 | 6 |
</div> |
app/views/repositories/show.rhtml | ||
---|---|---|
1 |
<div class="contextual"> |
|
2 | 1 |
<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> |
3 |
<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> |
|
4 | 2 | |
5 |
<% if !@entries.nil? && authorize_for('repositories', 'browse') -%> |
|
6 |
<% form_tag({:action => 'browse', :id => @project}, :method => :get) do -%> |
|
7 |
| <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %> |
|
8 |
<% end -%> |
|
9 |
<% end -%> |
|
3 |
<div class="contextual"> |
|
4 |
<%= render :partial => 'navigation' %> |
|
10 | 5 |
</div> |
11 | 6 | |
12 |
<h2><%= l(:label_repository) %> (<%= @repository.scm_name %>)</h2>
|
|
7 |
<h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
|
|
13 | 8 | |
14 | 9 |
<% if !@entries.nil? && authorize_for('repositories', 'browse') %> |
15 | 10 |
<%= render :partial => 'dir_list' %> |
config/locales/en.yml | ||
---|---|---|
543 | 543 |
label_browse: Browse |
544 | 544 |
label_modification: "{{count}} change" |
545 | 545 |
label_modification_plural: "{{count}} changes" |
546 |
label_branch: Branch |
|
546 | 547 |
label_revision: Revision |
547 | 548 |
label_revision_plural: Revisions |
548 | 549 |
label_associated_revisions: Associated revisions |
config/routes.rb | ||
---|---|---|
218 | 218 |
repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision' |
219 | 219 |
repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff' |
220 | 220 |
repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff' |
221 |
repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path' |
|
221 |
repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9.]+/ }
|
|
222 | 222 |
repository_views.connect 'projects/:id/repository/:action/*path' |
223 | 223 |
end |
224 | 224 |
|
lib/diff.rb | ||
---|---|---|
1 |
class Diff |
|
1 |
module RedmineDiff |
|
2 |
class Diff |
|
2 | 3 | |
3 |
VERSION = 0.3 |
|
4 |
VERSION = 0.3
|
|
4 | 5 | |
5 |
def Diff.lcs(a, b) |
|
6 |
astart = 0 |
|
7 |
bstart = 0 |
|
8 |
afinish = a.length-1 |
|
9 |
bfinish = b.length-1 |
|
10 |
mvector = [] |
|
11 |
|
|
12 |
# First we prune off any common elements at the beginning |
|
13 |
while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart]) |
|
14 |
mvector[astart] = bstart |
|
15 |
astart += 1 |
|
16 |
bstart += 1 |
|
17 |
end |
|
18 |
|
|
19 |
# now the end |
|
20 |
while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish]) |
|
21 |
mvector[afinish] = bfinish |
|
22 |
afinish -= 1 |
|
23 |
bfinish -= 1 |
|
24 |
end |
|
6 |
def Diff.lcs(a, b)
|
|
7 |
astart = 0
|
|
8 |
bstart = 0
|
|
9 |
afinish = a.length-1
|
|
10 |
bfinish = b.length-1
|
|
11 |
mvector = []
|
|
12 |
|
|
13 |
# First we prune off any common elements at the beginning
|
|
14 |
while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart])
|
|
15 |
mvector[astart] = bstart
|
|
16 |
astart += 1
|
|
17 |
bstart += 1
|
|
18 |
end
|
|
19 |
|
|
20 |
# now the end
|
|
21 |
while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish])
|
|
22 |
mvector[afinish] = bfinish
|
|
23 |
afinish -= 1
|
|
24 |
bfinish -= 1
|
|
25 |
end
|
|
25 | 26 | |
26 |
bmatches = b.reverse_hash(bstart..bfinish) |
|
27 |
thresh = [] |
|
28 |
links = [] |
|
29 |
|
|
30 |
(astart..afinish).each { |aindex| |
|
31 |
aelem = a[aindex] |
|
32 |
next unless bmatches.has_key? aelem |
|
33 |
k = nil |
|
34 |
bmatches[aelem].reverse.each { |bindex| |
|
35 |
if k && (thresh[k] > bindex) && (thresh[k-1] < bindex) |
|
36 |
thresh[k] = bindex |
|
37 |
else |
|
38 |
k = thresh.replacenextlarger(bindex, k) |
|
39 |
end |
|
40 |
links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k |
|
27 |
bmatches = b.reverse_hash(bstart..bfinish) |
|
28 |
thresh = [] |
|
29 |
links = [] |
|
30 |
|
|
31 |
(astart..afinish).each { |aindex| |
|
32 |
aelem = a[aindex] |
|
33 |
next unless bmatches.has_key? aelem |
|
34 |
k = nil |
|
35 |
bmatches[aelem].reverse.each { |bindex| |
|
36 |
if k && (thresh[k] > bindex) && (thresh[k-1] < bindex) |
|
37 |
thresh[k] = bindex |
|
38 |
else |
|
39 |
k = thresh.replacenextlarger(bindex, k) |
|
40 |
end |
|
41 |
links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k |
|
42 |
} |
|
41 | 43 |
} |
42 |
} |
|
43 | 44 | |
44 |
if !thresh.empty? |
|
45 |
link = links[thresh.length-1] |
|
46 |
while link |
|
47 |
mvector[link[1]] = link[2] |
|
48 |
link = link[0] |
|
45 |
if !thresh.empty? |
|
46 |
link = links[thresh.length-1] |
|
47 |
while link |
|
48 |
mvector[link[1]] = link[2] |
|
49 |
link = link[0] |
|
50 |
end |
|
49 | 51 |
end |
50 |
end |
|
51 | 52 | |
52 |
return mvector |
|
53 |
end |
|
54 | ||
55 |
def makediff(a, b) |
|
56 |
mvector = Diff.lcs(a, b) |
|
57 |
ai = bi = 0 |
|
58 |
while ai < mvector.length |
|
59 |
bline = mvector[ai] |
|
60 |
if bline |
|
61 |
while bi < bline |
|
62 |
discardb(bi, b[bi]) |
|
63 |
bi += 1 |
|
64 |
end |
|
65 |
match(ai, bi) |
|
66 |
bi += 1 |
|
67 |
else |
|
68 |
discarda(ai, a[ai]) |
|
69 |
end |
|
70 |
ai += 1 |
|
71 |
end |
|
72 |
while ai < a.length |
|
73 |
discarda(ai, a[ai]) |
|
74 |
ai += 1 |
|
53 |
return mvector |
|
75 | 54 |
end |
76 |
while bi < b.length |
|
55 | ||
56 |
def makediff(a, b) |
|
57 |
mvector = Diff.lcs(a, b) |
|
58 |
ai = bi = 0 |
|
59 |
while ai < mvector.length |
|
60 |
bline = mvector[ai] |
|
61 |
if bline |
|
62 |
while bi < bline |
|
77 | 63 |
discardb(bi, b[bi]) |
78 | 64 |
bi += 1 |
79 | 65 |
end |
80 | 66 |
match(ai, bi) |
81 |
1 |
|
82 |
end |
|
83 | ||
84 |
def compactdiffs |
|
85 |
diffs = [] |
|
86 |
@diffs.each { |df| |
|
87 |
i = 0 |
|
88 |
curdiff = [] |
|
89 |
while i < df.length |
|
90 |
whot = df[i][0] |
|
91 |
s = @isstring ? df[i][2].chr : [df[i][2]] |
|
92 |
p = df[i][1] |
|
93 |
last = df[i][1] |
|
94 |
i += 1 |
|
95 |
while df[i] && df[i][0] == whot && df[i][1] == last+1 |
|
96 |
s << df[i][2] |
|
97 |
last = df[i][1] |
|
98 |
i += 1 |
|
99 |
end |
|
100 |
curdiff.push [whot, p, s] |
|
67 |
bi += 1 |
|
68 |
else |
|
69 |
discarda(ai, a[ai]) |
|
70 |
end |
|
71 |
ai += 1 |
|
101 | 72 |
end |
102 |
diffs.push curdiff |
|
103 |
} |
|
104 |
return diffs |
|
105 |
end |
|
73 |
while ai < a.length |
|
74 |
discarda(ai, a[ai]) |
|
75 |
ai += 1 |
|
76 |
end |
|
77 |
while bi < b.length |
|
78 |
discardb(bi, b[bi]) |
|
79 |
bi += 1 |
|
80 |
end |
|
81 |
match(ai, bi) |
|
82 |
1 |
|
83 |
end |
|
106 | 84 | |
107 |
attr_reader :diffs, :difftype |
|
85 |
def compactdiffs |
|
86 |
diffs = [] |
|
87 |
@diffs.each { |df| |
|
88 |
i = 0 |
|
89 |
curdiff = [] |
|
90 |
while i < df.length |
|
91 |
whot = df[i][0] |
|
92 |
s = @isstring ? df[i][2].chr : [df[i][2]] |
|
93 |
p = df[i][1] |
|
94 |
last = df[i][1] |
|
95 |
i += 1 |
|
96 |
while df[i] && df[i][0] == whot && df[i][1] == last+1 |
|
97 |
s << df[i][2] |
|
98 |
last = df[i][1] |
|
99 |
i += 1 |
|
100 |
end |
|
101 |
curdiff.push [whot, p, s] |
|
102 |
end |
|
103 |
diffs.push curdiff |
|
104 |
} |
|
105 |
return diffs |
|
106 |
end |
|
108 | 107 | |
109 |
def initialize(diffs_or_a, b = nil, isstring = nil) |
|
110 |
if b.nil? |
|
111 |
@diffs = diffs_or_a |
|
112 |
@isstring = isstring |
|
113 |
else |
|
114 |
@diffs = [] |
|
108 |
attr_reader :diffs, :difftype |
|
109 | ||
110 |
def initialize(diffs_or_a, b = nil, isstring = nil) |
|
111 |
if b.nil? |
|
112 |
@diffs = diffs_or_a |
|
113 |
@isstring = isstring |
|
114 |
else |
|
115 |
@diffs = [] |
|
116 |
@curdiffs = [] |
|
117 |
makediff(diffs_or_a, b) |
|
118 |
@difftype = diffs_or_a.class |
|
119 |
end |
|
120 |
end |
|
121 |
|
|
122 |
def match(ai, bi) |
|
123 |
@diffs.push @curdiffs unless @curdiffs.empty? |
|
115 | 124 |
@curdiffs = [] |
116 |
makediff(diffs_or_a, b) |
|
117 |
@difftype = diffs_or_a.class |
|
118 | 125 |
end |
119 |
end |
|
120 |
|
|
121 |
def match(ai, bi) |
|
122 |
@diffs.push @curdiffs unless @curdiffs.empty? |
|
123 |
@curdiffs = [] |
|
124 |
end |
|
125 | 126 | |
126 |
def discarda(i, elem) |
|
127 |
@curdiffs.push ['-', i, elem] |
|
128 |
end |
|
127 |
def discarda(i, elem)
|
|
128 |
@curdiffs.push ['-', i, elem]
|
|
129 |
end
|
|
129 | 130 | |
130 |
def discardb(i, elem) |
|
131 |
@curdiffs.push ['+', i, elem] |
|
132 |
end |
|
131 |
def discardb(i, elem)
|
|
132 |
@curdiffs.push ['+', i, elem]
|
|
133 |
end
|
|
133 | 134 | |
134 |
def compact |
|
135 |
return Diff.new(compactdiffs) |
|
136 |
end |
|
135 |
def compact
|
|
136 |
return Diff.new(compactdiffs)
|
|
137 |
end
|
|
137 | 138 | |
138 |
def compact! |
|
139 |
@diffs = compactdiffs |
|
140 |
end |
|
139 |
def compact!
|
|
140 |
@diffs = compactdiffs
|
|
141 |
end
|
|
141 | 142 | |
142 |
def inspect |
|
143 |
@diffs.inspect |
|
144 |
end |
|
143 |
def inspect
|
|
144 |
@diffs.inspect
|
|
145 |
end
|
|
145 | 146 | |
147 |
end |
|
146 | 148 |
end |
147 | 149 | |
148 | 150 |
module Diffable |
149 | 151 |
def diff(b) |
150 |
Diff.new(self, b) |
|
152 |
RedmineDiff::Diff.new(self, b)
|
|
151 | 153 |
end |
152 | 154 | |
153 | 155 |
# Create a hash that maps elements of the array to arrays of indices |
... | ... | |
158 | 160 |
range.each { |i| |
159 | 161 |
elem = self[i] |
160 | 162 |
if revmap.has_key? elem |
161 |
revmap[elem].push i
|
|
163 |
revmap[elem].push i
|
|
162 | 164 |
else |
163 |
revmap[elem] = [i]
|
|
165 |
revmap[elem] = [i]
|
|
164 | 166 |
end |
165 | 167 |
} |
166 | 168 |
return revmap |
... | ... | |
179 | 181 |
found = self[index] |
180 | 182 |
return nil if value == found |
181 | 183 |
if value > found |
182 |
low = index + 1
|
|
184 |
low = index + 1
|
|
183 | 185 |
else |
184 |
high = index
|
|
186 |
high = index
|
|
185 | 187 |
end |
186 | 188 |
end |
187 | 189 | |
... | ... | |
204 | 206 |
bi = 0 |
205 | 207 |
diff.diffs.each { |d| |
206 | 208 |
d.each { |mod| |
207 |
case mod[0]
|
|
208 |
when '-'
|
|
209 |
while ai < mod[1]
|
|
210 |
newary << self[ai]
|
|
211 |
ai += 1
|
|
212 |
bi += 1
|
|
213 |
end
|
|
214 |
ai += 1
|
|
215 |
when '+'
|
|
216 |
while bi < mod[1]
|
|
217 |
newary << self[ai]
|
|
218 |
ai += 1
|
|
219 |
bi += 1
|
|
220 |
end
|
|
221 |
newary << mod[2]
|
|
222 |
bi += 1
|
|
223 |
else
|
|
224 |
raise "Unknown diff action"
|
|
225 |
end
|
|
209 |
case mod[0]
|
|
210 |
when '-'
|
|
211 |
while ai < mod[1]
|
|
212 |
newary << self[ai]
|
|
213 |
ai += 1
|
|
214 |
bi += 1
|
|
215 |
end
|
|
216 |
ai += 1
|
|
217 |
when '+'
|
|
218 |
while bi < mod[1]
|
|
219 |
newary << self[ai]
|
|
220 |
ai += 1
|
|
221 |
bi += 1
|
|
222 |
end
|
|
223 |
newary << mod[2]
|
|
224 |
bi += 1
|
|
225 |
else
|
|
226 |
raise "Unknown diff action"
|
|
227 |
end
|
|
226 | 228 |
} |
227 | 229 |
} |
228 | 230 |
while ai < self.length |
... | ... | |
243 | 245 |
end |
244 | 246 | |
245 | 247 |
=begin |
246 |
= Diff |
|
247 |
(({diff.rb})) - computes the differences between two arrays or |
|
248 |
strings. Copyright (C) 2001 Lars Christensen |
|
248 |
= Diff
|
|
249 |
(({diff.rb})) - computes the differences between two arrays or
|
|
250 |
strings. Copyright (C) 2001 Lars Christensen
|
|
249 | 251 | |
250 |
== Synopsis |
|
252 |
== Synopsis
|
|
251 | 253 | |
252 |
diff = Diff.new(a, b) |
|
253 |
b = a.patch(diff) |
|
254 |
diff = Diff.new(a, b)
|
|
255 |
b = a.patch(diff)
|
|
254 | 256 | |
255 |
== Class Diff |
|
256 |
=== Class Methods |
|
257 |
--- Diff.new(a, b) |
|
258 |
--- a.diff(b) |
|
259 |
Creates a Diff object which represent the differences between |
|
260 |
((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays |
|
261 |
of any objects, strings, or object of any class that include |
|
262 |
module ((|Diffable|)) |
|
257 |
== Class Diff
|
|
258 |
=== Class Methods
|
|
259 |
--- Diff.new(a, b)
|
|
260 |
--- a.diff(b)
|
|
261 |
Creates a Diff object which represent the differences between
|
|
262 |
((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays
|
|
263 |
of any objects, strings, or object of any class that include
|
|
264 |
module ((|Diffable|))
|
|
263 | 265 | |
264 |
== Module Diffable |
|
265 |
The module ((|Diffable|)) is intended to be included in any class for |
|
266 |
which differences are to be computed. Diffable is included into String |
|
267 |
and Array when (({diff.rb})) is (({require}))'d. |
|
266 |
== Module Diffable
|
|
267 |
The module ((|Diffable|)) is intended to be included in any class for
|
|
268 |
which differences are to be computed. Diffable is included into String
|
|
269 |
and Array when (({diff.rb})) is (({require}))'d.
|
|
268 | 270 | |
269 |
Classes including Diffable should implement (({[]})) to get element at |
|
270 |
integer indices, (({<<})) to append elements to the object and |
|
271 |
(({ClassName#new})) should accept 0 arguments to create a new empty |
|
272 |
object. |
|
271 |
Classes including Diffable should implement (({[]})) to get element at
|
|
272 |
integer indices, (({<<})) to append elements to the object and
|
|
273 |
(({ClassName#new})) should accept 0 arguments to create a new empty
|
|
274 |
object.
|
|
273 | 275 | |
274 |
=== Instance Methods |
|
275 |
--- Diffable#patch(diff) |
|
276 |
Applies the differences from ((|diff|)) to the object ((|obj|)) |
|
277 |
and return the result. ((|obj|)) is not changed. ((|obj|)) and |
|
278 |
can be either an array or a string, but must match the object |
|
279 |
from which the ((|diff|)) was created. |
|
276 |
=== Instance Methods
|
|
277 |
--- Diffable#patch(diff)
|
|
278 |
Applies the differences from ((|diff|)) to the object ((|obj|))
|
|
279 |
and return the result. ((|obj|)) is not changed. ((|obj|)) and
|
|
280 |
can be either an array or a string, but must match the object
|
|
281 |
from which the ((|diff|)) was created.
|
|
280 | 282 |
=end |
lib/redmine/scm/adapters/abstract_adapter.rb | ||
---|---|---|
100 | 100 |
def entries(path=nil, identifier=nil) |
101 | 101 |
return nil |
102 | 102 |
end |
103 | ||
104 |
def branches |
|
105 |
return nil |
|
106 |
end |
|
107 | ||
108 |
def default_branch |
|
109 |
return nil |
|
110 |
end |
|
103 | 111 |
|
104 | 112 |
def properties(path, identifier=nil) |
105 | 113 |
return nil |
... | ... | |
260 | 268 |
|
261 | 269 |
class Revision |
262 | 270 |
attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch |
271 | ||
263 | 272 |
def initialize(attributes={}) |
264 | 273 |
self.identifier = attributes[:identifier] |
265 | 274 |
self.scmid = attributes[:scmid] |
... | ... | |
271 | 280 |
self.revision = attributes[:revision] |
272 | 281 |
self.branch = attributes[:branch] |
273 | 282 |
end |
274 |
|
|
283 | ||
284 |
def save(repo) |
|
285 |
if repo.changesets.find_by_scmid(scmid.to_s).nil? |
|
286 |
changeset = Changeset.create!( |
|
287 |
:repository => repo, |
|
288 |
:revision => identifier, |
|
289 |
:scmid => scmid, |
|
290 |
:committer => author, |
|
291 |
:committed_on => time, |
|
292 |
:comments => message) |
|
293 | ||
294 |
paths.each do |file| |
|
295 |
Change.create!( |
|
296 |
:changeset => changeset, |
|
297 |
:action => file[:action], |
|
298 |
:path => file[:path]) |
|
299 |
end |
|
300 |
end |
|
301 |
end |
|
275 | 302 |
end |
276 | 303 |
|
277 | 304 |
class Annotate |
lib/redmine/scm/adapters/git_adapter.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 | |
18 | 18 |
require 'redmine/scm/adapters/abstract_adapter' |
19 |
require 'grit' |
|
20 | ||
21 | ||
19 | 22 | |
20 | 23 |
module Redmine |
21 | 24 |
module Scm |
22 | 25 |
module Adapters |
23 | 26 |
class GitAdapter < AbstractAdapter |
24 |
|
|
27 |
attr_accessor :repo |
|
28 | ||
25 | 29 |
# Git executable name |
26 | 30 |
GIT_BIN = "git" |
27 | 31 | |
28 |
# Get the revision of a particuliar file |
|
29 |
def get_rev (rev,path) |
|
30 |
|
|
31 |
if rev != 'latest' && !rev.nil? |
|
32 |
cmd="#{GIT_BIN} --git-dir #{target('')} show --date=iso --pretty=fuller #{shell_quote rev} -- #{shell_quote path}" |
|
33 |
else |
|
34 |
@branch ||= shellout("#{GIT_BIN} --git-dir #{target('')} branch") { |io| io.grep(/\*/)[0].strip.match(/\* (.*)/)[1] } |
|
35 |
cmd="#{GIT_BIN} --git-dir #{target('')} log --date=iso --pretty=fuller -1 #{@branch} -- #{shell_quote path}" |
|
36 |
end |
|
37 |
rev=[] |
|
38 |
i=0 |
|
39 |
shellout(cmd) do |io| |
|
40 |
files=[] |
|
41 |
changeset = {} |
|
42 |
parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files |
|
43 | ||
44 |
io.each_line do |line| |
|
45 |
if line =~ /^commit ([0-9a-f]{40})$/ |
|
46 |
key = "commit" |
|
47 |
value = $1 |
|
48 |
if (parsing_descr == 1 || parsing_descr == 2) |
|
49 |
parsing_descr = 0 |
|
50 |
rev = Revision.new({:identifier => changeset[:commit], |
|
51 |
:scmid => changeset[:commit], |
|
52 |
:author => changeset[:author], |
|
53 |
:time => Time.parse(changeset[:date]), |
|
54 |
:message => changeset[:description], |
|
55 |
:paths => files |
|
56 |
}) |
|
57 |
changeset = {} |
|
58 |
files = [] |
|
59 |
end |
|
60 |
changeset[:commit] = $1 |
|
61 |
elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ |
|
62 |
key = $1 |
|
63 |
value = $2 |
|
64 |
if key == "Author" |
|
65 |
changeset[:author] = value |
|
66 |
elsif key == "CommitDate" |
|
67 |
changeset[:date] = value |
|
68 |
end |
|
69 |
elsif (parsing_descr == 0) && line.chomp.to_s == "" |
|
70 |
parsing_descr = 1 |
|
71 |
changeset[:description] = "" |
|
72 |
elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/ |
|
73 |
parsing_descr = 2 |
|
74 |
fileaction = $1 |
|
75 |
filepath = $2 |
|
76 |
files << {:action => fileaction, :path => filepath} |
|
77 |
elsif (parsing_descr == 1) && line.chomp.to_s == "" |
|
78 |
parsing_descr = 2 |
|
79 |
elsif (parsing_descr == 1) |
|
80 |
changeset[:description] << line |
|
81 |
end |
|
82 |
end |
|
83 |
rev = Revision.new({:identifier => changeset[:commit], |
|
84 |
:scmid => changeset[:commit], |
|
85 |
:author => changeset[:author], |
|
86 |
:time => (changeset[:date] ? Time.parse(changeset[:date]) : nil), |
|
87 |
:message => changeset[:description], |
|
88 |
:paths => files |
|
89 |
}) |
|
32 |
def initialize(*args) |
|
33 |
args[1] = args[0] |
|
34 |
super(*args) |
|
90 | 35 | |
36 |
begin |
|
37 |
@repo = Grit::Repo.new(url, :is_bare => true) |
|
38 |
rescue |
|
39 |
Rails::logger.error "Repository could not be created" |
|
91 | 40 |
end |
41 |
end |
|
92 | 42 | |
93 |
get_rev('latest',path) if rev == [] |
|
43 |
def info |
|
44 |
begin |
|
45 |
Info.new(:root_url => url, :lastrev => @repo.log('all', nil, :n => 1).first.to_revision) |
|
46 |
rescue |
|
47 |
nil |
|
48 |
end |
|
49 |
end |
|
94 | 50 | |
95 |
return nil if $? && $?.exitstatus != 0
|
|
96 |
return rev
|
|
51 |
def branches
|
|
52 |
@repo.branches
|
|
97 | 53 |
end |
98 | 54 | |
99 |
def info |
|
100 |
revs = revisions(url,nil,nil,{:limit => 1}) |
|
101 |
if revs && revs.any? |
|
102 |
Info.new(:root_url => url, :lastrev => revs.first) |
|
103 |
else |
|
55 |
def default_branch |
|
56 |
begin |
|
57 |
@repo.default_branch |
|
58 |
rescue |
|
104 | 59 |
nil |
105 | 60 |
end |
106 |
rescue Errno::ENOENT => e |
|
107 |
return nil |
|
108 | 61 |
end |
109 | 62 |
|
110 | 63 |
def entries(path=nil, identifier=nil) |
111 |
path ||= '' |
|
64 |
return nil if repo.nil? |
|
65 |
path = nil if path.empty? |
|
66 | ||
112 | 67 |
entries = Entries.new |
113 |
cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l " |
|
114 |
cmd << shell_quote("HEAD:" + path) if identifier.nil? |
|
115 |
cmd << shell_quote(identifier + ":" + path) if identifier |
|
116 |
shellout(cmd) do |io| |
|
117 |
io.each_line do |line| |
|
118 |
e = line.chomp.to_s |
|
119 |
if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/ |
|
120 |
type = $1 |
|
121 |
sha = $2 |
|
122 |
size = $3 |
|
123 |
name = $4 |
|
124 |
entries << Entry.new({:name => name, |
|
125 |
:path => (path.empty? ? name : "#{path}/#{name}"), |
|
126 |
:kind => ((type == "tree") ? 'dir' : 'file'), |
|
127 |
:size => ((type == "tree") ? nil : size), |
|
128 |
:lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}")) |
|
129 |
|
|
130 |
}) unless entries.detect{|entry| entry.name == name} |
|
131 |
end |
|
132 |
end |
|
68 |
|
|
69 |
tree = repo.log(identifier, path, :n => 1).first.tree |
|
70 |
tree = tree / path if path |
|
71 | ||
72 |
tree.contents.each do |file| |
|
73 |
file_path = path ? "#{path}/#{file.name}" : file.name |
|
74 |
commit = repo.log(identifier, file_path, :n => 1).first |
|
75 | ||
76 |
entries << Entry.new({ |
|
77 |
:name => file.name, |
|
78 |
:path => file_path, |
|
79 |
:kind => file.class == Grit::Blob ? 'file' : 'dir', |
|
80 |
:size => file.respond_to?('size') ? file.size : nil, |
|
81 |
:lastrev => commit.to_revision |
|
82 |
}) |
|
133 | 83 |
end |
134 |
return nil if $? && $?.exitstatus != 0 |
|
84 | ||
135 | 85 |
entries.sort_by_name |
136 | 86 |
end |
137 |
|
|
87 | ||
138 | 88 |
def revisions(path, identifier_from, identifier_to, options={}) |
139 | 89 |
revisions = Revisions.new |
140 |
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
|
|
90 |
cmd = "#{GIT_BIN} --git-dir #{target('')} log -M -C --all --raw --date=iso --pretty=fuller --no-merges"
|
|
141 | 91 |
cmd << " --reverse" if options[:reverse] |
142 | 92 |
cmd << " -n #{options[:limit].to_i} " if (!options.nil?) && options[:limit] |
143 | 93 |
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from |
... | ... | |
192 | 142 |
elsif (parsing_descr == 1) |
193 | 143 |
changeset[:description] << line[4..-1] |
194 | 144 |
end |
195 |
end
|
|
145 |
end
|
|
196 | 146 | |
197 | 147 |
if changeset[:commit] |
198 | 148 |
revision = Revision.new({:identifier => changeset[:commit], |
... | ... | |
213 | 163 |
return nil if $? && $?.exitstatus != 0 |
214 | 164 |
revisions |
215 | 165 |
end |
216 |
|
|
166 | ||
217 | 167 |
def diff(path, identifier_from, identifier_to=nil) |
218 | 168 |
path ||= '' |
219 | 169 |
if !identifier_to |
... | ... | |
265 | 215 |
end |
266 | 216 |
end |
267 | 217 |
end |
268 | ||
269 | 218 |
end |
270 | 219 | |
220 |
module Grit |
|
221 |
class Repo |
|
222 |
def log(commit = 'all', path = nil, options = {}) |
|
223 |
default_options = {:pretty => "raw", "no-merges" => true} |
|
224 |
commit = default_branch if commit.nil? |
|
225 | ||
226 |
if commit == 'all' |
|
227 |
commit = default_branch |
|
228 |
default_options.merge!(:all => true) |
|
229 |
end |
|
230 | ||
231 |
actual_options = default_options.merge(options) |
|
232 |
arg = path ? [commit, '--', path] : [commit] |
|
233 |
commits = self.git.log(actual_options, *arg) |
|
234 |
Commit.list_from_string(self, commits) |
|
235 |
end |
|
236 | ||
237 |
def default_branch |
|
238 |
if branches.map{|h| h.name}.include?('master') |
|
239 |
'master' |
|
240 |
else |
|
241 |
branches.first.name |
|
242 |
end |
|
243 |
end |
|
244 |
end |
|
245 | ||
246 |
class Diff |
|
247 |
def action |
|
248 |
return 'A' if new_file |
|
249 |
return 'D' if deleted_file |
|
250 |
return 'M' |
|
251 |
end |
|
252 | ||
253 |
def path |
|
254 |
return a_path if a_path |
|
255 |
return b_path if b_path |
|
256 |
end |
|
257 |
end |
|
258 | ||
259 |
class Commit |
|
260 |
def to_revision |
|
261 |
Redmine::Scm::Adapters::Revision.new({ |
|
262 |
:identifier => id, |
|
263 |
:scmid => id, |
|
264 |
:author => "#{author.name} <#{author.email}>", |
|
265 |
:time => committed_date, |
|
266 |
:message => message |
|
267 |
}) |
|
268 |
end |
|
269 |
end |
|
270 |
end |
public/javascripts/repository_navigation.js | ||
---|---|---|
1 |
Event.observe(window,'load',function() { |
|
2 |
/* |
|
3 |
If we're viewing a named branch, don't display it in the |
|
4 |
revision box |
|
5 |
*/ |
|
6 |
if ($('rev').getValue() == $('branch').getValue()) { |
|
7 |
$('rev').setValue(''); |
|
8 |
} |
|
9 | ||
10 |
/* |
|
11 |
Temporarily disable the revision box if the branch drop-down |
|
12 |
is changed since both fields are named 'rev' |
|
13 |
*/ |
|
14 |
$('branch').observe('change',function(e) { |
|
15 |
$('rev').disable(); |
|
16 |
e.element().parentNode.submit(); |
|
17 |
$('rev').enable(); |
|
18 |
}) |
|
19 | ||
20 |
/* |
|
21 |
Temporarily disable the branch drop-down if 'Enter' is pressed |
|
22 |
in the revision box since both fields are named 'rev' |
|
23 |
*/ |
|
24 |
$('rev').observe('keydown',function(e) { |
|
25 |
if (e.keyCode == 13) { |
|
26 |
$('branch').disable(); |
|
27 |
e.element().parentNode.submit(); |
|
28 |
$('branch').enable(); |
|
29 |
} |
|
30 |
}) |
|
31 |
}) |
public/stylesheets/application.css | ||
---|---|---|
176 | 176 |
width: .6em; height: .6em; |
177 | 177 |
} |
178 | 178 |
.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} |
179 |
.contextual input {font-size:0.9em;} |
|
179 |
.contextual input,select {font-size:0.9em;}
|
|
180 | 180 |
.message .contextual { margin-top: 0; } |
181 | 181 | |
182 | 182 |
.splitcontentleft{float:left; width:49%;} |
test/functional/repositories_bazaar_controller_test.rb | ||
---|---|---|
45 | 45 |
end |
46 | 46 |
|
47 | 47 |
def test_browse_root |
48 |
get :browse, :id => 3
|
|
48 |
get :show, :id => 3
|
|
49 | 49 |
assert_response :success |
50 |
assert_template 'browse'
|
|
50 |
assert_template 'show'
|
|
51 | 51 |
assert_not_nil assigns(:entries) |
52 | 52 |
assert_equal 2, assigns(:entries).size |
53 | 53 |
assert assigns(:entries).detect {|e| e.name == 'directory' && e.kind == 'dir'} |
... | ... | |
55 | 55 |
end |
56 | 56 |
|
57 | 57 |
def test_browse_directory |
58 |
get :browse, :id => 3, :path => ['directory']
|
|
58 |
get :show, :id => 3, :path => ['directory']
|
|
59 | 59 |
assert_response :success |
60 |
assert_template 'browse'
|
|
60 |
assert_template 'show'
|
|
61 | 61 |
assert_not_nil assigns(:entries) |
62 | 62 |
assert_equal ['doc-ls.txt', 'document.txt', 'edit.png'], assigns(:entries).collect(&:name) |
63 | 63 |
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} |
... | ... | |
67 | 67 |
end |
68 | 68 |
|
69 | 69 |
def test_browse_at_given_revision |
70 |
get :browse, :id => 3, :path => [], :rev => 3
|
|
70 |
get :show, :id => 3, :path => [], :rev => 3
|
|
71 | 71 |
assert_response :success |
72 |
assert_template 'browse'
|
|
72 |
assert_template 'show'
|
|
73 | 73 |
assert_not_nil assigns(:entries) |
74 | 74 |
assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], assigns(:entries).collect(&:name) |
75 | 75 |
end |
... | ... | |
102 | 102 |
def test_directory_entry |
103 | 103 |
get :entry, :id => 3, :path => ['directory'] |
104 | 104 |
assert_response :success |
105 |
assert_template 'browse'
|
|
105 |
assert_template 'show'
|
|
106 | 106 |
assert_not_nil assigns(:entry) |
107 | 107 |
assert_equal 'directory', assigns(:entry).name |
108 | 108 |
end |
test/functional/repositories_cvs_controller_test.rb | ||
---|---|---|
51 | 51 |
end |
52 | 52 |
|
53 | 53 |
def test_browse_root |
54 |
get :browse, :id => 1
|
|
54 |
get :show, :id => 1
|
|
55 | 55 |
assert_response :success |
56 |
assert_template 'browse'
|
|
56 |
assert_template 'show'
|
|
57 | 57 |
assert_not_nil assigns(:entries) |
58 | 58 |
assert_equal 3, assigns(:entries).size |
59 | 59 |
|
... | ... | |
65 | 65 |
end |
66 | 66 |
|
67 | 67 |
def test_browse_directory |
68 |
get :browse, :id => 1, :path => ['images']
|
|
68 |
get :show, :id => 1, :path => ['images']
|
|
69 | 69 |
assert_response :success |
70 |
assert_template 'browse'
|
|
70 |
assert_template 'show'
|
|
71 | 71 |
assert_not_nil assigns(:entries) |
72 | 72 |
assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name) |
73 | 73 |
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} |
... | ... | |
78 | 78 |
|
79 | 79 |
def test_browse_at_given_revision |
80 | 80 |
Project.find(1).repository.fetch_changesets |
81 |
get :browse, :id => 1, :path => ['images'], :rev => 1
|
|
81 |
get :show, :id => 1, :path => ['images'], :rev => 1
|
|
82 | 82 |
assert_response :success |
83 |
assert_template 'browse'
|
|
83 |
assert_template 'show'
|
|
84 | 84 |
assert_not_nil assigns(:entries) |
85 | 85 |
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) |
86 | 86 |
end |
... | ... | |
118 | 118 |
def test_directory_entry |
119 | 119 |
get :entry, :id => 1, :path => ['sources'] |
120 | 120 |
assert_response :success |
121 |
assert_template 'browse'
|
|
121 |
assert_template 'show'
|
|
122 | 122 |
assert_not_nil assigns(:entry) |
123 | 123 |
assert_equal 'sources', assigns(:entry).name |
124 | 124 |
end |
test/functional/repositories_darcs_controller_test.rb | ||
---|---|---|
45 | 45 |
end |
46 | 46 |
|
47 | 47 |
def test_browse_root |
48 |
get :browse, :id => 3
|
|
48 |
get :show, :id => 3
|
|
49 | 49 |
assert_response :success |
50 |
assert_template 'browse'
|
|
50 |
assert_template 'show'
|
|
51 | 51 |
assert_not_nil assigns(:entries) |
52 | 52 |
assert_equal 3, assigns(:entries).size |
53 | 53 |
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} |
... | ... | |
56 | 56 |
end |
57 | 57 |
|
58 | 58 |
def test_browse_directory |
59 |
get :browse, :id => 3, :path => ['images']
|
|
59 |
get :show, :id => 3, :path => ['images']
|
|
60 | 60 |
assert_response :success |
61 |
assert_template 'browse'
|
|
61 |
assert_template 'show'
|
|
62 | 62 |
assert_not_nil assigns(:entries) |
63 | 63 |
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) |
64 | 64 |
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} |
... | ... | |
69 | 69 |
|
70 | 70 |
def test_browse_at_given_revision |
71 | 71 |
Project.find(3).repository.fetch_changesets |
72 |
get :browse, :id => 3, :path => ['images'], :rev => 1
|
|
72 |
get :show, :id => 3, :path => ['images'], :rev => 1
|
|
73 | 73 |
assert_response :success |
74 |
assert_template 'browse'
|
|
74 |
assert_template 'show'
|
|
75 | 75 |
assert_not_nil assigns(:entries) |
76 | 76 |
assert_equal ['delete.png'], assigns(:entries).collect(&:name) |
77 | 77 |
end |
test/functional/repositories_git_controller_test.rb | ||
---|---|---|
46 | 46 |
end |
47 | 47 |
|
48 | 48 |
def test_browse_root |
49 |
get :browse, :id => 3
|
|
49 |
get :show, :id => 3
|
|
50 | 50 |
assert_response :success |
51 |
assert_template 'browse'
|
|
51 |
assert_template 'show'
|
|
52 | 52 |
assert_not_nil assigns(:entries) |
53 |
assert_equal 3, assigns(:entries).size
|
|
53 |
assert_equal 6, assigns(:entries).size
|
|
54 | 54 |
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} |
55 | 55 |
assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} |
56 | 56 |
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} |
57 |
assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'} |
|
58 |
assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'} |
|
59 |
assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'} |
|
57 | 60 |
end |
58 |
|
|
61 | ||
62 |
def test_browse_branch |
|
63 |
get :show, :id => 3, :rev => 'test_branch' |
|
64 |
assert_response :success |
|
65 |
assert_template 'show' |
|
66 |
assert_not_nil assigns(:entries) |
|
67 |
assert_equal 4, assigns(:entries).size |
|
68 |
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} |
|
69 |
assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} |
|
70 |
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} |
|
71 |
assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'} |
|
72 |
end |
|
73 | ||
59 | 74 |
def test_browse_directory |
60 |
get :browse, :id => 3, :path => ['images']
|
|
75 |
get :show, :id => 3, :path => ['images']
|
|
61 | 76 |
assert_response :success |
62 |
assert_template 'browse'
|
|
77 |
assert_template 'show'
|
|
63 | 78 |
assert_not_nil assigns(:entries) |
64 |
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
|
|
79 |
assert_equal ['edit.png'], assigns(:entries).collect(&:name) |
|
65 | 80 |
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} |
66 | 81 |
assert_not_nil entry |
67 | 82 |
assert_equal 'file', entry.kind |
... | ... | |
69 | 84 |
end |
70 | 85 |
|
71 | 86 |
def test_browse_at_given_revision |
72 |
get :browse, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
|
|
87 |
get :show, :id => 3, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
|
|
73 | 88 |
assert_response :success |
74 |
assert_template 'browse'
|
|
89 |
assert_template 'show'
|
|
75 | 90 |
assert_not_nil assigns(:entries) |
76 | 91 |
assert_equal ['delete.png'], assigns(:entries).collect(&:name) |
77 | 92 |
end |
78 | 93 | |
94 |
=begin |
|
95 |
Even with a rev param, this seems to render the list page rather than a single revision |
|
96 |
assert_template 'revision' passes though...? |
|
97 | ||
98 |
def test_view_revision |
|
99 |
get :revisions, :id => 3, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3' |
|
100 |
assert_response :success |
|
101 |
assert_template 'revision' |
|
102 |
assert_tag :tag => 'h2', :child => "Revision #{assigns(:rev)[0,8]}" |
|
103 |
assert_tag :tag => 'li', |
|
104 |
:attributes => {:class => /change-A/}, |
|
105 |
:child => { :tag => 'a', :child => 'new_file.txt' } |
|
106 |
end |
|
107 |
=end |
|
108 | ||
79 | 109 |
def test_changes |
80 | 110 |
get :changes, :id => 3, :path => ['images', 'edit.png'] |
81 | 111 |
assert_response :success |
... | ... | |
89 | 119 |
assert_template 'entry' |
90 | 120 |
# Line 19 |
91 | 121 |
assert_tag :tag => 'th', |
92 |
:content => /10/,
|
|
122 |
:content => /11/,
|
|
93 | 123 |
:attributes => { :class => /line-num/ }, |
94 | 124 |
:sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } |
95 | 125 |
end |
... | ... | |
104 | 134 |
def test_directory_entry |
105 | 135 |
get :entry, :id => 3, :path => ['sources'] |
106 | 136 |
assert_response :success |
107 |
assert_template 'browse'
|
|
137 |
assert_template 'show'
|
|
108 | 138 |
assert_not_nil assigns(:entry) |
109 | 139 |
assert_equal 'sources', assigns(:entry).name |
110 | 140 |
end |
... | ... | |
127 | 157 |
assert_response :success |
128 | 158 |
assert_template 'annotate' |
129 | 159 |
# Line 23, changeset 2f9c0091 |
130 |
assert_tag :tag => 'th', :content => /23/,
|
|
160 |
assert_tag :tag => 'th', :content => /24/,
|
|
131 | 161 |
:sibling => { :tag => 'td', :child => { :tag => 'a', :content => /2f9c0091/ } }, |
132 | 162 |
:sibling => { :tag => 'td', :content => /jsmith/ }, |
133 | 163 |
:sibling => { :tag => 'td', :content => /watcher =/ } |
134 | 164 |
end |
135 | 165 |
|
136 | 166 |
def test_annotate_binary_file |
137 |
get :annotate, :id => 3, :path => ['images', 'delete.png']
|
|
167 |
get :annotate, :id => 3, :path => ['images', 'edit.png']
|
|
138 | 168 |
assert_response 500 |
139 | 169 |
assert_tag :tag => 'div', :attributes => { :class => /error/ }, |
140 | 170 |
:content => /can not be annotated/ |
test/functional/repositories_mercurial_controller_test.rb | ||
---|---|---|
45 | 45 |
end |
46 | 46 |
|
47 | 47 |
def test_browse_root |
48 |
get :browse, :id => 3
|
|
48 |
get :show, :id => 3
|
|
49 | 49 |
assert_response :success |
50 |
assert_template 'browse'
|
|
50 |
assert_template 'show'
|
|
51 | 51 |
assert_not_nil assigns(:entries) |
52 | 52 |
assert_equal 3, assigns(:entries).size |
53 | 53 |
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} |
... | ... | |
56 | 56 |
end |
57 | 57 |
|
58 | 58 |
def test_browse_directory |
59 |
get :browse, :id => 3, :path => ['images']
|
|
59 |
get :show, :id => 3, :path => ['images']
|
|
60 | 60 |
assert_response :success |
61 |
assert_template 'browse'
|
|
61 |
assert_template 'show'
|
|
62 | 62 |
assert_not_nil assigns(:entries) |
63 | 63 |
assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) |
64 | 64 |
entry = assigns(:entries).detect {|e| e.name == 'edit.png'} |
... | ... | |
68 | 68 |
end |
69 | 69 |
|
70 | 70 |
def test_browse_at_given_revision |
71 |
get :browse, :id => 3, :path => ['images'], :rev => 0
|
|
71 |
get :show, :id => 3, :path => ['images'], :rev => 0
|
|
72 | 72 |
assert_response :success |
73 |
assert_template 'browse'
|
|
73 |
assert_template 'show'
|
|
74 | 74 |
assert_not_nil assigns(:entries) |
75 | 75 |
assert_equal ['delete.png'], assigns(:entries).collect(&:name) |
76 | 76 |
end |
... | ... | |
103 | 103 |
def test_directory_entry |
104 | 104 |
get :entry, :id => 3, :path => ['sources'] |
105 | 105 |
assert_response :success |
106 |
assert_template 'browse'
|
|
106 |
assert_template 'show'
|
|
107 | 107 |
assert_not_nil assigns(:entry) |
108 | 108 |
assert_equal 'sources', assigns(:entry).name |
109 | 109 |
end |
test/functional/repositories_subversion_controller_test.rb | ||
---|---|---|
47 | 47 |
end |
48 | 48 |
|
49 | 49 |
def test_browse_root |
50 |
get :browse, :id => 1
|
|
50 |
get :show, :id => 1
|
|
51 | 51 |
assert_response :success |
52 |
assert_template 'browse'
|
|
52 |
assert_template 'show'
|
|
53 | 53 |
assert_not_nil assigns(:entries) |
54 | 54 |
entry = assigns(:entries).detect {|e| e.name == 'subversion_test'} |
55 | 55 |
assert_equal 'dir', entry.kind |
56 | 56 |
end |
57 | 57 |
|
58 | 58 |
def test_browse_directory |
59 |
get :browse, :id => 1, :path => ['subversion_test']
|
|
59 |
get :show, :id => 1, :path => ['subversion_test']
|
|
60 | 60 |
assert_response :success |
61 |
assert_template 'browse'
|
|
61 |
assert_template 'show'
|
|
62 | 62 |
assert_not_nil assigns(:entries) |
63 | 63 |
assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name) |
64 | 64 |
entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'} |
... | ... | |
68 | 68 |
end |
69 | 69 | |
70 | 70 |
def test_browse_at_given_revision |
71 |
get :browse, :id => 1, :path => ['subversion_test'], :rev => 4
|
|
71 |
get :show, :id => 1, :path => ['subversion_test'], :rev => 4
|
|
72 | 72 |
assert_response :success |
73 |
assert_template 'browse'
|
|
73 |
assert_template 'show'
|
|
74 | 74 |
assert_not_nil assigns(:entries) |
75 | 75 |
assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name) |
76 | 76 |
end |
... | ... | |
131 | 131 |
def test_directory_entry |
132 | 132 |
get :entry, :id => 1, :path => ['subversion_test', 'folder'] |
133 | 133 |
assert_response :success |
134 |
assert_template 'browse'
|
|
134 |
assert_template 'show'
|
|
135 | 135 |
assert_not_nil assigns(:entry) |
136 | 136 |
assert_equal 'folder', assigns(:entry).name |
137 | 137 |
end |