Compare commits

..
16 Commits
Author SHA1 Message Date
Jean-Philippe Lang fc6ccc1ea2 tagged version 0.9.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/0.9.3@3515 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 15:12:09 +00:00
Jean-Philippe Lang bfd9164c0a Merged r3506 for 0.9.3 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3507 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 10:21:33 +00:00
Jean-Philippe Lang d80fb751fd Merged r3469, r3472 and r3473 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3505 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 10:10:55 +00:00
Jean-Philippe Lang aacabbe645 Merged r3498 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3504 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 09:59:31 +00:00
Jean-Philippe Lang 8eafcbede9 Merged r3481 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3503 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 09:58:33 +00:00
Jean-Philippe Lang 43c1481998 Merged r3446 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3502 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 09:56:55 +00:00
Jean-Philippe Lang 17f60af490 Merged r3394, r3466, r3467, r3468 and r3471 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3501 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-28 09:51:10 +00:00
Jean-Philippe Lang e5e5ad6b7a Merged r3398 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3465 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:40:02 +00:00
Jean-Philippe Lang 13fb739b56 Merged r3409 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3464 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:26:49 +00:00
Jean-Philippe Lang 73e849be58 Merged r3451 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3463 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:22:06 +00:00
Jean-Philippe Lang 0b7d4e818a Merged r3452 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3462 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:20:52 +00:00
Jean-Philippe Lang 40a4b111fa Merged r3447 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3461 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:19:02 +00:00
Jean-Philippe Lang 7d913f93c3 Merged r3448 and r3455 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3460 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-20 10:16:08 +00:00
Jean-Philippe Lang 864fd9c6a1 Merged bug fixes r3423 and r3427.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3433 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-14 15:57:56 +00:00
Jean-Philippe Lang 57dcbd7376 Merged bug fixes r3412 to r3414.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3432 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-14 15:55:00 +00:00
Jean-Philippe Lang 0ef11ef4fe Merged bug fixes r3402, r3405 to r3408 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.9-stable@3431 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-14 15:48:28 +00:00
46 changed files with 432 additions and 136 deletions
@@ -21,8 +21,8 @@ class IssueRelationsController < ApplicationController
def new def new
@relation = IssueRelation.new(params[:relation]) @relation = IssueRelation.new(params[:relation])
@relation.issue_from = @issue @relation.issue_from = @issue
if params[:relation] && !params[:relation][:issue_to_id].blank? if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
@relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id]) @relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
end end
@relation.save if request.post? @relation.save if request.post?
respond_to do |format| respond_to do |format|
+1 -5
View File
@@ -320,13 +320,9 @@ class ProjectsController < ApplicationController
@issues_by_version = {} @issues_by_version = {}
unless @selected_tracker_ids.empty? unless @selected_tracker_ids.empty?
@versions.each do |version| @versions.each do |version|
conditions = {:tracker_id => @selected_tracker_ids}
if !@project.versions.include?(version)
conditions.merge!(:project_id => project_ids)
end
issues = version.fixed_issues.visible.find(:all, issues = version.fixed_issues.visible.find(:all,
:include => [:project, :status, :tracker, :priority], :include => [:project, :status, :tracker, :priority],
:conditions => conditions, :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
@issues_by_version[version] = issues @issues_by_version[version] = issues
end end
+6 -6
View File
@@ -506,17 +506,17 @@ module ApplicationHelper
# Forum messages: # Forum messages:
# message#1218 -> Link to message with id 1218 # message#1218 -> Link to message with id 1218
text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m| text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m|
leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8 leading, esc, prefix, sep, identifier = $1, $2, $3, $5 || $7, $6 || $8
link = nil link = nil
if esc.nil? if esc.nil?
if prefix.nil? && sep == 'r' if prefix.nil? && sep == 'r'
if project && (changeset = project.changesets.find_by_revision(oid)) if project && (changeset = project.changesets.find_by_revision(identifier))
link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid}, link = link_to("r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
:class => 'changeset', :class => 'changeset',
:title => truncate_single_line(changeset.comments, :length => 100)) :title => truncate_single_line(changeset.comments, :length => 100))
end end
elsif sep == '#' elsif sep == '#'
oid = oid.to_i oid = identifier.to_i
case prefix case prefix
when nil when nil
if issue = Issue.visible.find_by_id(oid, :include => :status) if issue = Issue.visible.find_by_id(oid, :include => :status)
@@ -547,7 +547,7 @@ module ApplicationHelper
end end
elsif sep == ':' elsif sep == ':'
# removes the double quotes if any # removes the double quotes if any
name = oid.gsub(%r{^"(.*)"$}, "\\1") name = identifier.gsub(%r{^"(.*)"$}, "\\1")
case prefix case prefix
when 'document' when 'document'
if project && document = project.documents.find_by_title(name) if project && document = project.documents.find_by_title(name)
@@ -584,7 +584,7 @@ module ApplicationHelper
end end
end end
end end
leading + (link || "#{prefix}#{sep}#{oid}") leading + (link || "#{prefix}#{sep}#{identifier}")
end end
text text
+15 -9
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2008 Jean-Philippe Lang # Copyright (C) 2006-2010 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -57,6 +57,10 @@ class Changeset < ActiveRecord::Base
super super
end end
def committer=(arg)
write_attribute(:committer, self.class.to_utf8(arg.to_s))
end
def project def project
repository.project repository.project
end end
@@ -80,9 +84,6 @@ class Changeset < ActiveRecord::Base
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
# keywords used to fix issues # keywords used to fix issues
fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
# status and optional done ratio applied
fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
done_ratio = Setting.commit_fix_done_ratio.blank? ? nil : Setting.commit_fix_done_ratio.to_i
kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
return if kw_regexp.blank? return if kw_regexp.blank?
@@ -100,7 +101,7 @@ class Changeset < ActiveRecord::Base
action = match[0] action = match[0]
target_issue_ids = match[1].scan(/\d+/) target_issue_ids = match[1].scan(/\d+/)
target_issues = find_referenced_issues_by_id(target_issue_ids) target_issues = find_referenced_issues_by_id(target_issue_ids)
if fix_status && fix_keywords.include?(action.downcase) if fix_keywords.include?(action.downcase) && fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
# update status of issues # update status of issues
logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug? logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
target_issues.each do |issue| target_issues.each do |issue|
@@ -114,7 +115,9 @@ class Changeset < ActiveRecord::Base
end end
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, csettext)) journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, csettext))
issue.status = fix_status issue.status = fix_status
issue.done_ratio = done_ratio if done_ratio unless Setting.commit_fix_done_ratio.blank?
issue.done_ratio = Setting.commit_fix_done_ratio.to_i
end
Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
{ :changeset => self, :issue => issue }) { :changeset => self, :issue => issue })
issue.save issue.save
@@ -123,7 +126,8 @@ class Changeset < ActiveRecord::Base
referenced_issues += target_issues referenced_issues += target_issues
end end
self.issues = referenced_issues.uniq referenced_issues.uniq!
self.issues = referenced_issues unless referenced_issues.empty?
end end
def short_comments def short_comments
@@ -154,6 +158,7 @@ class Changeset < ActiveRecord::Base
# Finds issues that can be referenced by the commit message # Finds issues that can be referenced by the commit message
# i.e. issues that belong to the repository project, a subproject or a parent project # i.e. issues that belong to the repository project, a subproject or a parent project
def find_referenced_issues_by_id(ids) def find_referenced_issues_by_id(ids)
return [] if ids.compact.empty?
Issue.find_all_by_id(ids, :include => :project).select {|issue| Issue.find_all_by_id(ids, :include => :project).select {|issue|
project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project) project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project)
} }
@@ -171,11 +176,12 @@ class Changeset < ActiveRecord::Base
encoding = Setting.commit_logs_encoding.to_s.strip encoding = Setting.commit_logs_encoding.to_s.strip
unless encoding.blank? || encoding == 'UTF-8' unless encoding.blank? || encoding == 'UTF-8'
begin begin
return Iconv.conv('UTF-8', encoding, str) str = Iconv.conv('UTF-8', encoding, str)
rescue Iconv::Failure rescue Iconv::Failure
# do nothing here # do nothing here
end end
end end
str # removes invalid UTF8 sequences
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
end end
end end
+2 -1
View File
@@ -159,7 +159,8 @@ class Issue < ActiveRecord::Base
end end
send :attributes_without_tracker_first=, new_attributes, *args send :attributes_without_tracker_first=, new_attributes, *args
end end
alias_method_chain :attributes=, :tracker_first # Do not redefine alias chain on reload (see #4838)
alias_method_chain(:attributes=, :tracker_first) unless method_defined?(:attributes_without_tracker_first=)
def estimated_hours=(h) def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
+14 -2
View File
@@ -56,7 +56,7 @@ class Project < ActiveRecord::Base
:delete_permission => :manage_files :delete_permission => :manage_files
acts_as_customizable acts_as_customizable
acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil
acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"}, acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
:url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}}, :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}},
:author => nil :author => nil
@@ -249,7 +249,7 @@ class Project < ActiveRecord::Base
return @allowed_parents if @allowed_parents return @allowed_parents if @allowed_parents
@allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects)) @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
@allowed_parents = @allowed_parents - self_and_descendants @allowed_parents = @allowed_parents - self_and_descendants
if User.current.allowed_to?(:add_project, nil, :global => true) if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
@allowed_parents << nil @allowed_parents << nil
end end
unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent) unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
@@ -512,11 +512,23 @@ class Project < ActiveRecord::Base
unless project.wiki.nil? unless project.wiki.nil?
self.wiki ||= Wiki.new self.wiki ||= Wiki.new
wiki.attributes = project.wiki.attributes.dup.except("id", "project_id") wiki.attributes = project.wiki.attributes.dup.except("id", "project_id")
wiki_pages_map = {}
project.wiki.pages.each do |page| project.wiki.pages.each do |page|
# Skip pages without content
next if page.content.nil?
new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on")) new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on"))
new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id")) new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id"))
new_wiki_page.content = new_wiki_content new_wiki_page.content = new_wiki_content
wiki.pages << new_wiki_page wiki.pages << new_wiki_page
wiki_pages_map[page.id] = new_wiki_page
end
wiki.save
# Reproduce page hierarchy
project.wiki.pages.each do |page|
if page.parent_id && wiki_pages_map[page.id]
wiki_pages_map[page.id].parent = wiki_pages_map[page.parent_id]
wiki_pages_map[page.id].save
end
end end
end end
end end
+4
View File
@@ -210,6 +210,10 @@ class Query < ActiveRecord::Base
add_custom_fields_filters(@project.all_issue_custom_fields) add_custom_fields_filters(@project.all_issue_custom_fields)
else else
# global filters for cross project issue list # global filters for cross project issue list
system_shared_versions = Version.visible.find_all_by_sharing('system')
unless system_shared_versions.empty?
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
end
add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true}))
end end
@available_filters @available_filters
+17 -6
View File
@@ -136,6 +136,7 @@ class Repository < ActiveRecord::Base
end end
end end
@committers = nil @committers = nil
@found_committer_users = nil
true true
else else
false false
@@ -146,24 +147,34 @@ class Repository < ActiveRecord::Base
# It will return nil if the committer is not yet mapped and if no User # It will return nil if the committer is not yet mapped and if no User
# with the same username or email was found # with the same username or email was found
def find_committer_user(committer) def find_committer_user(committer)
if committer unless committer.blank?
@found_committer_users ||= {}
return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
user = nil
c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
if c && c.user if c && c.user
c.user user = c.user
elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
username, email = $1.strip, $3 username, email = $1.strip, $3
u = User.find_by_login(username) u = User.find_by_login(username)
u ||= User.find_by_mail(email) unless email.blank? u ||= User.find_by_mail(email) unless email.blank?
u user = u
end end
@found_committer_users[committer] = user
user
end end
end end
# fetch new changesets for all repositories # Fetches new changesets for all repositories of active projects
# can be called periodically by an external script # Can be called periodically by an external script
# eg. ruby script/runner "Repository.fetch_changesets" # eg. ruby script/runner "Repository.fetch_changesets"
def self.fetch_changesets def self.fetch_changesets
find(:all).each(&:fetch_changesets) Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
if project.repository
project.repository.fetch_changesets
end
end
end end
# scan changeset comments to find related and fixed issues for all repositories # scan changeset comments to find related and fixed issues for all repositories
+12 -9
View File
@@ -40,23 +40,26 @@ class Repository::Git < Repository
# With SCM's that have a sequential commit numbering, redmine is able to be # 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 # 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 # 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 # commits into the middle of the repository history, so we should parse
# parse the entire log. # the entire log. Since it's way too slow for large repositories, we only
# parse 1 week before the last known commit.
# The repository can still be fully reloaded by calling #clear_changesets
# before fetching changesets (eg. for offline resync)
def fetch_changesets def fetch_changesets
# Save ourselves an expensive operation if we're already up to date c = changesets.find(:first, :order => 'committed_on DESC')
return if scm.num_revisions == changesets.count since = (c ? c.committed_on - 7.days : nil)
revisions = scm.revisions('', nil, nil, :all => true) revisions = scm.revisions('', nil, nil, :all => true, :since => since)
return if revisions.nil? || revisions.empty? return if revisions.nil? || revisions.empty?
# Find revisions that redmine knows about already recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
existing_revisions = changesets.find(:all).map!{|c| c.scmid}
# Clean out revisions that are no longer in git # 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]) recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
# Subtract revisions that redmine already knows about # Subtract revisions that redmine already knows about
revisions.reject!{|r| existing_revisions.include?(r.scmid)} recent_revisions = recent_changesets.map{|c| c.scmid}
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
# Save the remaining ones to the database # Save the remaining ones to the database
revisions.each{|r| r.save(self)} unless revisions.nil? revisions.each{|r| r.save(self)} unless revisions.nil?
+1 -3
View File
@@ -86,7 +86,6 @@ top = headers_height + 8
<%= link_to_issue i %> <%= link_to_issue i %>
<% else %> <% else %>
<span class="icon icon-package"> <span class="icon icon-package">
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i %> <%= link_to_version i %>
</span> </span>
<% end %> <% end %>
@@ -211,8 +210,7 @@ top = headers_height + 10
%> %>
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div> <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task"> <div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
<%= h("#{i.project} -") unless @project && @project == i.project %> <strong><%= format_version_name i %></strong>
<strong><%=h i %></strong>
</div> </div>
<% end %> <% end %>
<% top = top + 20 <% top = top + 20
+8 -8
View File
@@ -1,14 +1,14 @@
<h1><%= link_to "#{issue.tracker.name} ##{issue.id}: #{issue.subject}", issue_url %></h1> <h1><%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %></h1>
<ul> <ul>
<li><%=l(:field_author)%>: <%= issue.author %></li> <li><%=l(:field_author)%>: <%=h issue.author %></li>
<li><%=l(:field_status)%>: <%= issue.status %></li> <li><%=l(:field_status)%>: <%=h issue.status %></li>
<li><%=l(:field_priority)%>: <%= issue.priority %></li> <li><%=l(:field_priority)%>: <%=h issue.priority %></li>
<li><%=l(:field_assigned_to)%>: <%= issue.assigned_to %></li> <li><%=l(:field_assigned_to)%>: <%=h issue.assigned_to %></li>
<li><%=l(:field_category)%>: <%= issue.category %></li> <li><%=l(:field_category)%>: <%=h issue.category %></li>
<li><%=l(:field_fixed_version)%>: <%= issue.fixed_version %></li> <li><%=l(:field_fixed_version)%>: <%=h issue.fixed_version %></li>
<% issue.custom_values.each do |c| %> <% issue.custom_values.each do |c| %>
<li><%= c.custom_field.name %>: <%= show_value(c) %></li> <li><%=h c.custom_field.name %>: <%=h show_value(c) %></li>
<% end %> <% end %>
</ul> </ul>
@@ -1,2 +1,2 @@
<p><%= l(:mail_body_account_activation_request, @user.login) %></p> <p><%= l(:mail_body_account_activation_request, h(@user.login)) %></p>
<p><%= link_to @url, @url %></p> <p><%= link_to @url, @url %></p>
@@ -1,10 +1,10 @@
<% if @user.auth_source %> <% if @user.auth_source %>
<p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p> <p><%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %></p>
<% else %> <% else %>
<p><%= l(:mail_body_account_information) %>:</p> <p><%= l(:mail_body_account_information) %>:</p>
<ul> <ul>
<li><%= l(:field_login) %>: <%= @user.login %></li> <li><%= l(:field_login) %>: <%=h @user.login %></li>
<li><%= l(:field_password) %>: <%= @password %></li> <li><%= l(:field_password) %>: <%=h @password %></li>
</ul> </ul>
<% end %> <% end %>
@@ -1,5 +1,5 @@
<%= link_to @added_to, @added_to_url %><br /> <%= link_to @added_to, @added_to_url %><br />
<ul><% @attachments.each do |attachment | %> <ul><% @attachments.each do |attachment | %>
<li><%= attachment.filename %></li> <li><%=h attachment.filename %></li>
<% end %></ul> <% end %></ul>
@@ -1,3 +1,3 @@
<%= link_to @document.title, @document_url %> (<%= @document.category.name %>)<br /> <%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)<br />
<br /> <br />
<%= textilizable(@document, :description, :only_path => false) %> <%= textilizable(@document, :description, :only_path => false) %>
+1 -1
View File
@@ -1,3 +1,3 @@
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %> <%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %>
<hr /> <hr />
<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> <%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %>
+1 -1
View File
@@ -1,4 +1,4 @@
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> <%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %>
<ul> <ul>
<% for detail in @journal.details %> <% for detail in @journal.details %>
@@ -1,4 +1,4 @@
<p><%= l(:mail_body_lost_password) %><br /> <p><%= l(:mail_body_lost_password) %><br />
<%= auto_link(@url) %></p> <%= auto_link(@url) %></p>
<p><%= l(:field_login) %>: <b><%= @token.user.login %></b></p> <p><%= l(:field_login) %>: <b><%=h @token.user.login %></b></p>
@@ -1,4 +1,4 @@
<h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to @message.subject, @message_url %></h1> <h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %></h1>
<em><%= @message.author %></em> <em><%=h @message.author %></em>
<%= textilizable(@message, :content, :only_path => false) %> <%= textilizable(@message, :content, :only_path => false) %>
+2 -2
View File
@@ -1,4 +1,4 @@
<h1><%= link_to @news.title, @news_url %></h1> <h1><%= link_to(h(@news.title), @news_url) %></h1>
<em><%= @news.author.name %></em> <em><%=h @news.author.name %></em>
<%= textilizable(@news, :description, :only_path => false) %> <%= textilizable(@news, :description, :only_path => false) %>
+1 -1
View File
@@ -9,7 +9,7 @@
<div class="splitcontentleft"> <div class="splitcontentleft">
<%= textilizable @project.description %> <%= textilizable @project.description %>
<ul> <ul>
<% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= link_to(h(@project.homepage), @project.homepage) %></li><% end %> <% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %></li><% end %>
<% if @subprojects.any? %> <% if @subprojects.any? %>
<li><%=l(:label_subproject_plural)%>: <li><%=l(:label_subproject_plural)%>:
<%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li> <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li>
+67 -1
View File
@@ -1,4 +1,70 @@
# Outgoing email settings # = Outgoing email settings
#
# Each environment has it's own configuration options. If you are only
# running in production, only the production block needs to be configured.
#
# == Common configurations
#
# === Sendmail command
#
# production:
# delivery_method: :sendmail
#
# === Simple SMTP server at localhost
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "localhost"
# port: 25
#
# === SMTP server at example.com using LOGIN authentication and checking HELO for foo.com
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "example.com"
# port: 25
# authentication: :login
# domain: 'foo.com'
# user_name: 'myaccount'
# password: 'password'
#
# === SMTP server at example.com using PLAIN authentication
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "example.com"
# port: 25
# authentication: :plain
# domain: 'example.com'
# user_name: 'myaccount'
# password: 'password'
#
# === SMTP server at using TLS (GMail)
#
# This requires some additional configuration. See the article at:
# http://redmineblog.com/articles/setup-redmine-to-send-email-using-gmail/
#
# production:
# delivery_method: :smtp
# smtp_settings:
# tls: true
# address: "smtp.gmail.com"
# port: 587
# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps
# authentication: :plain
# user_name: "your_email@gmail.com"
# password: "your_password"
#
#
# == More configuration options
#
# See the "Configuration options" at the following website for a list of the
# full options allowed:
#
# http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer
production: production:
delivery_method: :smtp delivery_method: :smtp
+1 -1
View File
@@ -25,5 +25,5 @@ config.action_controller.session = {
config.action_controller.allow_forgery_protection = false config.action_controller.allow_forgery_protection = false
config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com" config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
config.gem "nofxx-object_daddy", :lib => "object_daddy", :source => "http://gems.github.com" config.gem "edavis10-object_daddy", :lib => "object_daddy"
config.gem "mocha" config.gem "mocha"
@@ -0,0 +1,9 @@
class AddIndexOnChangesetsScmid < ActiveRecord::Migration
def self.up
add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid
end
def self.down
remove_index :changesets, :name => :changesets_repos_scmid
end
end
+20
View File
@@ -4,6 +4,26 @@ Redmine - project management software
Copyright (C) 2006-2010 Jean-Philippe Lang Copyright (C) 2006-2010 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2010-02-28 v0.9.3
Adds filter for system shared versions on the cross project issue list
Makes project identifiers searchable
Remove invalid utf8 sequences from commit comments and author name
Fixed: Wrong link when "http" not included in project "Homepage" link
Fixed: Escaping in html email templates
Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
Fixed: Deselecting textile text formatting causes interning empty string errors
Fixed: error with postgres when entering a non-numeric id for an issue relation
Fixed: div.task incorrectly wrapping on Gantt Chart
Fixed: Project copy loses wiki pages hierarchy
Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
Fixed: Duplicated project name for subproject version on gantt chart
Fixed: roadmap shows subprojects issues even if subprojects is unchecked
Fixed: IndexError if all the :last menu items are deleted from a menu
Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
== 2010-02-07 v0.9.2 == 2010-02-07 v0.9.2
* Fixed: Sub-project repository commits not displayed on parent project issues * Fixed: Sub-project repository commits not displayed on parent project issues
+11 -7
View File
@@ -7,7 +7,11 @@ http://www.redmine.org/
== Requirements == Requirements
* Ruby on Rails 2.3.5 * Ruby 1.8.6 or 1.8.7
* Ruby on Rails 2.3.5 (official downloadable Redmine releases are packaged with
the appropriate Rails version)
* A database: * A database:
* MySQL (tested with MySQL 5) * MySQL (tested with MySQL 5)
* PostgreSQL (tested with PostgreSQL 8.1) * PostgreSQL (tested with PostgreSQL 8.1)
@@ -26,15 +30,15 @@ Optional:
3. Configure database parameters in config/database.yml 3. Configure database parameters in config/database.yml
for "production" environment (default database is MySQL) for "production" environment (default database is MySQL)
4. Create the database structure. Under the application main directory: 4. Generate a session store secret
rake db:migrate RAILS_ENV="production"
It will create tables and an administrator account.
5. Generate a session store secret
Redmine stores session data in cookies by default, which requires Redmine stores session data in cookies by default, which requires
a secret to be generated. Run: a secret to be generated. Run:
rake config/initializers/session_store.rb rake config/initializers/session_store.rb
5. Create the database structure. Under the application main directory:
rake db:migrate RAILS_ENV="production"
It will create tables and an administrator account.
6. Setting up permissions 6. Setting up permissions
The user who runs Redmine must have write permission on the following The user who runs Redmine must have write permission on the following
subdirectories: files, log, tmp (create the last one if not present). subdirectories: files, log, tmp (create the last one if not present).
+7 -7
View File
@@ -13,17 +13,17 @@ http://www.redmine.org/
and SMTP settings (RAILS_ROOT/config/email.yml) and SMTP settings (RAILS_ROOT/config/email.yml)
into the new config directory into the new config directory
DO NOT REPLACE ANY OTHERS FILES. DO NOT REPLACE ANY OTHERS FILES.
3. Migrate your database (please make a backup before doing this):
rake db:migrate RAILS_ENV="production"
4. Copy the RAILS_ROOT/files directory content into your new installation 3. Generate a session store secret
This directory contains all the attached files
5. Generate a session store secret
Redmine stores session data in cookies by default, which requires Redmine stores session data in cookies by default, which requires
a secret to be generated. Run: a secret to be generated. Run:
rake config/initializers/session_store.rb rake config/initializers/session_store.rb
4. Migrate your database (please make a backup before doing this):
rake db:migrate RAILS_ENV="production"
5. Copy the RAILS_ROOT/files directory content into your new installation
This directory contains all the attached files
== Notes == Notes
+11 -2
View File
@@ -84,6 +84,14 @@ module TreeNodePatch
end end
# Wrapp remove! making sure to decrement the last_items counter if
# the removed child was a last item
def remove!(child)
@last_items_count -= +1 if child && child.last
super
end
# Will return the position (zero-based) of the current child in # Will return the position (zero-based) of the current child in
# it's parent # it's parent
def position def position
@@ -352,7 +360,7 @@ module Redmine
target_root.add(MenuItem.new(name, url, options)) target_root.add(MenuItem.new(name, url, options))
end end
elsif options.delete(:last) elsif options[:last] # don't delete, needs to be stored
target_root.add_last(MenuItem.new(name, url, options)) target_root.add_last(MenuItem.new(name, url, options))
else else
target_root.add(MenuItem.new(name, url, options)) target_root.add(MenuItem.new(name, url, options))
@@ -386,7 +394,7 @@ module Redmine
class MenuItem < Tree::TreeNode class MenuItem < Tree::TreeNode
include Redmine::I18n include Redmine::I18n
attr_reader :name, :url, :param, :condition, :parent, :child_menus attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last
def initialize(name, url, options) def initialize(name, url, options)
raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
@@ -403,6 +411,7 @@ module Redmine
@html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
@parent = options[:parent] @parent = options[:parent]
@child_menus = options[:children] @child_menus = options[:children]
@last = options[:last] || false
super @name.to_sym super @name.to_sym
end end
+11 -9
View File
@@ -286,21 +286,23 @@ module Redmine
end end
def save(repo) def save(repo)
if repo.changesets.find_by_scmid(scmid.to_s).nil? Changeset.transaction do
changeset = Changeset.create!( changeset = Changeset.new(
:repository => repo, :repository => repo,
:revision => identifier, :revision => identifier,
:scmid => scmid, :scmid => scmid,
:committer => author, :committer => author,
:committed_on => time, :committed_on => time,
:comments => message) :comments => message)
paths.each do |file| if changeset.save
Change.create!( paths.each do |file|
:changeset => changeset, Change.create(
:action => file[:action], :changeset => changeset,
:path => file[:path]) :action => file[:action],
end :path => file[:path])
end
end
end end
end end
end end
+8 -11
View File
@@ -33,21 +33,22 @@ module Redmine
end end
def branches def branches
branches = [] return @branches if @branches
@branches = []
cmd = "#{GIT_BIN} --git-dir #{target('')} branch" cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
branches << line.match('\s*\*?\s*(.*)$')[1] @branches << line.match('\s*\*?\s*(.*)$')[1]
end end
end end
branches.sort! @branches.sort!
end end
def tags def tags
tags = [] return @tags if @tags
cmd = "#{GIT_BIN} --git-dir #{target('')} tag" cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
shellout(cmd) do |io| shellout(cmd) do |io|
io.readlines.sort!.map{|t| t.strip} @tags = io.readlines.sort!.map{|t| t.strip}
end end
end end
@@ -110,20 +111,16 @@ module Redmine
end end
end end
def num_revisions
cmd = "#{GIT_BIN} --git-dir #{target('')} log --all --pretty=format:'' | wc -l"
shellout(cmd) {|io| io.gets.chomp.to_i + 1}
end
def revisions(path, identifier_from, identifier_to, options={}) def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --find-copies-harder --raw --date=iso --pretty=fuller" cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
cmd << " --reverse" if options[:reverse] cmd << " --reverse" if options[:reverse]
cmd << " --all" if options[:all] cmd << " --all" if options[:all]
cmd << " -n #{options[:limit]} " if options[:limit] cmd << " -n #{options[:limit]} " if options[:limit]
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
cmd << " #{shell_quote identifier_to} " if identifier_to cmd << " #{shell_quote identifier_to} " if identifier_to
cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
cmd << " -- #{path}" if path && !path.empty? cmd << " -- #{path}" if path && !path.empty?
shellout(cmd) do |io| shellout(cmd) do |io|
+1 -1
View File
@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 0 MAJOR = 0
MINOR = 9 MINOR = 9
TINY = 2 TINY = 3
# Branch values: # Branch values:
# * official release: nil # * official release: nil
+4 -4
View File
@@ -25,17 +25,17 @@ module Redmine
end end
def register(name, formatter, helper) def register(name, formatter, helper)
raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_sym] raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s]
@@formatters[name.to_sym] = {:formatter => formatter, :helper => helper} @@formatters[name.to_s] = {:formatter => formatter, :helper => helper}
end end
def formatter_for(name) def formatter_for(name)
entry = @@formatters[name.to_sym] entry = @@formatters[name.to_s]
(entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter
end end
def helper_for(name) def helper_for(name)
entry = @@formatters[name.to_sym] entry = @@formatters[name.to_s]
(entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper
end end
+1
View File
@@ -728,6 +728,7 @@ background-image:url('../images/close_hl.png');
padding:0; padding:0;
margin:0; margin:0;
line-height:0.8em; line-height:0.8em;
white-space:nowrap;
} }
.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
+5
View File
@@ -1,6 +1,7 @@
class Issue < ActiveRecord::Base class Issue < ActiveRecord::Base
generator_for :subject, :method => :next_subject generator_for :subject, :method => :next_subject
generator_for :author, :method => :next_author generator_for :author, :method => :next_author
generator_for :priority, :method => :fetch_priority
def self.next_subject def self.next_subject
@last_subject ||= 'Subject 0' @last_subject ||= 'Subject 0'
@@ -12,4 +13,8 @@ class Issue < ActiveRecord::Base
User.generate_with_protected! User.generate_with_protected!
end end
def self.fetch_priority
IssuePriority.first || IssuePriority.generate!
end
end end
+1
View File
@@ -0,0 +1 @@
Texte encodé en ISO-8859-1.
+24
View File
@@ -71,4 +71,28 @@ wiki_contents_006:
version: 1 version: 1
author_id: 1 author_id: 1
comments: comments:
wiki_contents_007:
text: This is a child page
updated_on: 2007-03-08 00:18:07 +01:00
page_id: 7
id: 7
version: 1
author_id: 1
comments:
wiki_contents_008:
text: This is a parent page
updated_on: 2007-03-08 00:18:07 +01:00
page_id: 8
id: 8
version: 1
author_id: 1
comments:
wiki_contents_009:
text: This is a child page
updated_on: 2007-03-08 00:18:07 +01:00
page_id: 9
id: 9
version: 1
author_id: 1
comments:
+21
View File
@@ -41,4 +41,25 @@ wiki_pages_006:
wiki_id: 1 wiki_id: 1
protected: false protected: false
parent_id: 2 parent_id: 2
wiki_pages_007:
created_on: 2007-03-08 00:18:07 +01:00
title: Child_page_1
id: 7
wiki_id: 2
protected: false
parent_id: 8
wiki_pages_008:
created_on: 2007-03-08 00:18:07 +01:00
title: Parent_page
id: 8
wiki_id: 2
protected: false
parent_id:
wiki_pages_009:
created_on: 2007-03-08 00:18:07 +01:00
title: Child_page_2
id: 9
wiki_id: 2
protected: false
parent_id: 8
@@ -40,6 +40,24 @@ class IssueRelationsControllerTest < ActionController::TestCase
end end
end end
def test_new_should_accept_id_with_hash
assert_difference 'IssueRelation.count' do
@request.session[:user_id] = 3
post :new, :issue_id => 1,
:relation => {:issue_to_id => '#2', :relation_type => 'relates', :delay => ''}
end
end
def test_new_should_not_break_with_non_numerical_id
assert_no_difference 'IssueRelation.count' do
assert_nothing_raised do
@request.session[:user_id] = 3
post :new, :issue_id => 1,
:relation => {:issue_to_id => 'foo', :relation_type => 'relates', :delay => ''}
end
end
end
def test_should_create_relations_with_visible_issues_only def test_should_create_relations_with_visible_issues_only
Setting.cross_project_issue_relations = '1' Setting.cross_project_issue_relations = '1'
assert_nil Issue.visible(User.find(3)).find_by_id(4) assert_nil Issue.visible(User.find(3)).find_by_id(4)
+5 -19
View File
@@ -1,30 +1,16 @@
module ObjectDaddyHelpers module ObjectDaddyHelpers
# TODO: The gem or official version of ObjectDaddy doesn't set # TODO: Remove these three once everyone has ported their code to use the
# protected attributes so they need to be wrapped. # new object_daddy version with protected attribute support
def User.generate_with_protected(attributes={}) def User.generate_with_protected(attributes={})
user = User.spawn_with_protected(attributes) User.generate(attributes)
user.save
user
end end
# TODO: The gem or official version of ObjectDaddy doesn't set
# protected attributes so they need to be wrapped.
def User.generate_with_protected!(attributes={}) def User.generate_with_protected!(attributes={})
user = User.spawn_with_protected(attributes) User.generate!(attributes)
user.save!
user
end end
# TODO: The gem or official version of ObjectDaddy doesn't set
# protected attributes so they need to be wrapped.
def User.spawn_with_protected(attributes={}) def User.spawn_with_protected(attributes={})
user = User.spawn(attributes) do |user| User.spawn(attributes)
user.login = User.next_login
attributes.each do |attr,v|
user.send("#{attr}=", v)
end
end
user
end end
# Generate the default Query # Generate the default Query
+18 -2
View File
@@ -1,5 +1,7 @@
# redMine - project management software # encoding: utf-8
# Copyright (C) 2006-2007 Jean-Philippe Lang #
# Redmine - project management software
# Copyright (C) 2006-2010 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -117,4 +119,18 @@ class ChangesetTest < ActiveSupport::TestCase
changeset = Changeset.find_by_revision('10') changeset = Changeset.find_by_revision('10')
assert_nil changeset.next assert_nil changeset.next
end end
def test_comments_should_be_converted_to_utf8
with_settings :commit_logs_encoding => 'ISO-8859-1' do
c = Changeset.new
c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
assert_equal "Texte encodé en ISO-8859-1.", c.comments
end
end
def test_invalid_utf8_sequences_in_comments_should_be_stripped
c = Changeset.new
c.comments = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
assert_equal "Texte encod en ISO-8859-1.", c.comments
end
end end
@@ -193,6 +193,8 @@ RAW
'!version:1.0' => 'version:1.0', '!version:1.0' => 'version:1.0',
'!version:"1.0"' => 'version:"1.0"', '!version:"1.0"' => 'version:"1.0"',
'!source:/some/file' => 'source:/some/file', '!source:/some/file' => 'source:/some/file',
# not found
'#0123456789' => '#0123456789',
# invalid expressions # invalid expressions
'source:' => 'source:', 'source:' => 'source:',
# url hash # url hash
@@ -17,7 +17,7 @@
require File.dirname(__FILE__) + '/../../../../test_helper' require File.dirname(__FILE__) + '/../../../../test_helper'
class Redmine::MenuManager::MapperTest < Test::Unit::TestCase class Redmine::MenuManager::MapperTest < ActiveSupport::TestCase
context "Mapper#initialize" do context "Mapper#initialize" do
should "be tested" should "be tested"
end end
@@ -163,4 +163,21 @@ class Redmine::MenuManager::MapperTest < Test::Unit::TestCase
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
assert_nil menu_mapper.delete(:test_missing) assert_nil menu_mapper.delete(:test_missing)
end end
test 'deleting all items' do
# Exposed by deleting :last items
Redmine::MenuManager.map :test_menu do |menu|
menu.push :not_last, Redmine::Info.help_url
menu.push :administration, { :controller => 'projects', :action => 'show'}, {:last => true}
menu.push :help, Redmine::Info.help_url, :last => true
end
assert_nothing_raised do
Redmine::MenuManager.map :test_menu do |menu|
menu.delete(:administration)
menu.delete(:help)
menu.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
end
end
end
end end
+10
View File
@@ -19,6 +19,16 @@ require File.dirname(__FILE__) + '/../../../test_helper'
class Redmine::WikiFormattingTest < ActiveSupport::TestCase class Redmine::WikiFormattingTest < ActiveSupport::TestCase
def test_textile_formatter
assert_equal Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting.formatter_for('textile')
assert_equal Redmine::WikiFormatting::Textile::Helper, Redmine::WikiFormatting.helper_for('textile')
end
def test_null_formatter
assert_equal Redmine::WikiFormatting::NullFormatter::Formatter, Redmine::WikiFormatting.formatter_for('')
assert_equal Redmine::WikiFormatting::NullFormatter::Helper, Redmine::WikiFormatting.helper_for('')
end
def test_should_link_urls_and_email_addresses def test_should_link_urls_and_email_addresses
raw = <<-DIFF raw = <<-DIFF
This is a sample *text* with a link: http://www.redmine.org This is a sample *text* with a link: http://www.redmine.org
+55 -5
View File
@@ -285,6 +285,48 @@ class ProjectTest < ActiveSupport::TestCase
assert Project.new.allowed_parents.compact.empty? assert Project.new.allowed_parents.compact.empty?
end end
def test_allowed_parents_with_add_subprojects_permission
Role.find(1).remove_permission!(:add_project)
Role.find(1).add_permission!(:add_subprojects)
User.current = User.find(2)
# new project
assert !Project.new.allowed_parents.include?(nil)
assert Project.new.allowed_parents.include?(Project.find(1))
# existing root project
assert Project.find(1).allowed_parents.include?(nil)
# existing child
assert Project.find(3).allowed_parents.include?(Project.find(1))
assert !Project.find(3).allowed_parents.include?(nil)
end
def test_allowed_parents_with_add_project_permission
Role.find(1).add_permission!(:add_project)
Role.find(1).remove_permission!(:add_subprojects)
User.current = User.find(2)
# new project
assert Project.new.allowed_parents.include?(nil)
assert !Project.new.allowed_parents.include?(Project.find(1))
# existing root project
assert Project.find(1).allowed_parents.include?(nil)
# existing child
assert Project.find(3).allowed_parents.include?(Project.find(1))
assert Project.find(3).allowed_parents.include?(nil)
end
def test_allowed_parents_with_add_project_and_subprojects_permission
Role.find(1).add_permission!(:add_project)
Role.find(1).add_permission!(:add_subprojects)
User.current = User.find(2)
# new project
assert Project.new.allowed_parents.include?(nil)
assert Project.new.allowed_parents.include?(Project.find(1))
# existing root project
assert Project.find(1).allowed_parents.include?(nil)
# existing child
assert Project.find(3).allowed_parents.include?(Project.find(1))
assert Project.find(3).allowed_parents.include?(nil)
end
def test_users_by_role def test_users_by_role
users_by_role = Project.find(1).users_by_role users_by_role = Project.find(1).users_by_role
assert_kind_of Hash, users_by_role assert_kind_of Hash, users_by_role
@@ -555,7 +597,7 @@ class ProjectTest < ActiveSupport::TestCase
end end
should "copy issues" do should "copy issues" do
@source_project.issues << Issue.generate!(:status_id => 5, @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'),
:subject => "copy issue status", :subject => "copy issue status",
:tracker_id => 1, :tracker_id => 1,
:assigned_to_id => 2, :assigned_to_id => 2,
@@ -681,16 +723,24 @@ class ProjectTest < ActiveSupport::TestCase
assert_equal "Start page", @project.wiki.start_page assert_equal "Start page", @project.wiki.start_page
end end
should "copy wiki pages and content" do should "copy wiki pages and content with hierarchy" do
assert @project.copy(@source_project) assert_difference 'WikiPage.count', @source_project.wiki.pages.size do
assert @project.copy(@source_project)
end
assert @project.wiki assert @project.wiki
assert_equal 1, @project.wiki.pages.length assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size
@project.wiki.pages.each do |wiki_page| @project.wiki.pages.each do |wiki_page|
assert wiki_page.content assert wiki_page.content
assert !@source_project.wiki.pages.include?(wiki_page) assert !@source_project.wiki.pages.include?(wiki_page)
end end
parent = @project.wiki.find_page('Parent_page')
child1 = @project.wiki.find_page('Child_page_1')
child2 = @project.wiki.find_page('Child_page_2')
assert_equal parent, child1.parent
assert_equal parent, child2.parent
end end
should "copy issue categories" do should "copy issue categories" do
+7
View File
@@ -26,6 +26,13 @@ class QueryTest < ActiveSupport::TestCase
assert !query.available_filters.has_key?('cf_3') assert !query.available_filters.has_key?('cf_3')
end end
def test_system_shared_versions_should_be_available_in_global_queries
Version.find(2).update_attribute :sharing, 'system'
query = Query.new(:project => nil, :name => '_')
assert query.available_filters.has_key?('fixed_version_id')
assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
end
def find_issues_with_query(query) def find_issues_with_query(query)
Issue.find :all, Issue.find :all,
:include => [ :assigned_to, :status, :tracker, :project, :priority ], :include => [ :assigned_to, :status, :tracker, :project, :priority ],
+1 -1
View File
@@ -35,7 +35,7 @@ class RepositoryGitTest < ActiveSupport::TestCase
@repository.reload @repository.reload
assert_equal 12, @repository.changesets.count assert_equal 12, @repository.changesets.count
assert_equal 20, @repository.changes.count assert_equal 21, @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