Patch #259 » gitdiff-improved.diff
| app/helpers/application_helper.rb | ||
|---|---|---|
| 270 | 270 | # #52 -> Link to issue #52 | 
| 271 | 271 | # Changesets: | 
| 272 | 272 | # r52 -> Link to revision 52 | 
| 273 | # commit:a85130f -> Link to scmid starting with a85130f | |
| 273 | 274 | # Documents: | 
| 274 | 275 | # document#17 -> Link to document with id 17 | 
| 275 | 276 | # document:Greetings -> Link to the document with title "Greetings" | 
| ... | ... | |
| 280 | 281 | # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" | 
| 281 | 282 | # Attachments: | 
| 282 | 283 | # attachment:file.zip -> Link to the attachment of the current object named file.zip | 
| 283 |     text = text.gsub(%r{([\s\(,-^])(!)?(attachment|document|version)?((#|r)(\d+)|(:)([^"][^\s<>]+|"[^"]+"))(?=[[:punct:]]|\s|<|$)}) do |m| | |
| 284 |     text = text.gsub(%r{([\s\(,-^])(!)?(attachment|document|version|commit)?((#|r)(\d+)|(:)([^"][^\s<>]+|"[^"]+"))(?=[[:punct:]]|\s|<|$)}) do |m| | |
| 284 | 285 | leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8 | 
| 285 | 286 | link = nil | 
| 286 | 287 | if esc.nil? | 
| ... | ... | |
| 325 | 326 |               link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, | 
| 326 | 327 | :class => 'version' | 
| 327 | 328 | end | 
| 329 | when 'commit' | |
| 330 |             if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"])) | |
| 331 |               link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project.id, :rev => changeset.revision}, :class => 'changeset', :title => truncate(changeset.comments, 100) | |
| 332 | end | |
| 328 | 333 | when 'attachment' | 
| 329 | 334 |             if attachments && attachment = attachments.detect {|a| a.filename == name } | 
| 330 | 335 |               link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, | 
| app/helpers/repositories_helper.rb | ||
|---|---|---|
| 76 | 76 |       content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) | 
| 77 | 77 | end | 
| 78 | 78 | |
| 79 | def git_field_tags(form, repository) | |
| 80 |       content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) | |
| 81 | end | |
| 82 | ||
| 79 | 83 | def cvs_field_tags(form, repository) | 
| 80 | 84 |       content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) + | 
| 81 | 85 |       content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?)) | 
| app/models/repository/git.rb | ||
|---|---|---|
| 1 | # redMine - project management software | |
| 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
| 3 | # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com | |
| 4 | # This program is free software; you can redistribute it and/or | |
| 5 | # modify it under the terms of the GNU General Public License | |
| 6 | # as published by the Free Software Foundation; either version 2 | |
| 7 | # of the License, or (at your option) any later version. | |
| 8 | # | |
| 9 | # This program is distributed in the hope that it will be useful, | |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | # GNU General Public License for more details. | |
| 13 | # | |
| 14 | # You should have received a copy of the GNU General Public License | |
| 15 | # along with this program; if not, write to the Free Software | |
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 17 | ||
| 18 | require 'redmine/scm/adapters/git_adapter' | |
| 19 | ||
| 20 | class Repository::Git < Repository | |
| 21 | attr_protected :root_url | |
| 22 | validates_presence_of :url | |
| 23 | ||
| 24 | def scm_adapter | |
| 25 | Redmine::Scm::Adapters::GitAdapter | |
| 26 | end | |
| 27 |  | |
| 28 | def self.scm_name | |
| 29 | 'Git' | |
| 30 | end | |
| 31 |  | |
| 32 | def entries(path=nil, identifier=nil) | |
| 33 | entries=scm.entries(path, identifier) | |
| 34 | if entries | |
| 35 | entries.each do |entry| | |
| 36 | next unless entry.is_file? | |
| 37 | # Search the DB for the entry's last change | |
| 38 |         change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC") | |
| 39 | if change | |
| 40 | entry.lastrev.identifier = change.changeset.revision | |
| 41 | entry.lastrev.name = change.changeset.revision | |
| 42 | entry.lastrev.author = change.changeset.committer | |
| 43 | entry.lastrev.revision = change.revision | |
| 44 | end | |
| 45 | end | |
| 46 | end | |
| 47 | entries | |
| 48 | end | |
| 49 | ||
| 50 | def changesets_for_path(path) | |
| 51 |     path = "#{path}" unless path.starts_with?('/') | |
| 52 | Change.find(:all, :include => :changeset, | |
| 53 | :conditions => ["repository_id = ? AND path = ?", id, path], | |
| 54 |                 :order => "committed_on DESC, #{Changeset.table_name}.revision DESC").collect(&:changeset) | |
| 55 | end | |
| 56 | ||
| 57 | def fetch_changesets | |
| 58 | scm_info = scm.info | |
| 59 |  | |
| 60 | ||
| 61 | if scm_info | |
| 62 | # latest revision found in database | |
| 63 | db_revision = latest_changeset ? latest_changeset.scmid : nil | |
| 64 | next_rev = latest_changeset ? latest_changeset.revision + 1 : 1 | |
| 65 | # latest revision in the repository | |
| 66 | scm_revision = scm_info.lastrev.scmid | |
| 67 | ||
| 68 | unless changesets.find_by_scmid(scm_revision) | |
| 69 | ||
| 70 |         revisions = scm.revisions('', db_revision, nil) | |
| 71 | transaction do | |
| 72 | revisions.reverse_each do |revision| | |
| 73 | changeset = Changeset.create(:repository => self, | |
| 74 | :revision => next_rev, | |
| 75 | :scmid => revision.scmid, | |
| 76 | :committer => revision.author, | |
| 77 | :committed_on => revision.time, | |
| 78 | :comments => revision.message) | |
| 79 | next_rev += 1 | |
| 80 |  | |
| 81 | revision.paths.each do |change| | |
| 82 | Change.create(:changeset => changeset, | |
| 83 | :action => change[:action], | |
| 84 | :path => change[:path], | |
| 85 | :from_path => change[:from_path], | |
| 86 | :from_revision => change[:from_revision]) | |
| 87 | end | |
| 88 | end | |
| 89 | end | |
| 90 | end | |
| 91 | end | |
| 92 | end | |
| 93 | end | |
| app/views/repositories/_dir_list_content.rhtml | ||
|---|---|---|
| 25 | 25 | <td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td> | 
| 26 | 26 | <td class="revision"><%= link_to(entry.lastrev.name, :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %></td> | 
| 27 | 27 | <td class="age"><%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %></td> | 
| 28 | <td class="author"><%=h(entry.lastrev.author) if entry.lastrev %></td> | |
| 28 | <td class="author"><%=h(entry.lastrev.author.split('<').first) if entry.lastrev %></td> | |
| 29 | 29 | <% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev %> | 
| 30 | 30 | <td class="comments"><%=h truncate(changeset.comments, 50) unless changeset.nil? %></td> | 
| 31 | 31 | </tr> | 
| app/views/repositories/_revisions.rhtml | ||
|---|---|---|
| 17 | 17 | <td class="checkbox"><%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %></td> | 
| 18 | 18 | <td class="checkbox"><%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td> | 
| 19 | 19 | <td class="committed_on"><%= format_time(changeset.committed_on) %></td> | 
| 20 | <td class="author"><%=h changeset.committer %></td> | |
| 20 | <td class="author"><%=h changeset.committer.split('<').first %></td> | |
| 21 | 21 | <td class="comments"><%= textilizable(changeset.comments) %></td> | 
| 22 | 22 | </tr> | 
| 23 | 23 | <% line_num += 1 %> | 
| doc/RUNNING_TESTS | ||
|---|---|---|
| 19 | 19 | Mercurial | 
| 20 | 20 | --------- | 
| 21 | 21 | gunzip < test/fixtures/repositories/mercurial_repository.tar.gz | tar -xv -C tmp/test | 
| 22 | ||
| 23 | Git | |
| 24 | --- | |
| 25 | gunzip < test/fixtures/repositories/git_repository.tar.gz | tar -xv -C tmp/test | |
| 26 | ||
| 27 | ||
| 28 | Running Tests | |
| 29 | ============= | |
| 30 | ||
| 31 | Run | |
| 32 | ||
| 33 | rake --tasks | grep test | |
| 34 | ||
| 35 | to see available tests. | |
| 36 | ||
| 37 | RAILS_ENV=test rake test will run tests. | |
| lib/redmine.rb | ||
|---|---|---|
| 10 | 10 | # RMagick is not available | 
| 11 | 11 | end | 
| 12 | 12 | |
| 13 | REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar ) | |
| 13 | REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git ) | |
| 14 | 14 | |
| 15 | 15 | # Permissions | 
| 16 | 16 | Redmine::AccessControl.map do |map| | 
| lib/redmine/scm/adapters/git_adapter.rb | ||
|---|---|---|
| 1 | # redMine - project management software | |
| 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
| 3 | # | |
| 4 | # This program is free software; you can redistribute it and/or | |
| 5 | # modify it under the terms of the GNU General Public License | |
| 6 | # as published by the Free Software Foundation; either version 2 | |
| 7 | # of the License, or (at your option) any later version. | |
| 8 | # | |
| 9 | # This program is distributed in the hope that it will be useful, | |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | # GNU General Public License for more details. | |
| 13 | # | |
| 14 | # You should have received a copy of the GNU General Public License | |
| 15 | # along with this program; if not, write to the Free Software | |
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 17 | ||
| 18 | require 'redmine/scm/adapters/abstract_adapter' | |
| 19 | ||
| 20 | module Redmine | |
| 21 | module Scm | |
| 22 | module Adapters | |
| 23 | class GitAdapter < AbstractAdapter | |
| 24 |  | |
| 25 | # Git executable name | |
| 26 | GIT_BIN = "git" | |
| 27 | ||
| 28 | # Convert an identifier to a git revision | |
| 29 | def id_to_rev(identifier) | |
| 30 | if identifier.nil? | |
| 31 | return nil | |
| 32 | end | |
| 33 |  | |
| 34 |           cmd = "cd #{target('')} && #{GIT_BIN} log --reverse --raw " | |
| 35 | cmd << "--skip=" | |
| 36 | cmd << ((identifier - 1).to_s) | |
| 37 | answer = nil | |
| 38 | ||
| 39 | shellout(cmd) do |io| | |
| 40 |  | |
| 41 | io.each_line do |line| | |
| 42 |               if answer.nil? && line =~ /^commit ([0-9a-f]{40})$/ | |
| 43 | answer = $1 | |
| 44 | else | |
| 45 | next | |
| 46 | end | |
| 47 | end | |
| 48 | end | |
| 49 | ||
| 50 | return answer | |
| 51 | end | |
| 52 | ||
| 53 | #get the revision of a particuliar file | |
| 54 | def get_rev (rev,path) | |
| 55 |           cmd="cd #{target('')} && git show #{rev} -- #{path}" if rev!='latest' | |
| 56 |           cmd="cd #{target('')} && git log -1 master -- #{path}" if  | |
| 57 | rev=='latest' or rev.nil? | |
| 58 | rev=[] | |
| 59 | i=0 | |
| 60 | shellout(cmd) do |io| | |
| 61 | files=[] | |
| 62 |             changeset = {} | |
| 63 | parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files | |
| 64 | line_feeds = 0 | |
| 65 | ||
| 66 | io.each_line do |line| | |
| 67 |               if line =~ /^commit ([0-9a-f]{40})$/ | |
| 68 | key = "commit" | |
| 69 | value = $1 | |
| 70 | if (parsing_descr == 1 || parsing_descr == 2) | |
| 71 | parsing_descr = 0 | |
| 72 |                   rev = Revision.new({:identifier => nil, | |
| 73 | :scmid => changeset[:commit], | |
| 74 | :author => changeset[:author], | |
| 75 | :time => Time.parse(changeset[:date]), | |
| 76 | :message => changeset[:description], | |
| 77 | :paths => files | |
| 78 | }) | |
| 79 |                   changeset = {} | |
| 80 | files = [] | |
| 81 | end | |
| 82 | changeset[:commit] = $1 | |
| 83 | elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ | |
| 84 | key = $1 | |
| 85 | value = $2 | |
| 86 | if key == "Author" | |
| 87 | changeset[:author] = value | |
| 88 | elsif key == "Date" | |
| 89 | changeset[:date] = value | |
| 90 | end | |
| 91 | elsif (parsing_descr == 0) && line.chomp.to_s == "" | |
| 92 | parsing_descr = 1 | |
| 93 | changeset[:description] = "" | |
| 94 | elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/ | |
| 95 | parsing_descr = 2 | |
| 96 | fileaction = $1 | |
| 97 | filepath = $2 | |
| 98 |                 files << {:action => fileaction, :path => filepath} | |
| 99 | elsif (parsing_descr == 1) && line.chomp.to_s == "" | |
| 100 | parsing_descr = 2 | |
| 101 | elsif (parsing_descr == 1) | |
| 102 | changeset[:description] << line | |
| 103 | end | |
| 104 | end | |
| 105 |             rev = Revision.new({:identifier => nil, | |
| 106 | :scmid => changeset[:commit], | |
| 107 | :author => changeset[:author], | |
| 108 | :time => Time.parse(changeset[:date]), | |
| 109 | :message => changeset[:description], | |
| 110 | :paths => files | |
| 111 | }) | |
| 112 | ||
| 113 | end | |
| 114 | ||
| 115 |           get_rev('latest',path) if rev == [] | |
| 116 | ||
| 117 | return nil if $? && $?.exitstatus != 0 | |
| 118 | return rev | |
| 119 | # rescue Errno::ENOENT => e | |
| 120 | # raise CommandFailed | |
| 121 | end | |
| 122 | ||
| 123 | ||
| 124 | def info | |
| 125 |           #           cmd = "#{GIT_BIN} -R #{target('')} root" | |
| 126 | # root_url = nil | |
| 127 | # shellout(cmd) do |io| | |
| 128 |           root_url = target('') | |
| 129 | # end | |
| 130 |           info = Info.new({:root_url => target(''), | |
| 131 | :lastrev => revisions(root_url,nil,nil,nil).first | |
| 132 | }) | |
| 133 | info | |
| 134 | rescue Errno::ENOENT => e | |
| 135 | return nil | |
| 136 | end | |
| 137 |  | |
| 138 | def entries(path=nil, identifier=nil) | |
| 139 | path ||= '' | |
| 140 | entries = Entries.new | |
| 141 |           cmd = "cd #{target('')} && #{GIT_BIN} ls-tree -l HEAD:#{path}" if identifier.nil? | |
| 142 |           cmd = "cd #{target('')} && #{GIT_BIN} ls-tree -l #{identifier}:#{path}" if identifier | |
| 143 | shellout(cmd) do |io| | |
| 144 | io.each_line do |line| | |
| 145 | e = line.chomp.to_s | |
| 146 |               if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\s+(.+)$/ | |
| 147 | type = $1 | |
| 148 | sha = $2 | |
| 149 | size = $3 | |
| 150 | name = $4 | |
| 151 |                 entries << Entry.new({:name => name, | |
| 152 |                                        :path => (path.empty? ? name : "#{path}/#{name}"), | |
| 153 | :kind => ((type == "tree") ? 'dir' : 'file'), | |
| 154 | :size => ((type == "tree") ? nil : size), | |
| 155 |                                        :lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}"))  | |
| 156 |  | |
| 157 |                                      }) unless entries.detect{|entry| entry.name == name} | |
| 158 | end | |
| 159 | end | |
| 160 | end | |
| 161 | return nil if $? && $?.exitstatus != 0 | |
| 162 | entries.sort_by_name | |
| 163 | # rescue Errno::ENOENT => e | |
| 164 | # raise CommandFailed | |
| 165 | end | |
| 166 |  | |
| 167 | def entry(path=nil, identifier=nil) | |
| 168 | path ||= '' | |
| 169 |           search_path = path.split('/')[0..-2].join('/') | |
| 170 |           entry_name = path.split('/').last | |
| 171 | e = entries(search_path, identifier) | |
| 172 |           e ? e.detect{|entry| entry.name == entry_name} : nil | |
| 173 | end | |
| 174 |  | |
| 175 |         def revisions(path, identifier_from, identifier_to, options={}) | |
| 176 | revisions = Revisions.new | |
| 177 |           cmd = "cd #{target('')} && #{GIT_BIN} log --raw " | |
| 178 |           cmd << " #{identifier_from}.. " if identifier_from | |
| 179 |           cmd << " #{identifier_to} " if identifier_to | |
| 180 | #cmd << " HEAD " if !identifier_to | |
| 181 | shellout(cmd) do |io| | |
| 182 | files=[] | |
| 183 |             changeset = {} | |
| 184 | parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files | |
| 185 | line_feeds = 0 | |
| 186 | revno = 1 | |
| 187 | ||
| 188 | io.each_line do |line| | |
| 189 |               if line =~ /^commit ([0-9a-f]{40})$/ | |
| 190 | key = "commit" | |
| 191 | value = $1 | |
| 192 | if (parsing_descr == 1 || parsing_descr == 2) | |
| 193 | parsing_descr = 0 | |
| 194 |                   revisions << Revision.new({:identifier => nil, | |
| 195 | :scmid => changeset[:commit], | |
| 196 | :author => changeset[:author], | |
| 197 | :time => Time.parse(changeset[:date]), | |
| 198 | :message => changeset[:description], | |
| 199 | :paths => files | |
| 200 | }) | |
| 201 |                   changeset = {} | |
| 202 | files = [] | |
| 203 | revno = revno + 1 | |
| 204 | end | |
| 205 | changeset[:commit] = $1 | |
| 206 | elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ | |
| 207 | key = $1 | |
| 208 | value = $2 | |
| 209 | if key == "Author" | |
| 210 | changeset[:author] = value | |
| 211 | elsif key == "Date" | |
| 212 | changeset[:date] = value | |
| 213 | end | |
| 214 | elsif (parsing_descr == 0) && line.chomp.to_s == "" | |
| 215 | parsing_descr = 1 | |
| 216 | changeset[:description] = "" | |
| 217 | elsif (parsing_descr == 1 || parsing_descr == 2) && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/ | |
| 218 | parsing_descr = 2 | |
| 219 | fileaction = $1 | |
| 220 | filepath = $2 | |
| 221 |                 files << {:action => fileaction, :path => filepath} | |
| 222 | elsif (parsing_descr == 1) && line.chomp.to_s == "" | |
| 223 | parsing_descr = 2 | |
| 224 | elsif (parsing_descr == 1) | |
| 225 | changeset[:description] << line[4..-1] | |
| 226 | end | |
| 227 | end | |
| 228 | ||
| 229 |             revisions << Revision.new({:identifier => nil, | |
| 230 | :scmid => changeset[:commit], | |
| 231 | :author => changeset[:author], | |
| 232 | :time => Time.parse(changeset[:date]), | |
| 233 | :message => changeset[:description], | |
| 234 | :paths => files | |
| 235 | }) | |
| 236 | ||
| 237 | end | |
| 238 | ||
| 239 | return nil if $? && $?.exitstatus != 0 | |
| 240 | revisions | |
| 241 | rescue Errno::ENOENT => e | |
| 242 | raise CommandFailed | |
| 243 | end | |
| 244 |  | |
| 245 | def diff(path, identifier_from, identifier_to=nil, type="inline") | |
| 246 | path ||= '' | |
| 247 | if identifier_to | |
| 248 | identifier_to = identifier_to | |
| 249 | else | |
| 250 | identifier_to = nil | |
| 251 | end | |
| 252 | ||
| 253 | identifier_from = id_to_rev(identifier_from) | |
| 254 | identifier_to = id_to_rev(identifier_to) | |
| 255 |  | |
| 256 |           cmd = "cd #{target('')} && #{GIT_BIN}  diff   #{identifier_from}^!" if identifier_to.nil? | |
| 257 |           cmd = "cd #{target('')} && #{GIT_BIN}  diff #{identifier_to}  #{identifier_from}" if !identifier_to.nil? | |
| 258 |           cmd << " -- #{path}" unless path.empty? | |
| 259 | diff = [] | |
| 260 | shellout(cmd) do |io| | |
| 261 | io.each_line do |line| | |
| 262 | diff << line | |
| 263 | end | |
| 264 | end | |
| 265 | return nil if $? && $?.exitstatus != 0 | |
| 266 | DiffTableList.new diff, type | |
| 267 |  | |
| 268 | rescue Errno::ENOENT => e | |
| 269 | raise CommandFailed | |
| 270 | end | |
| 271 |  | |
| 272 | def cat(path, identifier=nil) | |
| 273 | identifier = id_to_rev(identifier) | |
| 274 | if identifier.nil? | |
| 275 | identifier = 'HEAD' | |
| 276 | end | |
| 277 |           cmd = "cd #{target('')} && #{GIT_BIN} show #{identifier}:#{path}" | |
| 278 | cat = nil | |
| 279 | shellout(cmd) do |io| | |
| 280 | io.binmode | |
| 281 | cat = io.read | |
| 282 | end | |
| 283 | return nil if $? && $?.exitstatus != 0 | |
| 284 | cat | |
| 285 | rescue Errno::ENOENT => e | |
| 286 | raise CommandFailed | |
| 287 | end | |
| 288 | end | |
| 289 | end | |
| 290 | end | |
| 291 | ||
| 292 | end | |
| 293 | ||
| test/functional/repositories_git_controller_test.rb | ||
|---|---|---|
| 1 | # redMine - project management software | |
| 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
| 3 | # | |
| 4 | # This program is free software; you can redistribute it and/or | |
| 5 | # modify it under the terms of the GNU General Public License | |
| 6 | # as published by the Free Software Foundation; either version 2 | |
| 7 | # of the License, or (at your option) any later version. | |
| 8 | # | |
| 9 | # This program is distributed in the hope that it will be useful, | |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | # GNU General Public License for more details. | |
| 13 | # | |
| 14 | # You should have received a copy of the GNU General Public License | |
| 15 | # along with this program; if not, write to the Free Software | |
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 17 | ||
| 18 | require File.dirname(__FILE__) + '/../test_helper' | |
| 19 | require 'repositories_controller' | |
| 20 | ||
| 21 | # Re-raise errors caught by the controller. | |
| 22 | class RepositoriesController; def rescue_action(e) raise e end; end | |
| 23 | ||
| 24 | class RepositoriesGitControllerTest < Test::Unit::TestCase | |
| 25 | fixtures :projects, :users, :roles, :members, :repositories, :enabled_modules | |
| 26 | ||
| 27 | # No '..' in the repository path | |
| 28 |   REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository' | |
| 29 | ||
| 30 | def setup | |
| 31 | @controller = RepositoriesController.new | |
| 32 | @request = ActionController::TestRequest.new | |
| 33 | @response = ActionController::TestResponse.new | |
| 34 | User.current = nil | |
| 35 | Repository::Git.create(:project => Project.find(3), :url => REPOSITORY_PATH) | |
| 36 | end | |
| 37 |  | |
| 38 | if File.directory?(REPOSITORY_PATH) | |
| 39 | def test_show | |
| 40 | get :show, :id => 3 | |
| 41 | assert_response :success | |
| 42 | assert_template 'show' | |
| 43 | assert_not_nil assigns(:entries) | |
| 44 | assert_not_nil assigns(:changesets) | |
| 45 | end | |
| 46 |  | |
| 47 | def test_browse_root | |
| 48 | get :browse, :id => 3 | |
| 49 | assert_response :success | |
| 50 | assert_template 'browse' | |
| 51 | assert_not_nil assigns(:entries) | |
| 52 | assert_equal 3, assigns(:entries).size | |
| 53 |       assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} | |
| 54 |       assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} | |
| 55 |       assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} | |
| 56 | end | |
| 57 |  | |
| 58 | def test_browse_directory | |
| 59 | get :browse, :id => 3, :path => ['images'] | |
| 60 | assert_response :success | |
| 61 | assert_template 'browse' | |
| 62 | assert_not_nil assigns(:entries) | |
| 63 | assert_equal 2, assigns(:entries).size | |
| 64 |       entry = assigns(:entries).detect {|e| e.name == 'edit.png'} | |
| 65 | assert_not_nil entry | |
| 66 | assert_equal 'file', entry.kind | |
| 67 | assert_equal 'images/edit.png', entry.path | |
| 68 | end | |
| 69 |  | |
| 70 | def test_changes | |
| 71 | get :changes, :id => 3, :path => ['images', 'edit.png'] | |
| 72 | assert_response :success | |
| 73 | assert_template 'changes' | |
| 74 | assert_tag :tag => 'h2', :content => 'edit.png' | |
| 75 | end | |
| 76 |  | |
| 77 | def test_entry_show | |
| 78 | get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'] | |
| 79 | assert_response :success | |
| 80 | assert_template 'entry' | |
| 81 | # Line 19 | |
| 82 | assert_tag :tag => 'th', | |
| 83 | :content => /10/, | |
| 84 |                  :attributes => { :class => /line-num/ }, | |
| 85 |                  :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } | |
| 86 | end | |
| 87 |  | |
| 88 | def test_entry_download | |
| 89 | get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw' | |
| 90 | assert_response :success | |
| 91 | # File content | |
| 92 |       assert @response.body.include?('WITHOUT ANY WARRANTY') | |
| 93 | end | |
| 94 |  | |
| 95 | def test_diff | |
| 96 | # Full diff of changeset 4 | |
| 97 | get :diff, :id => 3, :rev => 4 | |
| 98 | assert_response :success | |
| 99 | assert_template 'diff' | |
| 100 | # Line 22 removed | |
| 101 | assert_tag :tag => 'th', | |
| 102 | :content => /22/, | |
| 103 |                  :sibling => { :tag => 'td',  | |
| 104 |                                :attributes => { :class => /diff_out/ }, | |
| 105 | :content => /def remove/ } | |
| 106 | end | |
| 107 |  | |
| 108 | def test_annotate | |
| 109 | get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb'] | |
| 110 | assert_response :success | |
| 111 | assert_template 'annotate' | |
| 112 | # Line 23, revision 4 | |
| 113 | assert_tag :tag => 'th', :content => /23/, | |
| 114 |                  :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /4/ } }, | |
| 115 |                  :sibling => { :tag => 'td', :content => /jsmith/ }, | |
| 116 |                  :sibling => { :tag => 'td', :content => /watcher =/ } | |
| 117 | end | |
| 118 | else | |
| 119 | puts "Git test repository NOT FOUND. Skipping functional tests !!!" | |
| 120 | def test_fake; assert true end | |
| 121 | end | |
| 122 | end | |
| test/unit/repository_git_test.rb | ||
|---|---|---|
| 1 | # redMine - project management software | |
| 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
| 3 | # | |
| 4 | # This program is free software; you can redistribute it and/or | |
| 5 | # modify it under the terms of the GNU General Public License | |
| 6 | # as published by the Free Software Foundation; either version 2 | |
| 7 | # of the License, or (at your option) any later version. | |
| 8 | # | |
| 9 | # This program is distributed in the hope that it will be useful, | |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | # GNU General Public License for more details. | |
| 13 | # | |
| 14 | # You should have received a copy of the GNU General Public License | |
| 15 | # along with this program; if not, write to the Free Software | |
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 17 | ||
| 18 | require File.dirname(__FILE__) + '/../test_helper' | |
| 19 | ||
| 20 | class RepositoryGitTest < Test::Unit::TestCase | |
| 21 | fixtures :projects | |
| 22 |  | |
| 23 | # No '..' in the repository path | |
| 24 |   REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository' | |
| 25 |  | |
| 26 | def setup | |
| 27 | @project = Project.find(1) | |
| 28 | assert @repository = Repository::Git.create(:project => @project, :url => REPOSITORY_PATH) | |
| 29 | end | |
| 30 |  | |
| 31 | if File.directory?(REPOSITORY_PATH) | |
| 32 | def test_fetch_changesets_from_scratch | |
| 33 | @repository.fetch_changesets | |
| 34 | @repository.reload | |
| 35 |  | |
| 36 | assert_equal 6, @repository.changesets.count | |
| 37 | assert_equal 11, @repository.changes.count | |
| 38 | assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision(1).comments | |
| 39 | end | |
| 40 |  | |
| 41 | def test_fetch_changesets_incremental | |
| 42 | @repository.fetch_changesets | |
| 43 | # Remove changesets with revision > 3 | |
| 44 | @repository.changesets.find(:all, :conditions => 'revision > 3').each(&:destroy) | |
| 45 | @repository.reload | |
| 46 | assert_equal 3, @repository.changesets.count | |
| 47 |  | |
| 48 | @repository.fetch_changesets | |
| 49 | assert_equal 6, @repository.changesets.count | |
| 50 | end | |
| 51 | else | |
| 52 | puts "Git test repository NOT FOUND. Skipping unit tests !!!" | |
| 53 | def test_fake; assert true end | |
| 54 | end | |
| 55 | end | |