Merge branch 'release-v1.2.0' into stable
This commit is contained in:
commit
78cee48c2d
|
@ -1,3 +1,5 @@
|
||||||
|
/.project
|
||||||
|
/.loadpath
|
||||||
/config/additional_environment.rb
|
/config/additional_environment.rb
|
||||||
/config/configuration.yml
|
/config/configuration.yml
|
||||||
/config/database.yml
|
/config/database.yml
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
syntax: glob
|
syntax: glob
|
||||||
|
|
||||||
|
.project
|
||||||
|
.loadpath
|
||||||
config/additional_environment.rb
|
config/additional_environment.rb
|
||||||
config/configuration.yml
|
config/configuration.yml
|
||||||
config/database.yml
|
config/database.yml
|
||||||
|
|
|
@ -129,7 +129,7 @@ class AccountController < ApplicationController
|
||||||
|
|
||||||
def logout_user
|
def logout_user
|
||||||
if User.current.logged?
|
if User.current.logged?
|
||||||
cookies.delete :autologin
|
cookies.delete Redmine::Configuration['autologin_cookie_name']
|
||||||
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
|
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
|
||||||
self.logged_user = nil
|
self.logged_user = nil
|
||||||
end
|
end
|
||||||
|
@ -211,15 +211,14 @@ class AccountController < ApplicationController
|
||||||
|
|
||||||
def set_autologin_cookie(user)
|
def set_autologin_cookie(user)
|
||||||
token = Token.create(:user => user, :action => 'autologin')
|
token = Token.create(:user => user, :action => 'autologin')
|
||||||
cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
|
|
||||||
cookie_options = {
|
cookie_options = {
|
||||||
:value => token.value,
|
:value => token.value,
|
||||||
:expires => 1.year.from_now,
|
:expires => 1.year.from_now,
|
||||||
:path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
|
:path => Redmine::Configuration['autologin_cookie_path'],
|
||||||
:secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
|
:secure => Redmine::Configuration['autologin_cookie_secure'],
|
||||||
:httponly => true
|
:httponly => true
|
||||||
}
|
}
|
||||||
cookies[cookie_name] = cookie_options
|
cookies[Redmine::Configuration['autologin_cookie_name']] = cookie_options
|
||||||
end
|
end
|
||||||
|
|
||||||
# Onthefly creation failed, display the registration form to fill/fix attributes
|
# Onthefly creation failed, display the registration form to fill/fix attributes
|
||||||
|
|
|
@ -19,6 +19,9 @@ require 'uri'
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
include Redmine::I18n
|
include Redmine::I18n
|
||||||
|
|
||||||
layout 'base'
|
layout 'base'
|
||||||
|
@ -63,9 +66,9 @@ class ApplicationController < ActionController::Base
|
||||||
if session[:user_id]
|
if session[:user_id]
|
||||||
# existing session
|
# existing session
|
||||||
(User.active.find(session[:user_id]) rescue nil)
|
(User.active.find(session[:user_id]) rescue nil)
|
||||||
elsif cookies[:autologin] && Setting.autologin?
|
elsif cookies[Redmine::Configuration['autologin_cookie_name']] && Setting.autologin?
|
||||||
# auto-login feature starts a new session
|
# auto-login feature starts a new session
|
||||||
user = User.try_to_autologin(cookies[:autologin])
|
user = User.try_to_autologin(cookies[Redmine::Configuration['autologin_cookie_name']])
|
||||||
session[:user_id] = user.id if user
|
session[:user_id] = user.id if user
|
||||||
user
|
user
|
||||||
elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
|
elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
|
||||||
|
|
|
@ -9,7 +9,10 @@ class AutoCompletesController < ApplicationController
|
||||||
@issues << query.visible.find_by_id(q.to_i)
|
@issues << query.visible.find_by_id(q.to_i)
|
||||||
end
|
end
|
||||||
unless q.blank?
|
unless q.blank?
|
||||||
@issues += query.visible.find(:all, :conditions => ["LOWER(#{Issue.table_name}.subject) LIKE ?", "%#{q.downcase}%"], :limit => 10)
|
@issues += query.visible.find(:all,
|
||||||
|
:limit => 10,
|
||||||
|
:order => "#{Issue.table_name}.id ASC",
|
||||||
|
:conditions => ["LOWER(#{Issue.table_name}.subject) LIKE :q OR CAST(#{Issue.table_name}.id AS CHAR(13)) LIKE :q", {:q => "%#{q.downcase}%" }])
|
||||||
end
|
end
|
||||||
@issues.compact!
|
@issues.compact!
|
||||||
render :layout => false
|
render :layout => false
|
||||||
|
|
|
@ -27,6 +27,7 @@ class JournalsController < ApplicationController
|
||||||
include QueriesHelper
|
include QueriesHelper
|
||||||
helper :sort
|
helper :sort
|
||||||
include SortHelper
|
include SortHelper
|
||||||
|
helper :custom_fields
|
||||||
|
|
||||||
def index
|
def index
|
||||||
retrieve_query
|
retrieve_query
|
||||||
|
|
|
@ -100,12 +100,12 @@ class RepositoriesController < ApplicationController
|
||||||
def revisions
|
def revisions
|
||||||
@changeset_count = @repository.changesets.count
|
@changeset_count = @repository.changesets.count
|
||||||
@changeset_pages = Paginator.new self, @changeset_count,
|
@changeset_pages = Paginator.new self, @changeset_count,
|
||||||
per_page_option,
|
per_page_option,
|
||||||
params['page']
|
params['page']
|
||||||
@changesets = @repository.changesets.find(:all,
|
@changesets = @repository.changesets.find(:all,
|
||||||
:limit => @changeset_pages.items_per_page,
|
:limit => @changeset_pages.items_per_page,
|
||||||
:offset => @changeset_pages.current.offset,
|
:offset => @changeset_pages.current.offset,
|
||||||
:include => [:user, :repository])
|
:include => [:user, :repository])
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render :layout => false if request.xhr? }
|
format.html { render :layout => false if request.xhr? }
|
||||||
|
@ -122,9 +122,10 @@ class RepositoriesController < ApplicationController
|
||||||
|
|
||||||
@content = @repository.cat(@path, @rev)
|
@content = @repository.cat(@path, @rev)
|
||||||
(show_error_not_found; return) unless @content
|
(show_error_not_found; return) unless @content
|
||||||
if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
|
if 'raw' == params[:format] || @content.is_binary_data? ||
|
||||||
|
(@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
|
||||||
# Force the download
|
# Force the download
|
||||||
send_data @content, :filename => @path.split('/').last
|
send_data @content, :filename => filename_for_content_disposition(@path.split('/').last)
|
||||||
else
|
else
|
||||||
# Prevent empty lines when displaying a file with Windows style eol
|
# Prevent empty lines when displaying a file with Windows style eol
|
||||||
@content.gsub!("\r\n", "\n")
|
@content.gsub!("\r\n", "\n")
|
||||||
|
|
|
@ -92,7 +92,7 @@ class UsersController < ApplicationController
|
||||||
@user.safe_attributes = params[:user]
|
@user.safe_attributes = params[:user]
|
||||||
@user.admin = params[:user][:admin] || false
|
@user.admin = params[:user][:admin] || false
|
||||||
@user.login = params[:user][:login]
|
@user.login = params[:user][:login]
|
||||||
@user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
|
@user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] if @user.change_password_allowed?
|
||||||
|
|
||||||
# TODO: Similar to My#account
|
# TODO: Similar to My#account
|
||||||
@user.pref.attributes = params[:pref]
|
@user.pref.attributes = params[:pref]
|
||||||
|
@ -135,10 +135,10 @@ class UsersController < ApplicationController
|
||||||
def update
|
def update
|
||||||
@user.admin = params[:user][:admin] if params[:user][:admin]
|
@user.admin = params[:user][:admin] if params[:user][:admin]
|
||||||
@user.login = params[:user][:login] if params[:user][:login]
|
@user.login = params[:user][:login] if params[:user][:login]
|
||||||
if params[:user][:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?)
|
@user.safe_attributes = params[:user]
|
||||||
|
if params[:user][:password].present? && @user.change_password_allowed?
|
||||||
@user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
|
@user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
|
||||||
end
|
end
|
||||||
@user.safe_attributes = params[:user]
|
|
||||||
# Was the account actived ? (do it before User#save clears the change)
|
# Was the account actived ? (do it before User#save clears the change)
|
||||||
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
|
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
|
||||||
# TODO: Similar to My#account
|
# TODO: Similar to My#account
|
||||||
|
@ -151,7 +151,7 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
if was_activated
|
if was_activated
|
||||||
Mailer.deliver_account_activated(@user)
|
Mailer.deliver_account_activated(@user)
|
||||||
elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil?
|
elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.change_password_allowed?
|
||||||
Mailer.deliver_account_information(@user, params[:user][:password])
|
Mailer.deliver_account_information(@user, params[:user][:password])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -172,27 +172,27 @@ module RepositoriesHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def darcs_field_tags(form, repository)
|
def darcs_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
content_tag('p', form.text_field(:url, :label => :label_darcs_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def mercurial_field_tags(form, repository)
|
def mercurial_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
content_tag('p', form.text_field(:url, :label => :label_mercurial_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def git_field_tags(form, repository)
|
def git_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :label => 'Path to .git directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
content_tag('p', form.text_field(:url, :label => :label_git_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def cvs_field_tags(form, repository)
|
def cvs_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) +
|
content_tag('p', form.text_field(:root_url, :label => :label_cvs_path, :size => 60, :required => true, :disabled => !repository.new_record?)) +
|
||||||
content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?))
|
content_tag('p', form.text_field(:url, :label => :label_cvs_module, :size => 30, :required => true, :disabled => !repository.new_record?))
|
||||||
end
|
end
|
||||||
|
|
||||||
def bazaar_field_tags(form, repository)
|
def bazaar_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
content_tag('p', form.text_field(:url, :label => :label_bazaar_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def filesystem_field_tags(form, repository)
|
def filesystem_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
content_tag('p', form.text_field(:url, :label => :label_filesystem_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -566,9 +566,19 @@ class Query < ActiveRecord::Base
|
||||||
sql = ''
|
sql = ''
|
||||||
case operator
|
case operator
|
||||||
when "="
|
when "="
|
||||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
if value.present?
|
||||||
|
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
||||||
|
else
|
||||||
|
# empty set of allowed values produces no result
|
||||||
|
sql = "0=1"
|
||||||
|
end
|
||||||
when "!"
|
when "!"
|
||||||
sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
|
if value.present?
|
||||||
|
sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
|
||||||
|
else
|
||||||
|
# empty set of forbidden values allows all results
|
||||||
|
sql = "1=1"
|
||||||
|
end
|
||||||
when "!*"
|
when "!*"
|
||||||
sql = "#{db_table}.#{db_field} IS NULL"
|
sql = "#{db_table}.#{db_field} IS NULL"
|
||||||
sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
|
sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<%= render :partial => 'action_menu' %>
|
<%= render :partial => 'action_menu' %>
|
||||||
|
|
||||||
<h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
|
<h2><%= @issue.tracker.name %> #<%= @issue.id %><%= call_hook(:view_issues_show_identifier, :issue => @issue) %></h2>
|
||||||
|
|
||||||
<div class="<%= @issue.css_classes %> details">
|
<div class="<%= @issue.css_classes %> details">
|
||||||
<%= avatar(@issue.author, :size => "50") %>
|
<%= avatar(@issue.author, :size => "50") %>
|
||||||
|
|
|
@ -26,7 +26,9 @@ hr {
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<span class="header"><%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header) %></span>
|
<span class="header"><%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header) %></span>
|
||||||
|
<%= call_hook(:view_layouts_mailer_html_before_content, self.assigns) %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
|
<%= call_hook(:view_layouts_mailer_html_after_content, self.assigns) %>
|
||||||
<hr />
|
<hr />
|
||||||
<span class="footer"><%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer) %></span>
|
<span class="footer"><%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer) %></span>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<%= Setting.emails_header %>
|
<%= Setting.emails_header %>
|
||||||
|
<%= call_hook(:view_layouts_mailer_plain_before_content, self.assigns) %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
|
<%= call_hook(:view_layouts_mailer_plain_after_content, self.assigns) %>
|
||||||
--
|
--
|
||||||
<%= Setting.emails_footer %>
|
<%= Setting.emails_footer %>
|
||||||
|
|
|
@ -67,8 +67,13 @@
|
||||||
<% if @total_hours && User.current.allowed_to?(:view_time_entries, @project) %>
|
<% if @total_hours && User.current.allowed_to?(:view_time_entries, @project) %>
|
||||||
<h3><%= l(:label_spent_time) %></h3>
|
<h3><%= l(:label_spent_time) %></h3>
|
||||||
<p><span class="icon icon-time"><%= l_hours(@total_hours) %></span></p>
|
<p><span class="icon icon-time"><%= l_hours(@total_hours) %></span></p>
|
||||||
<p><%= link_to(l(:label_details), {:controller => 'timelog', :action => 'index', :project_id => @project}) %> |
|
<p>
|
||||||
<%= link_to(l(:label_report), {:controller => 'time_entry_reports', :action => 'report', :project_id => @project}) %></p>
|
<%= link_to(l(:label_details), {:controller => 'timelog', :action => 'index', :project_id => @project}) %> |
|
||||||
|
<%= link_to(l(:label_report), {:controller => 'time_entry_reports', :action => 'report', :project_id => @project}) %>
|
||||||
|
<% if authorize_for('timelog', 'new') %>
|
||||||
|
| <%= link_to l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project} %>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %>
|
<%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<p><%= setting_check_box :gravatar_enabled %></p>
|
<p><%= setting_check_box :gravatar_enabled %></p>
|
||||||
|
|
||||||
<p><%= setting_select :gravatar_default, [["Wavatars", 'wavatar'], ["Identicons", 'identicon'], ["Monster ids", 'monsterid']], :blank => :label_none %></p>
|
<p><%= setting_select :gravatar_default, [["Wavatars", 'wavatar'], ["Identicons", 'identicon'], ["Monster ids", 'monsterid'], ["Retro", "retro"]], :blank => :label_none %></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
|
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
|
||||||
<ul>
|
<ul>
|
||||||
<% @issues.each do |issue| -%>
|
<% @issues.each do |issue| -%>
|
||||||
<li><%= link_to_issue(issue) %></li>
|
<li><%= link_to_issue(issue, :project => issue.project != @version.project) %></li>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
</ul>
|
</ul>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -158,5 +158,8 @@ module Rails
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# working around deprecation in RubyGems 1.6
|
||||||
|
require 'thread'
|
||||||
|
|
||||||
# All that for this:
|
# All that for this:
|
||||||
Rails.boot!
|
Rails.boot!
|
||||||
|
|
|
@ -99,6 +99,18 @@ default:
|
||||||
# attachments_storage_path: D:/chiliproject/files
|
# attachments_storage_path: D:/chiliproject/files
|
||||||
attachments_storage_path:
|
attachments_storage_path:
|
||||||
|
|
||||||
|
# Path to the directories where themes are stored.
|
||||||
|
# Can be an absolute path or one relative to your ChiliProject instance.
|
||||||
|
# You can configure multiple paths.
|
||||||
|
# The default is the 'public/themes' directory in your ChiliProject instance.
|
||||||
|
# Examples:
|
||||||
|
# themes_storage_paths: public/themes
|
||||||
|
# themes_storage_paths:
|
||||||
|
# - public/themes
|
||||||
|
# - /opt/themes
|
||||||
|
# - D:/chiliproject/themes
|
||||||
|
themes_storage_path:
|
||||||
|
|
||||||
# Configuration of the autologin cookie.
|
# Configuration of the autologin cookie.
|
||||||
# autologin_cookie_name: the name of the cookie (default: autologin)
|
# autologin_cookie_name: the name of the cookie (default: autologin)
|
||||||
# autologin_cookie_path: the cookie path (default: /)
|
# autologin_cookie_path: the cookie path (default: /)
|
||||||
|
|
|
@ -86,7 +86,7 @@ module I18n
|
||||||
module Base
|
module Base
|
||||||
def warn_syntax_deprecation!(*args)
|
def warn_syntax_deprecation!(*args)
|
||||||
return if @skip_syntax_deprecation
|
return if @skip_syntax_deprecation
|
||||||
warn "The {{key}} interpolation syntax in I18n messages is deprecated and will be removed in Redmine 1.2. Please use %{key} instead, see http://www.redmine.org/issues/7013 for more information."
|
ActiveSupport::Deprecation.warn "The {{key}} interpolation syntax in I18n messages is deprecated and will be removed in ChiliProject 2.0. Please use %{key} instead. See the notice at https://www.chiliproject.org/boards/2/topics/243 for more information."
|
||||||
@skip_syntax_deprecation = true
|
@skip_syntax_deprecation = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -939,3 +939,10 @@ bg:
|
||||||
enumeration_system_activity: Системна активност
|
enumeration_system_activity: Системна активност
|
||||||
|
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -953,3 +953,10 @@ bs:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -942,3 +942,10 @@ ca:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -939,3 +939,10 @@ cs:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -955,3 +955,10 @@ da:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -956,3 +956,10 @@ de:
|
||||||
notice_gantt_chart_truncated: Die Grafik ist unvollständig, da das Maximum der anzeigbaren Aufgaben überschritten wurde (%{max})
|
notice_gantt_chart_truncated: Die Grafik ist unvollständig, da das Maximum der anzeigbaren Aufgaben überschritten wurde (%{max})
|
||||||
setting_gantt_items_limit: Maximale Anzahl von Aufgaben die im Gantt-Chart angezeigt werden.
|
setting_gantt_items_limit: Maximale Anzahl von Aufgaben die im Gantt-Chart angezeigt werden.
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -939,3 +939,10 @@ el:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -943,3 +943,10 @@ en-GB:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: "Powered by %{link}"
|
text_powered_by: "Powered by %{link}"
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -793,6 +793,13 @@ en:
|
||||||
label_project_copy_notifications: Send email notifications during the project copy
|
label_project_copy_notifications: Send email notifications during the project copy
|
||||||
label_principal_search: "Search for user or group:"
|
label_principal_search: "Search for user or group:"
|
||||||
label_user_search: "Search for user:"
|
label_user_search: "Search for user:"
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
|
||||||
button_login: Login
|
button_login: Login
|
||||||
button_submit: Submit
|
button_submit: Submit
|
||||||
|
|
|
@ -976,3 +976,10 @@ es:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -943,3 +943,10 @@ eu:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -960,3 +960,10 @@ fi:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -957,3 +957,10 @@ fr:
|
||||||
field_assigned_to_role: Rôle de l'assigné
|
field_assigned_to_role: Rôle de l'assigné
|
||||||
setting_emails_header: Emails header
|
setting_emails_header: Emails header
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -951,3 +951,10 @@ gl:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -944,3 +944,10 @@ he:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -946,3 +946,10 @@ hr:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -958,3 +958,10 @@
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -947,3 +947,10 @@ id:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -940,3 +940,10 @@ it:
|
||||||
notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare
|
notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare
|
||||||
setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt
|
setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -960,3 +960,10 @@ ja:
|
||||||
enumeration_activities: 作業分類 (時間トラッキング)
|
enumeration_activities: 作業分類 (時間トラッキング)
|
||||||
enumeration_system_activity: システム作業分類
|
enumeration_system_activity: システム作業分類
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -991,3 +991,10 @@ ko:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -999,3 +999,10 @@ lt:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -934,3 +934,10 @@ lv:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -939,3 +939,10 @@ mk:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -940,3 +940,10 @@ mn:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -921,3 +921,10 @@ nl:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -926,3 +926,10 @@
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -956,3 +956,10 @@ pl:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -959,3 +959,10 @@ pt-BR:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -943,3 +943,10 @@ pt:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -932,3 +932,10 @@ ro:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -1052,3 +1052,10 @@ ru:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Модуль
|
||||||
|
label_filesystem_path: Каталог
|
||||||
|
label_darcs_path: Каталог
|
||||||
|
label_bazaar_path: Каталог
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Путь к каталогу .git
|
||||||
|
label_mercurial_path: Каталог
|
||||||
|
|
|
@ -934,3 +934,10 @@ sk:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -935,3 +935,10 @@ sl:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -939,3 +939,10 @@ sr-YU:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -940,3 +940,10 @@ sr:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -980,3 +980,10 @@ sv:
|
||||||
enumeration_activities: Aktiviteter (tidsuppföljning)
|
enumeration_activities: Aktiviteter (tidsuppföljning)
|
||||||
enumeration_system_activity: Systemaktivitet
|
enumeration_system_activity: Systemaktivitet
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -936,3 +936,10 @@ th:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -958,3 +958,10 @@ tr:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -935,3 +935,10 @@ uk:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -990,3 +990,10 @@ vi:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -1020,3 +1020,10 @@
|
||||||
enumeration_activities: 活動 (時間追蹤)
|
enumeration_activities: 活動 (時間追蹤)
|
||||||
enumeration_system_activity: 系統活動
|
enumeration_system_activity: 系統活動
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -953,3 +953,10 @@ zh:
|
||||||
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
|
||||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||||
text_powered_by: Powered by %{link}
|
text_powered_by: Powered by %{link}
|
||||||
|
label_cvs_module: Module
|
||||||
|
label_filesystem_path: Root directory
|
||||||
|
label_darcs_path: Root directory
|
||||||
|
label_bazaar_path: Root directory
|
||||||
|
label_cvs_path: CVSROOT
|
||||||
|
label_git_path: Path to .git directory
|
||||||
|
label_mercurial_path: Root directory
|
||||||
|
|
|
@ -1,5 +1,32 @@
|
||||||
= ChiliProject changelog
|
= ChiliProject changelog
|
||||||
|
|
||||||
|
== 2011-03-27 v1.2.0
|
||||||
|
|
||||||
|
* Bug #209: Don't hardcode user viewable labels (like "Path to .git repository")
|
||||||
|
* Bug #225: Support spaces in scm commands
|
||||||
|
* Bug #250: Filter assignee group to Team leaders
|
||||||
|
* Bug #251: Make Chili work with RubyGems 1.6
|
||||||
|
* Bug #266: Fix monkey patching of rubytree in lib/redmine/menu_manager.rb
|
||||||
|
* Bug #267: /issues/changes?format=atom is returning 500 Internal Error
|
||||||
|
* Bug #270: Reposman.rb does not consider underscore to be valid char for a project identifier
|
||||||
|
* Bug #273: custom autologin cookie name not read
|
||||||
|
* Bug #278: Issue Form: Parent autocomplete won't work with issues under 3 charactors
|
||||||
|
* Bug #280: Issues AutoComplete isn't searching issue ids
|
||||||
|
* Bug #281: Cross project issues aren't showing their project on the Version page
|
||||||
|
* Bug #282: Enhance Redmine::SafeAttributes to work for subclasses
|
||||||
|
* Bug #302: Protect methods in ApplicationController
|
||||||
|
* Bug #305: Toolbar for textile edit fields is buggy in IE8
|
||||||
|
* Feature #199: [PATCH] Adding a hook in the heading on showing an issue
|
||||||
|
* Feature #219: Add plugin hooks to the mailer layout
|
||||||
|
* Feature #230: Allow the loadpaths of themes to be specified in configuration.yml
|
||||||
|
* Feature #245: Merge Redmine.pm git smart-http functionality
|
||||||
|
* Feature #271: Replace checks for "auth_source_id" with "change_password_allowed?" in UsersController
|
||||||
|
* Feature #276: Add Log Time link to the sidebar on Project Overview
|
||||||
|
* Feature #283: Check pre-i18n 0.4.2 depreciation
|
||||||
|
* Feature #307: Add retro style gravatars
|
||||||
|
* Task #246: Document git-smart-http integration
|
||||||
|
* Task #308: Remove Redmine::VERSION::BRANCH
|
||||||
|
|
||||||
== 2011-02-27 v1.1.0
|
== 2011-02-27 v1.1.0
|
||||||
|
|
||||||
* Bug #109: Backport fix to display full TOC with present < p r e > tags
|
* Bug #109: Backport fix to display full TOC with present < p r e > tags
|
||||||
|
|
|
@ -93,6 +93,84 @@ S<them :>
|
||||||
|
|
||||||
And you need to upgrade at least reposman.rb (after r860).
|
And you need to upgrade at least reposman.rb (after r860).
|
||||||
|
|
||||||
|
=head1 GIT SMART HTTP SUPPORT
|
||||||
|
|
||||||
|
Git's smart HTTP protocol (available since Git 1.7.0) will not work with the
|
||||||
|
above settings. Redmine.pm normally does access control depending on the HTTP
|
||||||
|
method used: read-only methods are OK for everyone in public projects and
|
||||||
|
members with read rights in private projects. The rest require membership with
|
||||||
|
commit rights in the project.
|
||||||
|
|
||||||
|
However, this scheme doesn't work for Git's smart HTTP protocol, as it will use
|
||||||
|
POST even for a simple clone. Instead, read-only requests must be detected using
|
||||||
|
the full URL (including the query string): anything that doesn't belong to the
|
||||||
|
git-receive-pack service is read-only.
|
||||||
|
|
||||||
|
To activate this mode of operation, add this line inside your <Location /git>
|
||||||
|
block:
|
||||||
|
|
||||||
|
RedmineGitSmartHttp yes
|
||||||
|
|
||||||
|
Here's a sample Apache configuration which integrates git-http-backend with
|
||||||
|
a MySQL database and this new option:
|
||||||
|
|
||||||
|
SetEnv GIT_PROJECT_ROOT /var/www/git/
|
||||||
|
SetEnv GIT_HTTP_EXPORT_ALL
|
||||||
|
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
|
||||||
|
<Location /git>
|
||||||
|
Order allow,deny
|
||||||
|
Allow from all
|
||||||
|
|
||||||
|
AuthType Basic
|
||||||
|
AuthName Git
|
||||||
|
Require valid-user
|
||||||
|
|
||||||
|
PerlAccessHandler Apache::Authn::Redmine::access_handler
|
||||||
|
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
|
||||||
|
# for mysql
|
||||||
|
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
|
||||||
|
RedmineDbUser "redmine"
|
||||||
|
RedmineDbPass "xxx"
|
||||||
|
RedmineGitSmartHttp yes
|
||||||
|
</Location>
|
||||||
|
|
||||||
|
Make sure that all the names of the repositories under /var/www/git/ match
|
||||||
|
exactly the identifier for some project: /var/www/git/myproject.git won't work,
|
||||||
|
due to the way this module extracts the identifier from the URL.
|
||||||
|
/var/www/git/myproject will work, though. You can put both bare and non-bare
|
||||||
|
repositories in /var/www/git, though bare repositories are strongly
|
||||||
|
recommended. You should create them with the rights of the user running Redmine,
|
||||||
|
like this:
|
||||||
|
|
||||||
|
cd /var/www/git
|
||||||
|
sudo -u user-running-redmine mkdir myproject
|
||||||
|
cd myproject
|
||||||
|
sudo -u user-running-redmine git init --bare
|
||||||
|
|
||||||
|
Once you have activated this option, you have three options when cloning a
|
||||||
|
repository:
|
||||||
|
|
||||||
|
- Cloning using "http://user@host/git/repo" works, but will ask for the password
|
||||||
|
all the time.
|
||||||
|
|
||||||
|
- Cloning with "http://user:pass@host/git/repo" does not have this problem, but
|
||||||
|
this could reveal accidentally your password to the console in some versions
|
||||||
|
of Git, and you would have to ensure that .git/config is not readable except
|
||||||
|
by the owner for each of your projects.
|
||||||
|
|
||||||
|
- Use "http://host/git/repo", and store your credentials in the ~/.netrc
|
||||||
|
file. This is the recommended solution, as you only have one file to protect
|
||||||
|
and passwords will not be leaked accidentally to the console.
|
||||||
|
|
||||||
|
IMPORTANT NOTE: It is *very important* that the file cannot be read by other
|
||||||
|
users, as it will contain your password in cleartext. To create the file, you
|
||||||
|
can use the following commands, replacing yourhost, youruser and yourpassword
|
||||||
|
with the right values:
|
||||||
|
|
||||||
|
touch ~/.netrc
|
||||||
|
chmod 600 ~/.netrc
|
||||||
|
echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -142,6 +220,11 @@ my @directives = (
|
||||||
args_how => TAKE1,
|
args_how => TAKE1,
|
||||||
errmsg => 'RedmineCacheCredsMax must be decimal number',
|
errmsg => 'RedmineCacheCredsMax must be decimal number',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name => 'RedmineGitSmartHttp',
|
||||||
|
req_override => OR_AUTHCFG,
|
||||||
|
args_how => TAKE1,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
sub RedmineDSN {
|
sub RedmineDSN {
|
||||||
|
@ -178,6 +261,17 @@ sub RedmineCacheCredsMax {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub RedmineGitSmartHttp {
|
||||||
|
my ($self, $parms, $arg) = @_;
|
||||||
|
$arg = lc $arg;
|
||||||
|
|
||||||
|
if ($arg eq "yes" || $arg eq "true") {
|
||||||
|
$self->{RedmineGitSmartHttp} = 1;
|
||||||
|
} else {
|
||||||
|
$self->{RedmineGitSmartHttp} = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub trim {
|
sub trim {
|
||||||
my $string = shift;
|
my $string = shift;
|
||||||
$string =~ s/\s{2,}/ /g;
|
$string =~ s/\s{2,}/ /g;
|
||||||
|
@ -194,6 +288,23 @@ Apache2::Module::add(__PACKAGE__, \@directives);
|
||||||
|
|
||||||
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
|
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
|
||||||
|
|
||||||
|
sub request_is_read_only {
|
||||||
|
my ($r) = @_;
|
||||||
|
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
|
||||||
|
|
||||||
|
# Do we use Git's smart HTTP protocol, or not?
|
||||||
|
if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
|
||||||
|
my $uri = $r->unparsed_uri;
|
||||||
|
my $location = $r->location;
|
||||||
|
my $is_read_only = $uri !~ m{^$location/*[^/]+/+(info/refs\?service=)?git\-receive\-pack$}o;
|
||||||
|
return $is_read_only;
|
||||||
|
} else {
|
||||||
|
# Old behaviour: check the HTTP method
|
||||||
|
my $method = $r->method;
|
||||||
|
return defined $read_only_methods{$method};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub access_handler {
|
sub access_handler {
|
||||||
my $r = shift;
|
my $r = shift;
|
||||||
|
|
||||||
|
@ -202,8 +313,7 @@ sub access_handler {
|
||||||
return FORBIDDEN;
|
return FORBIDDEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $method = $r->method;
|
return OK unless request_is_read_only($r);
|
||||||
return OK unless defined $read_only_methods{$method};
|
|
||||||
|
|
||||||
my $project_id = get_project_identifier($r);
|
my $project_id = get_project_identifier($r);
|
||||||
|
|
||||||
|
@ -320,7 +430,7 @@ sub is_member {
|
||||||
|
|
||||||
unless ($auth_source_id) {
|
unless ($auth_source_id) {
|
||||||
my $method = $r->method;
|
my $method = $r->method;
|
||||||
if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
if ($hashed_password eq $pass_digest && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
||||||
$ret = 1;
|
$ret = 1;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
@ -338,9 +448,7 @@ sub is_member {
|
||||||
bindpw => $rowldap[4] ? $rowldap[4] : "",
|
bindpw => $rowldap[4] ? $rowldap[4] : "",
|
||||||
filter => "(".$rowldap[6]."=%s)"
|
filter => "(".$rowldap[6]."=%s)"
|
||||||
);
|
);
|
||||||
my $method = $r->method;
|
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
||||||
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
$sthldap->finish();
|
$sthldap->finish();
|
||||||
undef $sthldap;
|
undef $sthldap;
|
||||||
|
|
|
@ -238,7 +238,7 @@ projects.each do |project|
|
||||||
if project.identifier.empty?
|
if project.identifier.empty?
|
||||||
log("\tno identifier for project #{project.name}")
|
log("\tno identifier for project #{project.name}")
|
||||||
next
|
next
|
||||||
elsif not project.identifier.match(/^[a-z0-9\-]+$/)
|
elsif not project.identifier.match(/^[a-z0-9\-_]+$/)
|
||||||
log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
|
log("\tinvalid identifier for project #{project.name} : #{project.identifier}");
|
||||||
next;
|
next;
|
||||||
end
|
end
|
||||||
|
@ -309,4 +309,3 @@ projects.each do |project|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,11 @@ module Redmine
|
||||||
|
|
||||||
# Configuration default values
|
# Configuration default values
|
||||||
@defaults = {
|
@defaults = {
|
||||||
'email_delivery' => nil
|
'email_delivery' => nil,
|
||||||
|
# Autologin cookie defaults:
|
||||||
|
'autologin_cookie_name' => 'autologin',
|
||||||
|
'autologin_cookie_path' => '/',
|
||||||
|
'autologin_cookie_secure' => false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@config = nil
|
@config = nil
|
||||||
|
|
|
@ -23,12 +23,13 @@ module TreeNodePatch
|
||||||
base.class_eval do
|
base.class_eval do
|
||||||
attr_reader :last_items_count
|
attr_reader :last_items_count
|
||||||
|
|
||||||
alias :old_initilize :initialize
|
def initialize_with_redmine(name, content = nil)
|
||||||
def initialize(name, content = nil)
|
extend InstanceMethods
|
||||||
old_initilize(name, content)
|
|
||||||
@last_items_count = 0
|
@last_items_count = 0
|
||||||
extend(InstanceMethods)
|
|
||||||
|
initialize_without_redmine(name, content)
|
||||||
end
|
end
|
||||||
|
alias_method_chain :initialize, :redmine
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -99,7 +100,9 @@ module TreeNodePatch
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Tree::TreeNode.send(:include, TreeNodePatch)
|
unless Tree::TreeNode.included_modules.include?(TreeNodePatch)
|
||||||
|
Tree::TreeNode.send(:include, TreeNodePatch)
|
||||||
|
end
|
||||||
|
|
||||||
module Redmine
|
module Redmine
|
||||||
module MenuManager
|
module MenuManager
|
||||||
|
|
|
@ -31,10 +31,15 @@ module Redmine
|
||||||
def safe_attributes(*args)
|
def safe_attributes(*args)
|
||||||
@safe_attributes ||= []
|
@safe_attributes ||= []
|
||||||
if args.empty?
|
if args.empty?
|
||||||
@safe_attributes
|
if superclass < Redmine::SafeAttributes
|
||||||
|
superclass.safe_attributes + @safe_attributes
|
||||||
|
else
|
||||||
|
@safe_attributes
|
||||||
|
end
|
||||||
else
|
else
|
||||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||||
@safe_attributes << [args, options]
|
@safe_attributes << [args, options]
|
||||||
|
safe_attributes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -62,7 +67,7 @@ module Redmine
|
||||||
# # => {'title' => 'My book'}
|
# # => {'title' => 'My book'}
|
||||||
def delete_unsafe_attributes(attrs, user=User.current)
|
def delete_unsafe_attributes(attrs, user=User.current)
|
||||||
safe = safe_attribute_names(user)
|
safe = safe_attribute_names(user)
|
||||||
attrs.dup.delete_if {|k,v| !safe.include?(k)}
|
attrs.dup.delete_if {|k,v| !safe.include?(k.to_s)}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sets attributes from attrs that are safe
|
# Sets attributes from attrs that are safe
|
||||||
|
|
|
@ -25,6 +25,10 @@ module Redmine
|
||||||
|
|
||||||
class AbstractAdapter #:nodoc:
|
class AbstractAdapter #:nodoc:
|
||||||
class << self
|
class << self
|
||||||
|
def client_command
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
# Returns the version of the scm client
|
# Returns the version of the scm client
|
||||||
# Eg: [1, 5, 0] or [] if unknown
|
# Eg: [1, 5, 0] or [] if unknown
|
||||||
def client_version
|
def client_version
|
||||||
|
@ -45,6 +49,18 @@ module Redmine
|
||||||
def client_version_above?(v, options={})
|
def client_version_above?(v, options={})
|
||||||
((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
|
((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def client_available
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def shell_quote(str)
|
||||||
|
if Redmine::Platform.mswin?
|
||||||
|
'"' + str.gsub(/"/, '\\"') + '"'
|
||||||
|
else
|
||||||
|
"'" + str.gsub(/'/, "'\"'\"'") + "'"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(url, root_url=nil, login=nil, password=nil)
|
def initialize(url, root_url=nil, login=nil, password=nil)
|
||||||
|
@ -150,11 +166,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def shell_quote(str)
|
def shell_quote(str)
|
||||||
if Redmine::Platform.mswin?
|
self.class.shell_quote(str)
|
||||||
'"' + str.gsub(/"/, '\\"') + '"'
|
|
||||||
else
|
|
||||||
"'" + str.gsub(/'/, "'\"'\"'") + "'"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -25,9 +25,19 @@ module Redmine
|
||||||
# Bazaar executable name
|
# Bazaar executable name
|
||||||
BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr"
|
BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr"
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= BZR_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(BZR_BIN)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Get info about the repository
|
# Get info about the repository
|
||||||
def info
|
def info
|
||||||
cmd = "#{BZR_BIN} revno #{target('')}"
|
cmd = "#{self.class.sq_bin} revno #{target('')}"
|
||||||
info = nil
|
info = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
if io.read =~ %r{^(\d+)\r?$}
|
if io.read =~ %r{^(\d+)\r?$}
|
||||||
|
@ -49,7 +59,7 @@ module Redmine
|
||||||
def entries(path=nil, identifier=nil)
|
def entries(path=nil, identifier=nil)
|
||||||
path ||= ''
|
path ||= ''
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{BZR_BIN} ls -v --show-ids"
|
cmd = "#{self.class.sq_bin} ls -v --show-ids"
|
||||||
identifier = -1 unless identifier && identifier.to_i > 0
|
identifier = -1 unless identifier && identifier.to_i > 0
|
||||||
cmd << " -r#{identifier.to_i}"
|
cmd << " -r#{identifier.to_i}"
|
||||||
cmd << " #{target(path)}"
|
cmd << " #{target(path)}"
|
||||||
|
@ -77,7 +87,7 @@ module Redmine
|
||||||
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
|
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
|
||||||
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
|
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
|
||||||
revisions = Revisions.new
|
revisions = Revisions.new
|
||||||
cmd = "#{BZR_BIN} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
|
cmd = "#{self.class.sq_bin} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
revision = nil
|
revision = nil
|
||||||
parsing = nil
|
parsing = nil
|
||||||
|
@ -143,7 +153,7 @@ module Redmine
|
||||||
if identifier_from
|
if identifier_from
|
||||||
identifier_from = identifier_from.to_i
|
identifier_from = identifier_from.to_i
|
||||||
end
|
end
|
||||||
cmd = "#{BZR_BIN} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
|
cmd = "#{self.class.sq_bin} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
|
||||||
diff = []
|
diff = []
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
io.each_line do |line|
|
io.each_line do |line|
|
||||||
|
@ -155,7 +165,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def cat(path, identifier=nil)
|
def cat(path, identifier=nil)
|
||||||
cmd = "#{BZR_BIN} cat"
|
cmd = "#{self.class.sq_bin} cat"
|
||||||
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
|
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
|
||||||
cmd << " #{target(path)}"
|
cmd << " #{target(path)}"
|
||||||
cat = nil
|
cat = nil
|
||||||
|
@ -168,7 +178,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def annotate(path, identifier=nil)
|
def annotate(path, identifier=nil)
|
||||||
cmd = "#{BZR_BIN} annotate --all"
|
cmd = "#{self.class.sq_bin} annotate --all"
|
||||||
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
|
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
|
||||||
cmd << " #{target(path)}"
|
cmd << " #{target(path)}"
|
||||||
blame = Annotate.new
|
blame = Annotate.new
|
||||||
|
|
|
@ -25,6 +25,16 @@ module Redmine
|
||||||
# CVS executable name
|
# CVS executable name
|
||||||
CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
|
CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= CVS_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(CVS_BIN)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Guidelines for the input:
|
# Guidelines for the input:
|
||||||
# url -> the project-path, relative to the cvsroot (eg. module name)
|
# url -> the project-path, relative to the cvsroot (eg. module name)
|
||||||
# root_url -> the good old, sometimes damned, CVSROOT
|
# root_url -> the good old, sometimes damned, CVSROOT
|
||||||
|
@ -63,7 +73,7 @@ module Redmine
|
||||||
logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
|
logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
|
||||||
path_with_project="#{url}#{with_leading_slash(path)}"
|
path_with_project="#{url}#{with_leading_slash(path)}"
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rls -e"
|
cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rls -e"
|
||||||
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
|
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
|
||||||
cmd << " #{shell_quote path_with_project}"
|
cmd << " #{shell_quote path_with_project}"
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -108,7 +118,7 @@ module Redmine
|
||||||
logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
||||||
|
|
||||||
path_with_project="#{url}#{with_leading_slash(path)}"
|
path_with_project="#{url}#{with_leading_slash(path)}"
|
||||||
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rlog"
|
cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rlog"
|
||||||
cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from
|
cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from
|
||||||
cmd << " #{shell_quote path_with_project}"
|
cmd << " #{shell_quote path_with_project}"
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -229,7 +239,7 @@ module Redmine
|
||||||
def diff(path, identifier_from, identifier_to=nil)
|
def diff(path, identifier_from, identifier_to=nil)
|
||||||
logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
||||||
path_with_project="#{url}#{with_leading_slash(path)}"
|
path_with_project="#{url}#{with_leading_slash(path)}"
|
||||||
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
|
cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
|
||||||
diff = []
|
diff = []
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
io.each_line do |line|
|
io.each_line do |line|
|
||||||
|
@ -244,11 +254,12 @@ module Redmine
|
||||||
identifier = (identifier) ? identifier : "HEAD"
|
identifier = (identifier) ? identifier : "HEAD"
|
||||||
logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
|
logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
|
||||||
path_with_project="#{url}#{with_leading_slash(path)}"
|
path_with_project="#{url}#{with_leading_slash(path)}"
|
||||||
cmd = "#{CVS_BIN} -d #{shell_quote root_url} co"
|
cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co"
|
||||||
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
|
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
|
||||||
cmd << " -p #{shell_quote path_with_project}"
|
cmd << " -p #{shell_quote path_with_project}"
|
||||||
cat = nil
|
cat = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
io.binmode
|
||||||
cat = io.read
|
cat = io.read
|
||||||
end
|
end
|
||||||
return nil if $? && $?.exitstatus != 0
|
return nil if $? && $?.exitstatus != 0
|
||||||
|
@ -259,7 +270,7 @@ module Redmine
|
||||||
identifier = (identifier) ? identifier.to_i : "HEAD"
|
identifier = (identifier) ? identifier.to_i : "HEAD"
|
||||||
logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
|
logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
|
||||||
path_with_project="#{url}#{with_leading_slash(path)}"
|
path_with_project="#{url}#{with_leading_slash(path)}"
|
||||||
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
|
cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
|
||||||
blame = Annotate.new
|
blame = Annotate.new
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
io.each_line do |line|
|
io.each_line do |line|
|
||||||
|
|
|
@ -26,6 +26,14 @@ module Redmine
|
||||||
DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs"
|
DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs"
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= DARCS_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(DARCS_BIN)
|
||||||
|
end
|
||||||
|
|
||||||
def client_version
|
def client_version
|
||||||
@@client_version ||= (darcs_binary_version || [])
|
@@client_version ||= (darcs_binary_version || [])
|
||||||
end
|
end
|
||||||
|
@ -38,7 +46,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def darcs_binary_version_from_command_line
|
def darcs_binary_version_from_command_line
|
||||||
shellout("#{DARCS_BIN} --version") { |io| io.read }.to_s
|
shellout("#{sq_bin} --version") { |io| io.read }.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -66,7 +74,7 @@ module Redmine
|
||||||
path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' )
|
path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' )
|
||||||
end
|
end
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --xml-output"
|
cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --xml-output"
|
||||||
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
|
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
|
||||||
cmd << " #{shell_quote path}"
|
cmd << " #{shell_quote path}"
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -90,7 +98,7 @@ module Redmine
|
||||||
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
|
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
|
||||||
path = '.' if path.blank?
|
path = '.' if path.blank?
|
||||||
revisions = Revisions.new
|
revisions = Revisions.new
|
||||||
cmd = "#{DARCS_BIN} changes --repodir #{shell_quote @url} --xml-output"
|
cmd = "#{self.class.sq_bin} changes --repodir #{shell_quote @url} --xml-output"
|
||||||
cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
|
cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
|
||||||
cmd << " --last #{options[:limit].to_i}" if options[:limit]
|
cmd << " --last #{options[:limit].to_i}" if options[:limit]
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -116,7 +124,7 @@ module Redmine
|
||||||
|
|
||||||
def diff(path, identifier_from, identifier_to=nil)
|
def diff(path, identifier_from, identifier_to=nil)
|
||||||
path = '*' if path.blank?
|
path = '*' if path.blank?
|
||||||
cmd = "#{DARCS_BIN} diff --repodir #{shell_quote @url}"
|
cmd = "#{self.class.sq_bin} diff --repodir #{shell_quote @url}"
|
||||||
if identifier_to.nil?
|
if identifier_to.nil?
|
||||||
cmd << " --match #{shell_quote("hash #{identifier_from}")}"
|
cmd << " --match #{shell_quote("hash #{identifier_from}")}"
|
||||||
else
|
else
|
||||||
|
@ -135,7 +143,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def cat(path, identifier=nil)
|
def cat(path, identifier=nil)
|
||||||
cmd = "#{DARCS_BIN} show content --repodir #{shell_quote @url}"
|
cmd = "#{self.class.sq_bin} show content --repodir #{shell_quote @url}"
|
||||||
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
|
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
|
||||||
cmd << " #{shell_quote path}"
|
cmd << " #{shell_quote path}"
|
||||||
cat = nil
|
cat = nil
|
||||||
|
@ -199,7 +207,7 @@ module Redmine
|
||||||
|
|
||||||
# Retrieve changed paths for a single patch
|
# Retrieve changed paths for a single patch
|
||||||
def get_paths_for_patch_raw(hash)
|
def get_paths_for_patch_raw(hash)
|
||||||
cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --summary --xml-output"
|
cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --summary --xml-output"
|
||||||
cmd << " --match #{shell_quote("hash #{hash}")} "
|
cmd << " --match #{shell_quote("hash #{hash}")} "
|
||||||
paths = []
|
paths = []
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
|
|
@ -26,6 +26,11 @@ module Redmine
|
||||||
module Adapters
|
module Adapters
|
||||||
class FilesystemAdapter < AbstractAdapter
|
class FilesystemAdapter < AbstractAdapter
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def client_available
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(url, root_url=nil, login=nil, password=nil)
|
def initialize(url, root_url=nil, login=nil, password=nil)
|
||||||
@url = with_trailling_slash(url)
|
@url = with_trailling_slash(url)
|
||||||
|
|
|
@ -24,6 +24,20 @@ module Redmine
|
||||||
# Git executable name
|
# Git executable name
|
||||||
GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
|
GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= GIT_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(GIT_BIN)
|
||||||
|
end
|
||||||
|
|
||||||
|
def client_available
|
||||||
|
!client_version.empty?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def info
|
def info
|
||||||
begin
|
begin
|
||||||
Info.new(:root_url => url, :lastrev => lastrev('',nil))
|
Info.new(:root_url => url, :lastrev => lastrev('',nil))
|
||||||
|
@ -35,7 +49,7 @@ module Redmine
|
||||||
def branches
|
def branches
|
||||||
return @branches if @branches
|
return @branches if @branches
|
||||||
@branches = []
|
@branches = []
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} branch --no-color"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} branch --no-color"
|
||||||
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]
|
||||||
|
@ -46,7 +60,7 @@ module Redmine
|
||||||
|
|
||||||
def tags
|
def tags
|
||||||
return @tags if @tags
|
return @tags if @tags
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} tag"
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
@tags = io.readlines.sort!.map{|t| t.strip}
|
@tags = io.readlines.sort!.map{|t| t.strip}
|
||||||
end
|
end
|
||||||
|
@ -59,7 +73,7 @@ module Redmine
|
||||||
def entries(path=nil, identifier=nil)
|
def entries(path=nil, identifier=nil)
|
||||||
path ||= ''
|
path ||= ''
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} ls-tree -l "
|
||||||
cmd << shell_quote("HEAD:" + path) if identifier.nil?
|
cmd << shell_quote("HEAD:" + path) if identifier.nil?
|
||||||
cmd << shell_quote(identifier + ":" + path) if identifier
|
cmd << shell_quote(identifier + ":" + path) if identifier
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -86,7 +100,7 @@ module Redmine
|
||||||
|
|
||||||
def lastrev(path,rev)
|
def lastrev(path,rev)
|
||||||
return nil if path.nil?
|
return nil if path.nil?
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 "
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 "
|
||||||
cmd << " #{shell_quote rev} " if rev
|
cmd << " #{shell_quote rev} " if rev
|
||||||
cmd << "-- #{shell_quote path} " unless path.empty?
|
cmd << "-- #{shell_quote path} " unless path.empty?
|
||||||
lines = []
|
lines = []
|
||||||
|
@ -114,7 +128,7 @@ module Redmine
|
||||||
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 --no-color --raw --date=iso --pretty=fuller "
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --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].to_i} " if options[:limit]
|
cmd << " -n #{options[:limit].to_i} " if options[:limit]
|
||||||
|
@ -209,9 +223,9 @@ module Redmine
|
||||||
path ||= ''
|
path ||= ''
|
||||||
|
|
||||||
if identifier_to
|
if identifier_to
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}"
|
||||||
else
|
else
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}"
|
||||||
end
|
end
|
||||||
|
|
||||||
cmd << " -- #{shell_quote path}" unless path.empty?
|
cmd << " -- #{shell_quote path}" unless path.empty?
|
||||||
|
@ -227,7 +241,7 @@ module Redmine
|
||||||
|
|
||||||
def annotate(path, identifier=nil)
|
def annotate(path, identifier=nil)
|
||||||
identifier = 'HEAD' if identifier.blank?
|
identifier = 'HEAD' if identifier.blank?
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
|
||||||
blame = Annotate.new
|
blame = Annotate.new
|
||||||
content = nil
|
content = nil
|
||||||
shellout(cmd) { |io| io.binmode; content = io.read }
|
shellout(cmd) { |io| io.binmode; content = io.read }
|
||||||
|
@ -255,7 +269,7 @@ module Redmine
|
||||||
if identifier.nil?
|
if identifier.nil?
|
||||||
identifier = 'HEAD'
|
identifier = 'HEAD'
|
||||||
end
|
end
|
||||||
cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}"
|
cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}"
|
||||||
cat = nil
|
cat = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
io.binmode
|
io.binmode
|
||||||
|
|
|
@ -30,10 +30,22 @@ module Redmine
|
||||||
TEMPLATE_EXTENSION = "tmpl"
|
TEMPLATE_EXTENSION = "tmpl"
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= HG_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(HG_BIN)
|
||||||
|
end
|
||||||
|
|
||||||
def client_version
|
def client_version
|
||||||
@@client_version ||= (hgversion || [])
|
@@client_version ||= (hgversion || [])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def client_available
|
||||||
|
!client_version.empty?
|
||||||
|
end
|
||||||
|
|
||||||
def hgversion
|
def hgversion
|
||||||
# The hg version is expressed either as a
|
# The hg version is expressed either as a
|
||||||
# release number (eg 0.9.5 or 1.0) or as a revision
|
# release number (eg 0.9.5 or 1.0) or as a revision
|
||||||
|
@ -45,7 +57,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def hgversion_from_command_line
|
def hgversion_from_command_line
|
||||||
shellout("#{HG_BIN} --version") { |io| io.read }.to_s
|
shellout("#{sq_bin} --version") { |io| io.read }.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def template_path
|
def template_path
|
||||||
|
@ -63,7 +75,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def info
|
def info
|
||||||
cmd = "#{HG_BIN} -R #{target('')} root"
|
cmd = "#{self.class.sq_bin} -R #{target('')} root"
|
||||||
root_url = nil
|
root_url = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
root_url = io.read
|
root_url = io.read
|
||||||
|
@ -80,7 +92,7 @@ module Redmine
|
||||||
def entries(path=nil, identifier=nil)
|
def entries(path=nil, identifier=nil)
|
||||||
path ||= ''
|
path ||= ''
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{HG_BIN} -R #{target('')} --cwd #{target('')} locate"
|
cmd = "#{self.class.sq_bin} -R #{target('')} --cwd #{target('')} locate"
|
||||||
cmd << " -r #{hgrev(identifier)}"
|
cmd << " -r #{hgrev(identifier)}"
|
||||||
cmd << " " + shell_quote("path:#{path}") unless path.empty?
|
cmd << " " + shell_quote("path:#{path}") unless path.empty?
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -106,7 +118,7 @@ module Redmine
|
||||||
# makes Mercurial produce a xml output.
|
# makes Mercurial produce a xml output.
|
||||||
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
|
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
|
||||||
revisions = Revisions.new
|
revisions = Revisions.new
|
||||||
cmd = "#{HG_BIN} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}"
|
cmd = "#{self.class.sq_bin} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}"
|
||||||
if identifier_from && identifier_to
|
if identifier_from && identifier_to
|
||||||
cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
|
cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
|
||||||
elsif identifier_from
|
elsif identifier_from
|
||||||
|
@ -164,7 +176,7 @@ module Redmine
|
||||||
return []
|
return []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cmd = "#{HG_BIN} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}"
|
cmd = "#{self.class.sq_bin} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}"
|
||||||
cmd << " -I #{target(path)}" unless path.empty?
|
cmd << " -I #{target(path)}" unless path.empty?
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
io.each_line do |line|
|
io.each_line do |line|
|
||||||
|
@ -176,7 +188,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
def cat(path, identifier=nil)
|
def cat(path, identifier=nil)
|
||||||
cmd = "#{HG_BIN} -R #{target('')} cat"
|
cmd = "#{self.class.sq_bin} -R #{target('')} cat"
|
||||||
cmd << " -r #{hgrev(identifier)}"
|
cmd << " -r #{hgrev(identifier)}"
|
||||||
cmd << " #{target(path)}"
|
cmd << " #{target(path)}"
|
||||||
cat = nil
|
cat = nil
|
||||||
|
@ -190,7 +202,7 @@ module Redmine
|
||||||
|
|
||||||
def annotate(path, identifier=nil)
|
def annotate(path, identifier=nil)
|
||||||
path ||= ''
|
path ||= ''
|
||||||
cmd = "#{HG_BIN} -R #{target('')}"
|
cmd = "#{self.class.sq_bin} -R #{target('')}"
|
||||||
cmd << " annotate -ncu"
|
cmd << " annotate -ncu"
|
||||||
cmd << " -r #{hgrev(identifier)}"
|
cmd << " -r #{hgrev(identifier)}"
|
||||||
cmd << " #{target(path)}"
|
cmd << " #{target(path)}"
|
||||||
|
|
|
@ -27,12 +27,20 @@ module Redmine
|
||||||
SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn"
|
SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn"
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
def client_command
|
||||||
|
@@bin ||= SVN_BIN
|
||||||
|
end
|
||||||
|
|
||||||
|
def sq_bin
|
||||||
|
@@sq_bin ||= shell_quote(SVN_BIN)
|
||||||
|
end
|
||||||
|
|
||||||
def client_version
|
def client_version
|
||||||
@@client_version ||= (svn_binary_version || [])
|
@@client_version ||= (svn_binary_version || [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def svn_binary_version
|
def svn_binary_version
|
||||||
cmd = "#{SVN_BIN} --version"
|
cmd = "#{sq_bin} --version"
|
||||||
version = nil
|
version = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
# Read svn version in first returned line
|
# Read svn version in first returned line
|
||||||
|
@ -47,7 +55,7 @@ module Redmine
|
||||||
|
|
||||||
# Get info about the svn repository
|
# Get info about the svn repository
|
||||||
def info
|
def info
|
||||||
cmd = "#{SVN_BIN} info --xml #{target}"
|
cmd = "#{self.class.sq_bin} info --xml #{target}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
info = nil
|
info = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -77,7 +85,7 @@ module Redmine
|
||||||
path ||= ''
|
path ||= ''
|
||||||
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
||||||
entries = Entries.new
|
entries = Entries.new
|
||||||
cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
|
cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
output = io.read
|
output = io.read
|
||||||
|
@ -116,7 +124,7 @@ module Redmine
|
||||||
return nil unless self.class.client_version_above?([1, 5, 0])
|
return nil unless self.class.client_version_above?([1, 5, 0])
|
||||||
|
|
||||||
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
||||||
cmd = "#{SVN_BIN} proplist --verbose --xml #{target(path)}@#{identifier}"
|
cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
properties = {}
|
properties = {}
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -138,7 +146,7 @@ module Redmine
|
||||||
identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
|
identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
|
||||||
identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
|
identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
|
||||||
revisions = Revisions.new
|
revisions = Revisions.new
|
||||||
cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
|
cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
cmd << " --verbose " if options[:with_paths]
|
cmd << " --verbose " if options[:with_paths]
|
||||||
cmd << " --limit #{options[:limit].to_i}" if options[:limit]
|
cmd << " --limit #{options[:limit].to_i}" if options[:limit]
|
||||||
|
@ -177,7 +185,7 @@ module Redmine
|
||||||
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
|
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
|
||||||
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
|
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
|
||||||
|
|
||||||
cmd = "#{SVN_BIN} diff -r "
|
cmd = "#{self.class.sq_bin} diff -r "
|
||||||
cmd << "#{identifier_to}:"
|
cmd << "#{identifier_to}:"
|
||||||
cmd << "#{identifier_from}"
|
cmd << "#{identifier_from}"
|
||||||
cmd << " #{target(path)}@#{identifier_from}"
|
cmd << " #{target(path)}@#{identifier_from}"
|
||||||
|
@ -194,7 +202,7 @@ module Redmine
|
||||||
|
|
||||||
def cat(path, identifier=nil)
|
def cat(path, identifier=nil)
|
||||||
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
||||||
cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}"
|
cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
cat = nil
|
cat = nil
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
@ -207,7 +215,7 @@ module Redmine
|
||||||
|
|
||||||
def annotate(path, identifier=nil)
|
def annotate(path, identifier=nil)
|
||||||
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
|
||||||
cmd = "#{SVN_BIN} blame #{target(path)}@#{identifier}"
|
cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}"
|
||||||
cmd << credentials_string
|
cmd << credentials_string
|
||||||
blame = Annotate.new
|
blame = Annotate.new
|
||||||
shellout(cmd) do |io|
|
shellout(cmd) do |io|
|
||||||
|
|
|
@ -89,11 +89,22 @@ module Redmine
|
||||||
private
|
private
|
||||||
|
|
||||||
def self.scan_themes
|
def self.scan_themes
|
||||||
dirs = Dir.glob("#{Rails.public_path}/themes/*").select do |f|
|
theme_paths.inject([]) do |themes, path|
|
||||||
# A theme should at least override application.css
|
dirs = Dir.glob(File.join(path, '*')).select do |f|
|
||||||
File.directory?(f) && File.exist?("#{f}/stylesheets/application.css")
|
# A theme should at least override application.css
|
||||||
end
|
File.directory?(f) && File.exist?("#{f}/stylesheets/application.css")
|
||||||
dirs.collect {|dir| Theme.new(dir)}.sort
|
end
|
||||||
|
themes += dirs.collect { |dir| Theme.new(dir) }
|
||||||
|
end.sort
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.theme_paths
|
||||||
|
paths = Redmine::Configuration['themes_storage_path']
|
||||||
|
paths = [paths] unless paths.is_a?(Array)
|
||||||
|
paths.flatten!; paths.compact!
|
||||||
|
|
||||||
|
paths = ["#{Rails.public_path}/themes"] if paths.empty?
|
||||||
|
paths.collect { |p| File.expand_path(p, Rails.root) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,18 +3,10 @@ require 'rexml/document'
|
||||||
module Redmine
|
module Redmine
|
||||||
module VERSION #:nodoc:
|
module VERSION #:nodoc:
|
||||||
MAJOR = 1
|
MAJOR = 1
|
||||||
MINOR = 1
|
MINOR = 2
|
||||||
PATCH = 0
|
PATCH = 0
|
||||||
TINY = PATCH # Redmine compat
|
TINY = PATCH # Redmine compat
|
||||||
|
|
||||||
# Branches:
|
|
||||||
# * stable - released version
|
|
||||||
# * master - stable development
|
|
||||||
# * unstable - future development
|
|
||||||
#
|
|
||||||
# Source: https://www.chiliproject.org/projects/chiliproject/wiki/ChiliProject_Repository
|
|
||||||
BRANCH = 'master'
|
|
||||||
|
|
||||||
def self.revision
|
def self.revision
|
||||||
revision = nil
|
revision = nil
|
||||||
entries_path = "#{RAILS_ROOT}/.svn/entries"
|
entries_path = "#{RAILS_ROOT}/.svn/entries"
|
||||||
|
@ -37,7 +29,7 @@ module Redmine
|
||||||
end
|
end
|
||||||
|
|
||||||
REVISION = self.revision
|
REVISION = self.revision
|
||||||
ARRAY = [MAJOR, MINOR, PATCH, BRANCH, REVISION].compact
|
ARRAY = [MAJOR, MINOR, PATCH, REVISION].compact
|
||||||
STRING = ARRAY.join('.')
|
STRING = ARRAY.join('.')
|
||||||
|
|
||||||
def self.to_a; ARRAY end
|
def self.to_a; ARRAY end
|
||||||
|
|
|
@ -51,7 +51,8 @@ namespace :test do
|
||||||
(supported_scms - [:subversion, :mercurial]).each do |scm|
|
(supported_scms - [:subversion, :mercurial]).each do |scm|
|
||||||
desc "Creates a test #{scm} repository"
|
desc "Creates a test #{scm} repository"
|
||||||
task scm => :create_dir do
|
task scm => :create_dir do
|
||||||
system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test"
|
# system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test"
|
||||||
|
system "tar -xvz -C tmp/test -f test/fixtures/repositories/#{scm}_repository.tar.gz"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ function observeParentIssueField(url) {
|
||||||
new Ajax.Autocompleter('issue_parent_issue_id',
|
new Ajax.Autocompleter('issue_parent_issue_id',
|
||||||
'parent_issue_candidates',
|
'parent_issue_candidates',
|
||||||
url,
|
url,
|
||||||
{ minChars: 3,
|
{ minChars: 1,
|
||||||
frequency: 0.5,
|
frequency: 0.5,
|
||||||
paramName: 'q',
|
paramName: 'q',
|
||||||
updateElement: function(value) {
|
updateElement: function(value) {
|
||||||
|
@ -222,7 +222,7 @@ function observeRelatedIssueField(url) {
|
||||||
new Ajax.Autocompleter('relation_issue_to_id',
|
new Ajax.Autocompleter('relation_issue_to_id',
|
||||||
'related_issue_candidates',
|
'related_issue_candidates',
|
||||||
url,
|
url,
|
||||||
{ minChars: 3,
|
{ minChars: 1,
|
||||||
frequency: 0.5,
|
frequency: 0.5,
|
||||||
paramName: 'q',
|
paramName: 'q',
|
||||||
updateElement: function(value) {
|
updateElement: function(value) {
|
||||||
|
|
|
@ -243,106 +243,105 @@ jsToolBar.prototype = {
|
||||||
this.encloseSelection(stag,etag);
|
this.encloseSelection(stag,etag);
|
||||||
},
|
},
|
||||||
|
|
||||||
encloseLineSelection: function(prefix, suffix, fn) {
|
encloseLineSelection: function (prefix, suffix, fn) {
|
||||||
this.textarea.focus();
|
this.textarea.focus();
|
||||||
|
prefix = prefix || '';
|
||||||
|
suffix = suffix || '';
|
||||||
|
var start, end, sel, scrollPos, subst, res;
|
||||||
|
if (typeof(document["selection"]) != "undefined") {
|
||||||
|
// just makes it work in IE8 somehow
|
||||||
|
var range = document.selection.createRange();
|
||||||
|
var bookmark = range.getBookmark();
|
||||||
|
var origParent = range.parentElement();
|
||||||
|
// we move the starting point of the selection to the last newline
|
||||||
|
try {
|
||||||
|
while (range.text[0] != "\n" && range.text[0] != "\r") {
|
||||||
|
bookmark = range.getBookmark();
|
||||||
|
range.moveStart("character", -1);
|
||||||
|
if (origParent != range.parentElement()) {
|
||||||
|
throw "Outside of Textarea";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range.moveStart("character", 1);
|
||||||
|
} catch(err) {
|
||||||
|
if (err == "Outside of Textarea")
|
||||||
|
range.moveToBookmark(bookmark);
|
||||||
|
else
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
if (range.text.match(/ $/))
|
||||||
|
range.moveEnd("character", -1);
|
||||||
|
sel = range.text;
|
||||||
|
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
||||||
|
start = this.textarea.selectionStart;
|
||||||
|
end = this.textarea.selectionEnd;
|
||||||
|
scrollPos = this.textarea.scrollTop;
|
||||||
|
// go to the start of the line
|
||||||
|
start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length;
|
||||||
|
// go to the end of the line
|
||||||
|
end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length;
|
||||||
|
sel = this.textarea.value.substring(start, end);
|
||||||
|
}
|
||||||
|
if (sel.match(/ $/)) {
|
||||||
|
sel = sel.substring(0, sel.length - 1);
|
||||||
|
suffix = suffix + " ";
|
||||||
|
}
|
||||||
|
if (typeof(fn) == 'function') {
|
||||||
|
res = (sel) ? fn.call(this, sel) : fn('');
|
||||||
|
} else {
|
||||||
|
res = (sel) ? sel : '';
|
||||||
|
}
|
||||||
|
subst = prefix + res + suffix;
|
||||||
|
if (typeof(document["selection"]) != "undefined") {
|
||||||
|
range.text = subst;
|
||||||
|
this.textarea.caretPos -= suffix.length;
|
||||||
|
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
||||||
|
this.textarea.value = this.textarea.value.substring(0, start) + subst + this.textarea.value.substring(end);
|
||||||
|
if (sel) {
|
||||||
|
this.textarea.setSelectionRange(start + subst.length, start + subst.length);
|
||||||
|
} else {
|
||||||
|
this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
|
||||||
|
}
|
||||||
|
this.textarea.scrollTop = scrollPos;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
prefix = prefix || '';
|
encloseSelection: function (prefix, suffix, fn) {
|
||||||
suffix = suffix || '';
|
this.textarea.focus();
|
||||||
|
prefix = prefix || '';
|
||||||
var start, end, sel, scrollPos, subst, res;
|
suffix = suffix || '';
|
||||||
|
var start, end, sel, scrollPos, subst, res;
|
||||||
if (typeof(document["selection"]) != "undefined") {
|
if (typeof(document["selection"]) != "undefined") {
|
||||||
sel = document.selection.createRange().text;
|
sel = document.selection.createRange().text;
|
||||||
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
||||||
start = this.textarea.selectionStart;
|
start = this.textarea.selectionStart;
|
||||||
end = this.textarea.selectionEnd;
|
end = this.textarea.selectionEnd;
|
||||||
scrollPos = this.textarea.scrollTop;
|
scrollPos = this.textarea.scrollTop;
|
||||||
// go to the start of the line
|
sel = this.textarea.value.substring(start, end);
|
||||||
start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length;
|
}
|
||||||
// go to the end of the line
|
if (sel.match(/ $/)) {
|
||||||
end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length;
|
sel = sel.substring(0, sel.length - 1);
|
||||||
sel = this.textarea.value.substring(start, end);
|
suffix = suffix + " ";
|
||||||
}
|
}
|
||||||
|
if (typeof(fn) == 'function') {
|
||||||
if (sel.match(/ $/)) { // exclude ending space char, if any
|
res = (sel) ? fn.call(this, sel) : fn('');
|
||||||
sel = sel.substring(0, sel.length - 1);
|
} else {
|
||||||
suffix = suffix + " ";
|
res = (sel) ? sel : '';
|
||||||
}
|
}
|
||||||
|
subst = prefix + res + suffix;
|
||||||
if (typeof(fn) == 'function') {
|
if (typeof(document["selection"]) != "undefined") {
|
||||||
res = (sel) ? fn.call(this,sel) : fn('');
|
var range = document.selection.createRange().text = subst;
|
||||||
} else {
|
this.textarea.caretPos -= suffix.length;
|
||||||
res = (sel) ? sel : '';
|
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
||||||
}
|
this.textarea.value = this.textarea.value.substring(0, start) + subst + this.textarea.value.substring(end);
|
||||||
|
if (sel) {
|
||||||
subst = prefix + res + suffix;
|
this.textarea.setSelectionRange(start + subst.length, start + subst.length);
|
||||||
|
} else {
|
||||||
if (typeof(document["selection"]) != "undefined") {
|
this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
|
||||||
document.selection.createRange().text = subst;
|
}
|
||||||
var range = this.textarea.createTextRange();
|
this.textarea.scrollTop = scrollPos;
|
||||||
range.collapse(false);
|
}
|
||||||
range.move('character', -suffix.length);
|
},
|
||||||
range.select();
|
|
||||||
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
|
||||||
this.textarea.value = this.textarea.value.substring(0, start) + subst +
|
|
||||||
this.textarea.value.substring(end);
|
|
||||||
if (sel) {
|
|
||||||
this.textarea.setSelectionRange(start + subst.length, start + subst.length);
|
|
||||||
} else {
|
|
||||||
this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
|
|
||||||
}
|
|
||||||
this.textarea.scrollTop = scrollPos;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
encloseSelection: function(prefix, suffix, fn) {
|
|
||||||
this.textarea.focus();
|
|
||||||
|
|
||||||
prefix = prefix || '';
|
|
||||||
suffix = suffix || '';
|
|
||||||
|
|
||||||
var start, end, sel, scrollPos, subst, res;
|
|
||||||
|
|
||||||
if (typeof(document["selection"]) != "undefined") {
|
|
||||||
sel = document.selection.createRange().text;
|
|
||||||
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
|
||||||
start = this.textarea.selectionStart;
|
|
||||||
end = this.textarea.selectionEnd;
|
|
||||||
scrollPos = this.textarea.scrollTop;
|
|
||||||
sel = this.textarea.value.substring(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.match(/ $/)) { // exclude ending space char, if any
|
|
||||||
sel = sel.substring(0, sel.length - 1);
|
|
||||||
suffix = suffix + " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(fn) == 'function') {
|
|
||||||
res = (sel) ? fn.call(this,sel) : fn('');
|
|
||||||
} else {
|
|
||||||
res = (sel) ? sel : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
subst = prefix + res + suffix;
|
|
||||||
|
|
||||||
if (typeof(document["selection"]) != "undefined") {
|
|
||||||
document.selection.createRange().text = subst;
|
|
||||||
var range = this.textarea.createTextRange();
|
|
||||||
range.collapse(false);
|
|
||||||
range.move('character', -suffix.length);
|
|
||||||
range.select();
|
|
||||||
// this.textarea.caretPos -= suffix.length;
|
|
||||||
} else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
|
|
||||||
this.textarea.value = this.textarea.value.substring(0, start) + subst +
|
|
||||||
this.textarea.value.substring(end);
|
|
||||||
if (sel) {
|
|
||||||
this.textarea.setSelectionRange(start + subst.length, start + subst.length);
|
|
||||||
} else {
|
|
||||||
this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
|
|
||||||
}
|
|
||||||
this.textarea.scrollTop = scrollPos;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
stripBaseURL: function(url) {
|
stripBaseURL: function(url) {
|
||||||
if (this.base_url != '') {
|
if (this.base_url != '') {
|
||||||
|
|
|
@ -47,55 +47,55 @@ class ApplicationControllerTest < ActionController::TestCase
|
||||||
context "test_api_offset_and_limit" do
|
context "test_api_offset_and_limit" do
|
||||||
context "without params" do
|
context "without params" do
|
||||||
should "return 0, 25" do
|
should "return 0, 25" do
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with limit" do
|
context "with limit" do
|
||||||
should "return 0, limit" do
|
should "return 0, limit" do
|
||||||
assert_equal [0, 30], @controller.api_offset_and_limit({:limit => 30})
|
assert_equal [0, 30], @controller.send(:api_offset_and_limit, {:limit => 30})
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not exceed 100" do
|
should "not exceed 100" do
|
||||||
assert_equal [0, 100], @controller.api_offset_and_limit({:limit => 120})
|
assert_equal [0, 100], @controller.send(:api_offset_and_limit, {:limit => 120})
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not be negative" do
|
should "not be negative" do
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({:limit => -10})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {:limit => -10})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with offset" do
|
context "with offset" do
|
||||||
should "return offset, 25" do
|
should "return offset, 25" do
|
||||||
assert_equal [10, 25], @controller.api_offset_and_limit({:offset => 10})
|
assert_equal [10, 25], @controller.send(:api_offset_and_limit, {:offset => 10})
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not be negative" do
|
should "not be negative" do
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({:offset => -10})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {:offset => -10})
|
||||||
end
|
end
|
||||||
|
|
||||||
context "and limit" do
|
context "and limit" do
|
||||||
should "return offset, limit" do
|
should "return offset, limit" do
|
||||||
assert_equal [10, 50], @controller.api_offset_and_limit({:offset => 10, :limit => 50})
|
assert_equal [10, 50], @controller.send(:api_offset_and_limit, {:offset => 10, :limit => 50})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with page" do
|
context "with page" do
|
||||||
should "return offset, 25" do
|
should "return offset, 25" do
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({:page => 1})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {:page => 1})
|
||||||
assert_equal [50, 25], @controller.api_offset_and_limit({:page => 3})
|
assert_equal [50, 25], @controller.send(:api_offset_and_limit, {:page => 3})
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not be negative" do
|
should "not be negative" do
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({:page => 0})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {:page => 0})
|
||||||
assert_equal [0, 25], @controller.api_offset_and_limit({:page => -2})
|
assert_equal [0, 25], @controller.send(:api_offset_and_limit, {:page => -2})
|
||||||
end
|
end
|
||||||
|
|
||||||
context "and limit" do
|
context "and limit" do
|
||||||
should "return offset, limit" do
|
should "return offset, limit" do
|
||||||
assert_equal [0, 100], @controller.api_offset_and_limit({:page => 1, :limit => 100})
|
assert_equal [0, 100], @controller.send(:api_offset_and_limit, {:page => 1, :limit => 100})
|
||||||
assert_equal [200, 100], @controller.api_offset_and_limit({:page => 3, :limit => 100})
|
assert_equal [200, 100], @controller.send(:api_offset_and_limit, {:page => 3, :limit => 100})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,24 @@ class AutoCompletesControllerTest < ActionController::TestCase
|
||||||
assert assigns(:issues).include?(Issue.find(13))
|
assert assigns(:issues).include?(Issue.find(13))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'should return issues matching a given id' do
|
||||||
|
@project = Project.find('subproject1')
|
||||||
|
@issue_21 = Issue.generate_for_project!(@project, :id => 21)
|
||||||
|
@issue_101 = Issue.generate_for_project!(@project, :id => 101)
|
||||||
|
@issue_102 = Issue.generate_for_project!(@project, :id => 102)
|
||||||
|
@issue_with_subject = Issue.generate_for_project!(@project, :subject => 'This has 1 in the subject')
|
||||||
|
|
||||||
|
get :issues, :project_id => @project.id, :q => '1'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_not_nil assigns(:issues)
|
||||||
|
assert assigns(:issues).include?(Issue.find(13))
|
||||||
|
assert assigns(:issues).include?(@issue_21)
|
||||||
|
assert assigns(:issues).include?(@issue_101)
|
||||||
|
assert assigns(:issues).include?(@issue_102)
|
||||||
|
assert assigns(:issues).include?(@issue_with_subject)
|
||||||
|
end
|
||||||
|
|
||||||
def test_auto_complete_with_scope_all_and_cross_project_relations
|
def test_auto_complete_with_scope_all_and_cross_project_relations
|
||||||
Setting.cross_project_issue_relations = '1'
|
Setting.cross_project_issue_relations = '1'
|
||||||
get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all'
|
get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all'
|
||||||
|
|
|
@ -50,7 +50,7 @@ class AccountTest < ActionController::IntegrationTest
|
||||||
assert_equal user, token.user
|
assert_equal user, token.user
|
||||||
assert_equal 'autologin', token.action
|
assert_equal 'autologin', token.action
|
||||||
assert_equal user.id, session[:user_id]
|
assert_equal user.id, session[:user_id]
|
||||||
assert_equal token.value, cookies['autologin']
|
assert_equal token.value, cookies[Redmine::Configuration['autologin_cookie_name']]
|
||||||
|
|
||||||
# Session is cleared
|
# Session is cleared
|
||||||
reset!
|
reset!
|
||||||
|
@ -60,7 +60,7 @@ class AccountTest < ActionController::IntegrationTest
|
||||||
assert_nil user.reload.last_login_on
|
assert_nil user.reload.last_login_on
|
||||||
|
|
||||||
# User comes back with his autologin cookie
|
# User comes back with his autologin cookie
|
||||||
cookies[:autologin] = token.value
|
cookies[Redmine::Configuration['autologin_cookie_name']] = token.value
|
||||||
get '/my/page'
|
get '/my/page'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_template 'my/page'
|
assert_template 'my/page'
|
||||||
|
|
|
@ -35,11 +35,16 @@ class Redmine::SafeAttributesTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
class Book < Base
|
class Book < Base
|
||||||
attr_accessor :title
|
attr_accessor :title, :isbn
|
||||||
include Redmine::SafeAttributes
|
include Redmine::SafeAttributes
|
||||||
safe_attributes :title
|
safe_attributes :title
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
class PublishedBook < Book
|
||||||
|
safe_attributes :isbn
|
||||||
|
end
|
||||||
|
|
||||||
def test_safe_attribute_names
|
def test_safe_attribute_names
|
||||||
p = Person.new
|
p = Person.new
|
||||||
assert_equal ['firstname', 'lastname'], p.safe_attribute_names(User.anonymous)
|
assert_equal ['firstname', 'lastname'], p.safe_attribute_names(User.anonymous)
|
||||||
|
@ -84,4 +89,25 @@ class Redmine::SafeAttributesTest < ActiveSupport::TestCase
|
||||||
assert_equal 'Smith', p.lastname
|
assert_equal 'Smith', p.lastname
|
||||||
assert_equal 'jsmith', p.login
|
assert_equal 'jsmith', p.login
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_with_indifferent_access
|
||||||
|
p = Person.new
|
||||||
|
p.safe_attributes = {'firstname' => 'Jack', :lastname => 'Miller'}
|
||||||
|
assert_equal 'Jack', p.firstname
|
||||||
|
assert_equal 'Miller', p.lastname
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_use_safe_attributes_in_subclasses
|
||||||
|
b = Book.new
|
||||||
|
p = PublishedBook.new
|
||||||
|
|
||||||
|
b.safe_attributes = {'title' => 'My awesome Ruby Book', 'isbn' => '1221132343'}
|
||||||
|
p.safe_attributes = {'title' => 'The Pickaxe', 'isbn' => '1934356085'}
|
||||||
|
|
||||||
|
assert_equal 'My awesome Ruby Book', b.title
|
||||||
|
assert_nil b.isbn
|
||||||
|
|
||||||
|
assert_equal 'The Pickaxe', p.title
|
||||||
|
assert_equal '1934356085', p.isbn
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
require File.expand_path('../../../../../../test_helper', __FILE__)
|
||||||
|
begin
|
||||||
|
require 'mocha'
|
||||||
|
|
||||||
|
class BazaarAdapterTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
|
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/bazaar_repository'
|
||||||
|
|
||||||
|
if File.directory?(REPOSITORY_PATH)
|
||||||
|
def setup
|
||||||
|
@adapter = Redmine::Scm::Adapters::BazaarAdapter.new(MODULE_NAME, REPOSITORY_PATH)
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!"
|
||||||
|
def test_fake; assert true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue LoadError
|
||||||
|
class BazaarMochaFake < ActiveSupport::TestCase
|
||||||
|
def test_fake; assert(false, "Requires mocha to run those tests") end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ begin
|
||||||
class CvsAdapterTest < ActiveSupport::TestCase
|
class CvsAdapterTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository'
|
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository'
|
||||||
|
REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
|
||||||
MODULE_NAME = 'test'
|
MODULE_NAME = 'test'
|
||||||
|
|
||||||
if File.directory?(REPOSITORY_PATH)
|
if File.directory?(REPOSITORY_PATH)
|
||||||
|
|
|
@ -1,71 +1,92 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
|
# This file includes UTF-8 "Felix Schäfer".
|
||||||
|
# We need to consider Ruby 1.9 compatibility.
|
||||||
|
|
||||||
require File.expand_path('../../../../../../test_helper', __FILE__)
|
require File.expand_path('../../../../../../test_helper', __FILE__)
|
||||||
|
begin
|
||||||
|
require 'mocha'
|
||||||
|
|
||||||
class GitAdapterTest < ActiveSupport::TestCase
|
class GitAdapterTest < ActiveSupport::TestCase
|
||||||
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
|
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository'
|
||||||
|
|
||||||
if File.directory?(REPOSITORY_PATH)
|
if File.directory?(REPOSITORY_PATH)
|
||||||
def setup
|
def setup
|
||||||
@adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
|
@adapter = Redmine::Scm::Adapters::GitAdapter.new(REPOSITORY_PATH)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_branches
|
||||||
|
assert_equal @adapter.branches, ['master', 'test_branch']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_all_revisions
|
||||||
|
assert_equal 15, @adapter.revisions('',nil,nil,:all => true).length
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_certain_revisions
|
||||||
|
assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_revisions_with_spaces_in_filename
|
||||||
|
assert_equal 1, @adapter.revisions("filemane with spaces.txt",
|
||||||
|
nil, nil, :all => true).length
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
|
||||||
|
assert_equal " filename with a leading space.txt ",
|
||||||
|
@adapter.revisions(" filename with a leading space.txt ",
|
||||||
|
nil, nil, :all => true)[0].paths[0][:path]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_getting_entries_with_leading_and_trailing_spaces_in_filename
|
||||||
|
assert_equal " filename with a leading space.txt ",
|
||||||
|
@adapter.entries('',
|
||||||
|
'83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_annotate
|
||||||
|
annotate = @adapter.annotate('sources/watchers_controller.rb')
|
||||||
|
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
|
||||||
|
assert_equal 41, annotate.lines.size
|
||||||
|
assert_equal "# This program is free software; you can redistribute it and/or", annotate.lines[4].strip
|
||||||
|
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
|
||||||
|
annotate.revisions[4].identifier
|
||||||
|
assert_equal "jsmith", annotate.revisions[4].author
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_annotate_moved_file
|
||||||
|
annotate = @adapter.annotate('renamed_test.txt')
|
||||||
|
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
|
||||||
|
assert_equal 2, annotate.lines.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_last_rev
|
||||||
|
last_rev = @adapter.lastrev("README",
|
||||||
|
"4f26664364207fa8b1af9f8722647ab2d4ac5d43")
|
||||||
|
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
|
||||||
|
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
|
||||||
|
assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
|
||||||
|
assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_last_rev_with_spaces_in_filename
|
||||||
|
last_rev = @adapter.lastrev("filemane with spaces.txt",
|
||||||
|
"ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
|
||||||
|
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
|
||||||
|
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
|
||||||
|
assert_equal "Felix Schäfer <felix@fachschaften.org>",
|
||||||
|
last_rev.author
|
||||||
|
assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "Git test repository NOT FOUND. Skipping unit tests !!!"
|
||||||
|
def test_fake; assert true end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_branches
|
rescue LoadError
|
||||||
assert_equal @adapter.branches, ['master', 'test_branch']
|
class GitMochaFake < ActiveSupport::TestCase
|
||||||
end
|
def test_fake; assert(false, "Requires mocha to run those tests") end
|
||||||
|
|
||||||
def test_getting_all_revisions
|
|
||||||
assert_equal 15, @adapter.revisions('',nil,nil,:all => true).length
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_getting_certain_revisions
|
|
||||||
assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_getting_revisions_with_spaces_in_filename
|
|
||||||
assert_equal 1, @adapter.revisions("filemane with spaces.txt", nil, nil, :all => true).length
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
|
|
||||||
assert_equal " filename with a leading space.txt ", @adapter.revisions(" filename with a leading space.txt ", nil, nil, :all => true)[0].paths[0][:path]
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_getting_entries_with_leading_and_trailing_spaces_in_filename
|
|
||||||
assert_equal " filename with a leading space.txt ", @adapter.entries('', '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_annotate
|
|
||||||
annotate = @adapter.annotate('sources/watchers_controller.rb')
|
|
||||||
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
|
|
||||||
assert_equal 41, annotate.lines.size
|
|
||||||
assert_equal "# This program is free software; you can redistribute it and/or", annotate.lines[4].strip
|
|
||||||
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", annotate.revisions[4].identifier
|
|
||||||
assert_equal "jsmith", annotate.revisions[4].author
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_annotate_moved_file
|
|
||||||
annotate = @adapter.annotate('renamed_test.txt')
|
|
||||||
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
|
|
||||||
assert_equal 2, annotate.lines.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_last_rev
|
|
||||||
last_rev = @adapter.lastrev("README", "4f26664364207fa8b1af9f8722647ab2d4ac5d43")
|
|
||||||
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
|
|
||||||
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
|
|
||||||
assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
|
|
||||||
assert_equal "2009-06-24 05:27:38".to_time, last_rev.time
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_last_rev_with_spaces_in_filename
|
|
||||||
last_rev = @adapter.lastrev("filemane with spaces.txt", "ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
|
|
||||||
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
|
|
||||||
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
|
|
||||||
assert_equal "Felix Schäfer <felix@fachschaften.org>", last_rev.author
|
|
||||||
assert_equal "2010-09-18 19:59:46".to_time, last_rev.time
|
|
||||||
end
|
|
||||||
else
|
|
||||||
puts "Git test repository NOT FOUND. Skipping unit tests !!!"
|
|
||||||
def test_fake; assert true end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,27 @@
|
||||||
|
|
||||||
require File.expand_path('../../../../../../test_helper', __FILE__)
|
require File.expand_path('../../../../../../test_helper', __FILE__)
|
||||||
|
|
||||||
class SubversionAdapterTest < ActiveSupport::TestCase
|
begin
|
||||||
|
require 'mocha'
|
||||||
|
|
||||||
if repository_configured?('subversion')
|
class SubversionAdapterTest < ActiveSupport::TestCase
|
||||||
def test_client_version
|
|
||||||
v = Redmine::Scm::Adapters::SubversionAdapter.client_version
|
if repository_configured?('subversion')
|
||||||
assert v.is_a?(Array)
|
def setup
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_client_version
|
||||||
|
v = Redmine::Scm::Adapters::SubversionAdapter.client_version
|
||||||
|
assert v.is_a?(Array)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "Subversion test repository NOT FOUND. Skipping unit tests !!!"
|
||||||
|
def test_fake; assert true end
|
||||||
end
|
end
|
||||||
else
|
end
|
||||||
puts "Subversion test repository NOT FOUND. Skipping unit tests !!!"
|
|
||||||
def test_fake; assert true end
|
rescue LoadError
|
||||||
|
class SubversionMochaFake < ActiveSupport::TestCase
|
||||||
|
def test_fake; assert(false, "Requires mocha to run those tests") end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -467,6 +467,7 @@ class QueryTest < ActiveSupport::TestCase
|
||||||
@group2 = Group.generate!.reload
|
@group2 = Group.generate!.reload
|
||||||
@group2.users << @user_in_group2
|
@group2.users << @user_in_group2
|
||||||
|
|
||||||
|
@empty_group = Group.generate!.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
should "search assigned to for users in the group" do
|
should "search assigned to for users in the group" do
|
||||||
|
@ -484,7 +485,6 @@ class QueryTest < ActiveSupport::TestCase
|
||||||
# Users not in a group
|
# Users not in a group
|
||||||
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
|
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
|
||||||
assert_find_issues_with_query_is_successful @query
|
assert_find_issues_with_query_is_successful @query
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
should "search assigned to any group member (all)" do
|
should "search assigned to any group member (all)" do
|
||||||
|
@ -494,7 +494,22 @@ class QueryTest < ActiveSupport::TestCase
|
||||||
# Only users in a group
|
# Only users in a group
|
||||||
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
|
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
|
||||||
assert_find_issues_with_query_is_successful @query
|
assert_find_issues_with_query_is_successful @query
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return no results on empty set" do
|
||||||
|
@query = Query.new(:name => '_')
|
||||||
|
@query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
|
||||||
|
|
||||||
|
assert_query_statement_includes @query, "(0=1)"
|
||||||
|
assert find_issues_with_query(@query).empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return results on disallowed empty set" do
|
||||||
|
@query = Query.new(:name => '_')
|
||||||
|
@query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
|
||||||
|
|
||||||
|
assert_query_statement_includes @query, "(1=1)"
|
||||||
|
assert_find_issues_with_query_is_successful @query
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -507,6 +522,7 @@ class QueryTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
@manager_role = Role.generate!(:name => 'Manager')
|
@manager_role = Role.generate!(:name => 'Manager')
|
||||||
@developer_role = Role.generate!(:name => 'Developer')
|
@developer_role = Role.generate!(:name => 'Developer')
|
||||||
|
@empty_role = Role.generate!(:name => 'Empty')
|
||||||
|
|
||||||
@project = Project.generate!
|
@project = Project.generate!
|
||||||
@manager = User.generate!
|
@manager = User.generate!
|
||||||
|
@ -540,6 +556,22 @@ class QueryTest < ActiveSupport::TestCase
|
||||||
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
|
assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
|
||||||
assert_find_issues_with_query_is_successful @query
|
assert_find_issues_with_query_is_successful @query
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "return no results on empty set" do
|
||||||
|
@query = Query.new(:name => '_')
|
||||||
|
@query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
|
||||||
|
|
||||||
|
assert_query_statement_includes @query, "(0=1)"
|
||||||
|
assert find_issues_with_query(@query).empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return results on disallowed empty set" do
|
||||||
|
@query = Query.new(:name => '_')
|
||||||
|
@query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
|
||||||
|
|
||||||
|
assert_query_statement_includes @query, "(1=1)"
|
||||||
|
assert_find_issues_with_query_is_successful @query
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue