summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2013-10-05 09:41:11 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2013-10-05 09:41:11 +0000
commita77b462a53a02dbead1042bd12060177ade7b22a (patch)
tree4d58c8dee5c021a8dd1af32a8fbe741e3c6ea1d0 /app
parentb59d10968036b7da57a499895a9a2d91ea227c34 (diff)
downloadredmine-a77b462a53a02dbead1042bd12060177ade7b22a.tar.gz
redmine-a77b462a53a02dbead1042bd12060177ade7b22a.zip
Support for multiple issue update keywords/rules in commit messages (#4911).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12197 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r--app/controllers/settings_controller.rb7
-rw-r--r--app/models/changeset.rb21
-rw-r--r--app/models/setting.rb74
-rw-r--r--app/views/settings/_repositories.html.erb58
4 files changed, 129 insertions, 31 deletions
diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb
index 586c23956..05550bc65 100644
--- a/app/controllers/settings_controller.rb
+++ b/app/controllers/settings_controller.rb
@@ -33,9 +33,7 @@ class SettingsController < ApplicationController
if request.post? && params[:settings] && params[:settings].is_a?(Hash)
settings = (params[:settings] || {}).dup.symbolize_keys
settings.each do |name, value|
- # remove blank values in array settings
- value.delete_if {|v| v.blank? } if value.is_a?(Array)
- Setting[name] = value
+ Setting.set_from_params name, value
end
flash[:notice] = l(:notice_successful_update)
redirect_to settings_path(:tab => params[:tab])
@@ -48,6 +46,9 @@ class SettingsController < ApplicationController
@guessed_host_and_path = request.host_with_port.dup
@guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
+ @commit_update_keywords = Setting.commit_update_keywords.dup
+ @commit_update_keywords[''] = {} if @commit_update_keywords.blank?
+
Redmine::Themes.rescan
end
end
diff --git a/app/models/changeset.rb b/app/models/changeset.rb
index d3fa8ab2b..7920ae078 100644
--- a/app/models/changeset.rb
+++ b/app/models/changeset.rb
@@ -118,21 +118,21 @@ class Changeset < ActiveRecord::Base
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
ref_keywords_any = ref_keywords.delete('*')
# keywords used to fix issues
- fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
+ fix_keywords = Setting.commit_update_by_keyword.keys
kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
referenced_issues = []
comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
- action, refs = match[2], match[3]
+ action, refs = match[2].to_s.downcase, match[3]
next unless action.present? || ref_keywords_any
refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
if issue
referenced_issues << issue
- fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
+ fix_issue(issue, action) if fix_keywords.include?(action)
log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
end
end
@@ -210,12 +210,10 @@ class Changeset < ActiveRecord::Base
private
- def fix_issue(issue)
- status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
- if status.nil?
- logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
- return issue
- end
+ # Updates the +issue+ according to +action+
+ def fix_issue(issue, action)
+ updates = Setting.commit_update_by_keyword[action]
+ return unless updates.is_a?(Hash)
# the issue may have been updated by the closure of another one (eg. duplicate)
issue.reload
@@ -223,10 +221,7 @@ class Changeset < ActiveRecord::Base
return if issue.status && issue.status.is_closed?
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
- issue.status = status
- unless Setting.commit_fix_done_ratio.blank?
- issue.done_ratio = Setting.commit_fix_done_ratio.to_i
- end
+ issue.assign_attributes updates.slice(*Issue.attribute_names)
Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
{ :changeset => self, :issue => issue })
unless issue.save
diff --git a/app/models/setting.rb b/app/models/setting.rb
index a0ab18b5b..71ef15208 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -132,15 +132,87 @@ class Setting < ActiveRecord::Base
def self.#{name}=(value)
self[:#{name}] = value
end
- END_SRC
+END_SRC
class_eval src, __FILE__, __LINE__
end
+ # Sets a setting value from params
+ def self.set_from_params(name, params)
+ params = params.dup
+ params.delete_if {|v| v.blank? } if params.is_a?(Array)
+
+ m = "#{name}_from_params"
+ if respond_to? m
+ self[name.to_sym] = send m, params
+ else
+ self[name.to_sym] = params
+ end
+ end
+
+ # Returns a hash suitable for commit_update_keywords setting
+ #
+ # Example:
+ # params = {:keywords => ['fixes', 'closes'], :status_id => ["3", "5"], :done_ratio => ["", "100"]}
+ # Setting.commit_update_keywords_from_params(params)
+ # # => {'fixes' => {'status_id' => "3"}, 'closes' => {'status_id' => "5", 'done_ratio' => "100"}}
+ def self.commit_update_keywords_from_params(params)
+ s = {}
+ if params.is_a?(Hash) && params.key?(:keywords) && params.values.all? {|v| v.is_a? Array}
+ attributes = params.except(:keywords).keys
+ params[:keywords].each_with_index do |keywords, i|
+ next if keywords.blank?
+ s[keywords] = attributes.inject({}) {|h, a|
+ value = params[a][i].to_s
+ h[a.to_s] = value if value.present?
+ h
+ }
+ end
+ end
+ s
+ end
+
# Helper that returns an array based on per_page_options setting
def self.per_page_options_array
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
end
+ # Helper that returns a Hash with single update keywords as keys
+ def self.commit_update_by_keyword
+ h = {}
+ if commit_update_keywords.is_a?(Hash)
+ commit_update_keywords.each do |keywords, attribute_updates|
+ next unless attribute_updates.is_a?(Hash)
+ attribute_updates = attribute_updates.dup
+ attribute_updates.delete_if {|k, v| v.blank?}
+ keywords.to_s.split(",").map(&:strip).reject(&:blank?).each do |keyword|
+ h[keyword.downcase] = attribute_updates
+ end
+ end
+ end
+ h
+ end
+
+ def self.commit_fix_keywords
+ ActiveSupport::Deprecation.warn "Setting.commit_fix_keywords is deprecated and will be removed in Redmine 3"
+ if commit_update_keywords.is_a?(Hash)
+ commit_update_keywords.keys.first
+ end
+ end
+
+ def self.commit_fix_status_id
+ ActiveSupport::Deprecation.warn "Setting.commit_fix_status_id is deprecated and will be removed in Redmine 3"
+ if commit_update_keywords.is_a?(Hash)
+ commit_update_keywords[commit_fix_keywords]['status_id']
+ end
+ end
+
+ def self.commit_fix_done_ratio
+ ActiveSupport::Deprecation.warn "Setting.commit_fix_done_ratio is deprecated and will be removed in Redmine 3"
+ if commit_update_keywords.is_a?(Hash)
+ commit_update_keywords[commit_fix_keywords]['done_ratio']
+ end
+ end
+
def self.openid?
Object.const_defined?(:OpenID) && self[:openid].to_i > 0
end
diff --git a/app/views/settings/_repositories.html.erb b/app/views/settings/_repositories.html.erb
index 3341de313..d90c212ec 100644
--- a/app/views/settings/_repositories.html.erb
+++ b/app/views/settings/_repositories.html.erb
@@ -65,19 +65,6 @@
<p><%= setting_text_field :commit_ref_keywords, :size => 30 %>
<em class="info"><%= l(:text_comma_separated) %></em></p>
-<p><%= setting_text_field :commit_fix_keywords, :size => 30 %>
-&nbsp;<%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id,
- [["", 0]] +
- IssueStatus.sorted.all.collect{
- |status| [status.name, status.id.to_s]
- },
- :label => false %>
-&nbsp;<%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio,
- (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] },
- :blank => :label_no_change_option,
- :label => false %>
-<em class="info"><%= l(:text_comma_separated) %></em></p>
-
<p><%= setting_check_box :commit_cross_project_ref %></p>
<p><%= setting_check_box :commit_logtime_enabled,
@@ -90,5 +77,48 @@
:disabled => !Setting.commit_logtime_enabled?%></p>
</fieldset>
-<%= submit_tag l(:button_save) %>
+<table class="list" id="commit-keywords">
+ <thead>
+ <tr>
+ <th><%= l(:setting_commit_fix_keywords) %></th>
+ <th><%= l(:label_applied_status) %></th>
+ <th><%= l(:field_done_ratio) %></th>
+ <th class="buttons"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @commit_update_keywords.each do |keywords, updates| %>
+ <tr class="commit-keywords">
+ <td><%= text_field_tag "settings[commit_update_keywords][keywords][]", keywords, :size => 30 %></td>
+ <td><%= select_tag "settings[commit_update_keywords][status_id][]", options_for_select([["", 0]] + IssueStatus.sorted.all.collect{|status| [status.name, status.id.to_s]}, updates['status_id']) %></td>
+ <td><%= select_tag "settings[commit_update_keywords][done_ratio][]", options_for_select([["", ""]] + (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] }, updates['done_ratio']) %></td>
+ <td class="buttons"><%= link_to image_tag('delete.png'), '#', :class => 'delete-commit-keywords' %></td>
+ </tr>
+ <% end %>
+ <tr>
+ <td><em class="info"><%= l(:text_comma_separated) %></em></td>
+ <td></td>
+ <td></td>
+ <td class="buttons"><%= link_to image_tag('add.png'), '#', :class => 'add-commit-keywords' %></td>
+ </tr>
+ </tbody>
+</table>
+
+<p><%= submit_tag l(:button_save) %></p>
+<% end %>
+
+<%= javascript_tag do %>
+$('#commit-keywords').on('click', 'a.delete-commit-keywords', function(e){
+ e.preventDefault();
+ if ($('#commit-keywords tbody tr.commit-keywords').length > 1) {
+ $(this).parents('#commit-keywords tr').remove();
+ } else {
+ $('#commit-keywords tbody tr.commit-keywords').find('input, select').val('');
+ }
+});
+$('#commit-keywords').on('click', 'a.add-commit-keywords', function(e){
+ e.preventDefault();
+ var row = $('#commit-keywords tr.commit-keywords:last');
+ row.clone().insertAfter(row).find('input, select').val('');
+});
<% end %>