From 7aa6f8fd79691c00056d901a367999ab565921b1 Mon Sep 17 00:00:00 2001 From: simonbrandhof Date: Wed, 30 Mar 2011 16:02:04 +0200 Subject: [PATCH] SONAR-1332 profile comparison tool --- .../app/controllers/profiles_controller.rb | 160 +++++++++++++++++- .../WEB-INF/app/helpers/profiles_helper.rb | 12 ++ .../app/views/profiles/_diff_rule.html.erb | 3 + .../app/views/profiles/compare.html.erb | 136 +++++++++++++++ .../WEB-INF/app/views/profiles/index.html.erb | 11 +- .../src/main/webapp/images/compare.png | Bin 0 -> 593 bytes .../src/main/webapp/images/switch.png | Bin 0 -> 3223 bytes .../src/main/webapp/stylesheets/style.css | 27 ++- 8 files changed, 344 insertions(+), 5 deletions(-) create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_diff_rule.html.erb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/profiles/compare.html.erb create mode 100644 sonar-server/src/main/webapp/images/compare.png create mode 100644 sonar-server/src/main/webapp/images/switch.png diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb index 1f068161adf..24339483e4a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb @@ -197,7 +197,8 @@ class ProfilesController < ApplicationController @select_parent = [['None', nil]] + profiles.collect{ |profile| [profile.name, profile.name] } end - + + # # # POST /profiles/change_parent?id=&parent_name= @@ -282,8 +283,165 @@ class ProfilesController < ApplicationController end + # + # + # GET /profiles/compare?id1=&id2= + # + # + def compare + @profiles = Profile.find(:all, :conditions => ['enabled=?', true], :order => 'language asc, name') + if params[:id1].present? && params[:id2].present? + @profile1 = Profile.find(params[:id1]) + @profile2 = Profile.find(params[:id2]) + + arules1 = ActiveRule.find(:all, :include => [{:active_rule_parameters => :rules_parameter}, :rule], + :conditions => ['active_rules.profile_id=?', @profile1.id]) + arules2 = ActiveRule.find(:all, :order => 'rules.plugin_name, rules.plugin_rule_key', :include => [{:active_rule_parameters => :rules_parameter}, :rule], + :conditions => ['active_rules.profile_id=?', @profile2.id]) + + diffs_by_rule={} + arules1.each do |arule1| + diffs_by_rule[arule1.rule]||=RuleDiff.new(arule1.rule) + diffs_by_rule[arule1.rule].arule1=arule1 + end + arules2.each do |arule2| + diffs_by_rule[arule2.rule]||=RuleDiff.new(arule2.rule) + diffs_by_rule[arule2.rule].arule2=arule2 + end + @in1=[] + @in2=[] + @modified=[] + @sames=[] + diffs_by_rule.values.sort.each do |diff| + case diff.status + when DIFF_IN1: @in1<(other) + rule.name()<=>other.rule.name + end + end + + # + # Remove active rules that are identical in both collections (same severity and same parameters) + # and return a map with results {:added => X, :removed => Y, :modified => Z, + # :rules => {rule1 => [activeruleleft1, activeruleright1], rule2 => [activeruleleft2, nil], ...]} + # Assume both collections are ordered by rule key + # + def compute_diff(arules1, arules2) + rules = {} + removed = 0 + added = 0 + modified = 0 + same = 0 + begin + diff = false + #take first item of each collection + active_rule1 = arules1.first + active_rule2 = arules2.first + if active_rule1 != nil and active_rule2 != nil + order = active_rule1.rule.key <=> active_rule2.rule.key + if order < 0 + active_rule2 = nil + rule = active_rule1.rule + diff = true + removed = removed +1 + elsif order > 0 + active_rule1 = nil + rule = active_rule2.rule + diff = true + added = added +1 + else + rule = active_rule1.rule # = active_rule2.rule + #compare severity + diff = true if active_rule1.priority != active_rule2.priority + #compare parameters + rule.parameters.each do |param| + diff = true if active_rule1.value(param.id) != active_rule2.value(param.id) + end + if diff + modified = modified + 1 + else + same = same +1 + end + end + elsif active_rule1 != nil + #no more rule in right collection + diff = true + removed = removed +1 + rule = active_rule1.rule + elsif active_rule2 != nil + #no more rule in left collection + diff = true + added = added +1 + rule = active_rule2.rule + end + # remove processed rule(s) + arules1 = arules1.drop(1) if active_rule1 != nil + arules2 = arules2.drop(1) if active_rule2 != nil + if diff + rules[rule] = [active_rule1, active_rule2] + end + end while !arules1.empty? || !arules2.empty? + return {:same => same, :added => added, :removed => removed, :modified => modified, :rules => rules} + end + def read_file_param(configuration_file) # configuration file is a StringIO if configuration_file.respond_to?(:read) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/profiles_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/profiles_helper.rb index d9e3d3a5db5..3c2146fb835 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/profiles_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/profiles_helper.rb @@ -32,4 +32,16 @@ module ProfilesHelper end label end + + def options_for_profiles(profiles, selected_id=nil) + html="" + profiles.group_by(&:language).each do |language, profiles| + html += "" + profiles.each do |profile| + html += "" + end + html += "" + end + html + end end \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_diff_rule.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_diff_rule.html.erb new file mode 100644 index 00000000000..9b7acaec2d7 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_diff_rule.html.erb @@ -0,0 +1,3 @@ +<%= image_tag "priority/#{arule.priority}.png" %> + +<%= h(arule.rule.name) -%> <%= h(arule.rule.plugin_name) -%> \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/compare.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/compare.html.erb new file mode 100644 index 00000000000..70235457779 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/compare.html.erb @@ -0,0 +1,136 @@ +

