1 # $Id$ |
2 |
3 require 'redmine/version' |
4 |
5 module RedmineHudson |
6 module RedmineExt |
7 |
8 def RedmineExt.redmine_090_or_higher? |
9 return !(Redmine::VERSION::MAJOR == 0 && Redmine::VERSION::MINOR < 9) |
10 end |
11 |
12 module QueryPatch |
13 def self.included(base) # :nodoc: |
14 base.extend(ClassMethods) |
15 |
16 base.send(:include, InstanceMethods) |
17 base.send(:include, InstanceMethodsFor09Later) if RedmineHudson::RedmineExt.redmine_090_or_higher? |
18 base.send(:include, InstanceMethodsFor08) unless RedmineHudson::RedmineExt.redmine_090_or_higher? |
19 |
20 # Same as typing in the class |
21 base.class_eval do |
22 unloadable # Send unloadable so it will not be unloaded in development |
23 |
24 alias_method_chain :available_filters, :redmine_hudson unless method_defined?(:available_filters_without_redmine_hudson) |
25 alias_method_chain :sql_for_field, :redmine_hudson unless method_defined?(:sql_for_field_without_redmine_hudson) |
26 end |
27 |
28 end |
29 end |
30 |
31 module ClassMethods |
32 |
33 unless Query.respond_to?(:available_columns=) |
34 # Setter for +available_columns+ that isn't provided by the core. |
35 def available_columns=(v) |
36 self.available_columns = (v) |
37 end |
38 end |
39 |
40 unless Query.respond_to?(:add_available_column) |
41 # Method to add a column to the +available_columns+ that isn't provided by the core. |
42 def add_available_column(column) |
43 self.available_columns << (column) |
44 end |
45 end |
46 end |
47 |
48 module InstanceMethods |
49 |
50 def available_filters_with_redmine_hudson |
51 return @available_filters if @available_filters |
52 |
53 available_filters_without_redmine_hudson |
54 |
55 return @available_filters unless project |
56 |
57 hudson_filters |
58 |
59 @hudson_filters.each do |filter| |
60 @available_filters[filter.name] = filter.available_values |
61 end |
62 return @available_filters |
63 end |
64 |
65 def sql_for_hudson_build(field, operator, value) |
66 return sql_for_always_false unless project |
67 |
68 hudson_changesets = find_hudson_changesets |
69 |
70 return sql_for_issues(hudson_changesets) |
71 end |
72 |
73 def sql_for_hudson_job(field, operator, value) |
74 return sql_for_always_false unless project |
75 |
76 if filters.has_key?('hudson_build') |
77 return sql_for_always_true |
78 end |
79 |
80 hudson_changesets = find_hudson_changesets |
81 |
82 return sql_for_issues(hudson_changesets) |
83 end |
84 |
85 def find_hudson_changesets |
86 |
87 retval = [] |
88 find_hudson_jobs.each do |job| |
89 builds = find_hudson_builds(job) |
90 next if builds.length == 0 |
91 cond_builds = builds.collect{|build| "#{connection.quote_string(build.id.to_s)}"}.join(",") |
92 retval += HudsonBuildChangeset.find(:all, :conditions => ["#{HudsonBuildChangeset.table_name}.hudson_build_id in (#{cond_builds})"], :order => "#{HudsonBuildChangeset.table_name}.id DESC", :limit => Hudson.query_limit_changesets_each_job) |
93 end |
94 |
95 return retval |
96 |
97 end |
98 |
99 def find_hudson_builds(job) |
100 return [] unless job |
101 |
102 if filters.has_key?('hudson_build') |
103 cond_builds = conditions_for('hudson_build', operator_for('hudson_build'), values_for('hudson_build')) |
104 else |
105 cond_builds = "#{HudsonBuild.table_name}.id > 0" #always true |
106 end |
107 |
108 return HudsonBuild.find(:all, :conditions => ["#{HudsonBuild.table_name}.hudson_job_id = ? and #{cond_builds}", job.id], :order => "#{HudsonBuild.table_name}.number DESC", :limit => Hudson.query_limit_builds_each_job) |
109 end |
110 |
111 def find_hudson_jobs |
112 return [] unless project |
113 |
114 if filters.has_key?('hudson_job') |
115 cond_jobs = "#{HudsonJob.table_name}.project_id = #{project.id} and #{conditions_for('hudson_job', operator_for('hudson_job'), values_for('hudson_job'))}" |
116 else |
117 cond_jobs = "#{HudsonJob.table_name}.project_id = #{project.id}" |
118 end |
119 return HudsonJob.find(:all, :conditions => cond_jobs) |
120 end |
121 |
122 |
123 # conditions always true |
124 def sql_for_always_true |
125 return "#{Issue.table_name}.id > 0" |
126 end |
127 |
128 # conditions always false |
129 def sql_for_always_false |
130 return "#{Issue.table_name}.id < 0" |
131 end |
132 |
133 def sql_for_issues(hudson_changesets) |
134 |
135 return sql_for_always_false unless hudson_changesets |
136 return sql_for_always_false if hudson_changesets.length == 0 |
137 |
138 value_revisions = hudson_changesets.collect{|target| "#{connection.quote_string(target.revision.to_s)}"}.join(",") |
139 sql = "#{Issue.table_name}.id in" |
140 sql << "(select changesets_issues.issue_id from changesets_issues" |
141 sql << " where changesets_issues.changeset_id in" |
142 sql << " (select #{Changeset.table_name}.id from #{Changeset.table_name}" |
143 sql << " where #{Changeset.table_name}.repository_id = #{project.repository.id}" |
144 sql << " and #{Changeset.table_name}.revision in (#{value_revisions})" |
145 sql << " )" |
146 sql << ")" |
147 |
148 return sql |
149 end |
150 |
151 def conditions_for(field, operator, value) |
152 retval = "" |
153 |
154 available_filters |
155 return retval unless @hudson_filters |
156 filter = @hudson_filters.detect {|hfilter| hfilter.name == field} |
157 return retval unless filter |
158 db_table = filter.db_table |
159 db_field = filter.db_field |
160 |
161 case operator |
162 when "=" |
163 retval = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" |
164 when "!" |
165 retval = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" |
166 when "!*" |
167 retval = "#{db_table}.#{db_field} IS NULL" |
168 retval << " OR #{db_table}.#{db_field} = ''" |
169 when "*" |
170 retval = "#{db_table}.#{db_field} IS NOT NULL" |
171 retval << " AND #{db_table}.#{db_field} <> ''" |
172 when ">=" |
173 retval = "#{db_table}.#{db_field} >= #{value.first.to_i}" |
174 when "<=" |
175 retval = "#{db_table}.#{db_field} <= #{value.first.to_i}" |
176 when "!~" |
177 retval = "#{db_table}.#{db_field} NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" |
178 end |
179 return retval |
180 end |
181 |
182 def hudson_filters |
183 |
184 @hudson_filters = [] |
185 return @hudson_filters unless project |
186 return @hudson_filters unless @available_filters |
187 |
188 hudson = Hudson.find_by_project_id(project.id) |
189 return @hudson_filters unless hudson |
190 |
191 @hudson_filters << HudsonQueryFilter.new("hudson_job", |
192 { :type => :list_optional, :order => @available_filters.size + 1, |
193 :values => HudsonJob.find(:all, :conditions => ["#{HudsonJob.table_name}.project_id = ?", project.id], |
194 :order => "#{HudsonJob.table_name}.name").collect {|job| |
195 next unless hudson.settings.job_include?(job.name) |
196 [job.name, job.id.to_s] |
197 } |
198 }, |
199 HudsonJob.table_name, |
200 "id") |
201 @hudson_filters << HudsonQueryFilter.new("hudson_build", |
202 { :type => :integer, :order => @available_filters.size + 2 }, |
203 HudsonBuild.table_name, |
204 "number") |
205 |
206 return @hudson_filters |
207 |
208 end |
209 |
210 end #InstanceMethods |
211 |
212 module InstanceMethodsFor09Later |
213 def sql_for_field_with_redmine_hudson(field, operator, value, db_table, db_field, is_custom_filter=false) |
214 case field |
215 when "hudson_build" |
216 return sql_for_hudson_build(field, operator, value) |
217 |
218 when "hudson_job" |
219 return sql_for_hudson_job(field, operator, value) |
220 |
221 else |
222 return sql_for_field_without_redmine_hudson(field, operator, value, db_table, db_field, is_custom_filter) |
223 end |
224 end |
225 end #InstanceMethodsFor09Later |
226 |
227 module InstanceMethodsFor08 |
228 def sql_for_field_with_redmine_hudson(field, value, db_table, db_field, is_custom_filter) |
229 operator = operator_for field |
230 case field |
231 when "hudson_build" |
232 return sql_for_hudson_build(field, operator, value) |
233 |
234 when "hudson_job" |
235 return sql_for_hudson_job(field, operator, value) |
236 |
237 else |
238 return sql_for_field_without_redmine_hudson(field, value, db_table, db_field, is_custom_filter) |
239 end |
240 end |
241 end #InstanceMethodsFor08 |
242 |
243 end #RedmineExt |
244 end #RedmineHudson |