Mercurial > hg > soundsoftware-site
comparison app/models/changeset.rb @ 1464:261b3d9a4903 redmine-2.4
Update to Redmine 2.4 branch rev 12663
author | Chris Cannam |
---|---|
date | Tue, 14 Jan 2014 14:37:42 +0000 |
parents | 433d4f72a19b |
children | e248c7af89ec |
comparison
equal
deleted
inserted
replaced
1296:038ba2d95de8 | 1464:261b3d9a4903 |
---|---|
1 # Redmine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2012 Jean-Philippe Lang | 2 # Copyright (C) 2006-2013 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
13 # | 13 # |
14 # You should have received a copy of the GNU General Public License | 14 # You should have received a copy of the GNU General Public License |
15 # along with this program; if not, write to the Free Software | 15 # along with this program; if not, write to the Free Software |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
18 require 'iconv' | |
19 | |
20 class Changeset < ActiveRecord::Base | 18 class Changeset < ActiveRecord::Base |
21 belongs_to :repository | 19 belongs_to :repository |
22 belongs_to :user | 20 belongs_to :user |
23 has_many :filechanges, :class_name => 'Change', :dependent => :delete_all | 21 has_many :filechanges, :class_name => 'Change', :dependent => :delete_all |
24 has_and_belongs_to_many :issues | 22 has_and_belongs_to_many :issues |
47 | 45 |
48 validates_presence_of :repository_id, :revision, :committed_on, :commit_date | 46 validates_presence_of :repository_id, :revision, :committed_on, :commit_date |
49 validates_uniqueness_of :revision, :scope => :repository_id | 47 validates_uniqueness_of :revision, :scope => :repository_id |
50 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true | 48 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true |
51 | 49 |
52 scope :visible, | 50 scope :visible, lambda {|*args| |
53 lambda {|*args| { :include => {:repository => :project}, | 51 includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args)) |
54 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } } | 52 } |
55 | 53 |
56 after_create :scan_for_issues | 54 after_create :scan_for_issues |
57 before_create :before_create_cs | 55 before_create :before_create_cs |
58 | 56 |
59 def revision=(r) | 57 def revision=(r) |
118 return if comments.blank? | 116 return if comments.blank? |
119 # keywords used to reference issues | 117 # keywords used to reference issues |
120 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) | 118 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) |
121 ref_keywords_any = ref_keywords.delete('*') | 119 ref_keywords_any = ref_keywords.delete('*') |
122 # keywords used to fix issues | 120 # keywords used to fix issues |
123 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) | 121 fix_keywords = Setting.commit_update_keywords_array.map {|r| r['keywords']}.flatten.compact |
124 | 122 |
125 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") | 123 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") |
126 | 124 |
127 referenced_issues = [] | 125 referenced_issues = [] |
128 | 126 |
129 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| | 127 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| |
130 action, refs = match[2], match[3] | 128 action, refs = match[2].to_s.downcase, match[3] |
131 next unless action.present? || ref_keywords_any | 129 next unless action.present? || ref_keywords_any |
132 | 130 |
133 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| | 131 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| |
134 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] | 132 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] |
135 if issue | 133 if issue |
136 referenced_issues << issue | 134 referenced_issues << issue |
137 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase) | 135 # Don't update issues or log time when importing old commits |
138 log_time(issue, hours) if hours && Setting.commit_logtime_enabled? | 136 unless repository.created_on && committed_on && committed_on < repository.created_on |
137 fix_issue(issue, action) if fix_keywords.include?(action) | |
138 log_time(issue, hours) if hours && Setting.commit_logtime_enabled? | |
139 end | |
139 end | 140 end |
140 end | 141 end |
141 end | 142 end |
142 | 143 |
143 referenced_issues.uniq! | 144 referenced_issues.uniq! |
210 issue | 211 issue |
211 end | 212 end |
212 | 213 |
213 private | 214 private |
214 | 215 |
215 def fix_issue(issue) | 216 # Updates the +issue+ according to +action+ |
216 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) | 217 def fix_issue(issue, action) |
217 if status.nil? | |
218 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger | |
219 return issue | |
220 end | |
221 | |
222 # the issue may have been updated by the closure of another one (eg. duplicate) | 218 # the issue may have been updated by the closure of another one (eg. duplicate) |
223 issue.reload | 219 issue.reload |
224 # don't change the status is the issue is closed | 220 # don't change the status is the issue is closed |
225 return if issue.status && issue.status.is_closed? | 221 return if issue.status && issue.status.is_closed? |
226 | 222 |
227 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) | 223 journal = issue.init_journal(user || User.anonymous, |
228 issue.status = status | 224 ll(Setting.default_language, |
229 unless Setting.commit_fix_done_ratio.blank? | 225 :text_status_changed_by_changeset, |
230 issue.done_ratio = Setting.commit_fix_done_ratio.to_i | 226 text_tag(issue.project))) |
227 rule = Setting.commit_update_keywords_array.detect do |rule| | |
228 rule['keywords'].include?(action) && | |
229 (rule['if_tracker_id'].blank? || rule['if_tracker_id'] == issue.tracker_id.to_s) | |
230 end | |
231 if rule | |
232 issue.assign_attributes rule.slice(*Issue.attribute_names) | |
231 end | 233 end |
232 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, | 234 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, |
233 { :changeset => self, :issue => issue }) | 235 { :changeset => self, :issue => issue, :action => action }) |
234 unless issue.save | 236 unless issue.save |
235 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger | 237 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger |
236 end | 238 end |
237 issue | 239 issue |
238 end | 240 end |