<%= link_to 'Quality profiles', :controller => 'profiles', :action => 'index' -%> / Compare

+ +
+ + + + + <% if @profile1 && @profile2 %> + <%= image_tag 'switch.png'-%> + <% end %> +
+ +<% if @profile1 && @profile2 %> + + + + +<% unless @in1.empty? %> + + + + + +<% end %> + +<% unless @in2.empty? %> + + + + + +<% end %> + + +<% unless @modified.empty? %> + + + +<% end %> + +<% unless @sames.empty? %> + + + +<% end %> + +
+ + + + + + + <% @in1.each do |diff| %> + + + + <% end %> +
<%= @in1.size -%> rules only in <%= h @profile1.name %>
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule1} %> +
+
+ + + + + + + <% @in2.each do |diff| %> + + + + <% end %> +
<%= @in2.size -%> rules only in <%= h @profile2.name %>
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule2} %> +
+
+ + + + + + + + + <% @modified.each do |diff| + td_css=cycle('even','odd', :name => 'modified') + %> + + + + + + <% end %> +
<%= @modified.size -%> rules have a different configuration
+ <%= h @profile1.name %> +

<%= h @profile2.name %>
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule1} %> + <% if diff.removed_params && !diff.removed_params.empty? %> +
    + <% diff.removed_params.each do |parameter| %> +
  • <%= h(parameter.name) -%>: <%= parameter.value.gsub(',', ', ') -%>
  • + <% end %> +
+ <% end %> +
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule2} %> + <% if diff.added_params && !diff.added_params.empty? %> +
    + <% diff.added_params.each do |parameter| %> +
  • <%= h(parameter.name) -%>: <%= parameter.value.gsub(',', ', ') -%>
  • + <% end %> +
+ <% end %> +
+
+ + + + + + + + + + + +
<%= @sames.size -%> rules have the same configuration
Not displayed
+
+<% end %> \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb index 48cb7947eb3..c3d2cf5104e 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb @@ -1,7 +1,12 @@ <% if administrator? %>
-
    -
  • + @@ -15,7 +20,7 @@ - + Cancel diff --git a/sonar-server/src/main/webapp/images/compare.png b/sonar-server/src/main/webapp/images/compare.png new file mode 100644 index 0000000000000000000000000000000000000000..a61ec134324c862aeb41cd9e4c43bf9167af17f4 GIT binary patch literal 593 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