quality_meter 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ require 'fileutils'
2
+
3
+ module QaulityMeter
4
+ class ReportController < ::ApplicationController
5
+
6
+ # GET::report#index
7
+ # localhost:3000/qmeter
8
+ def index
9
+ thresholds = {}
10
+ thresholds['security_warnings_min'] = 1
11
+ thresholds['security_warnings_max'] = 100
12
+
13
+ thresholds['rails_best_practices_min'] = 30
14
+ thresholds['rails_best_practices_max'] = 100
15
+
16
+ thresholds['flog_complexity_min'] = 3
17
+ thresholds['flog_complexity_max'] = 25
18
+
19
+ thresholds['stats_ratio_min'] = 0.0
20
+ thresholds['stats_ratio_max'] = 5.0
21
+
22
+ extend QaulityMeter
23
+ # Call methods from lib/qmeter.rb
24
+ self.initialize_thresholds(thresholds)
25
+ self.generate_final_report
26
+ self.choose_color
27
+
28
+ # move report.html from root to the /public folder
29
+ FileUtils.cp('report.html', 'public/') if File.file?("#{Rails.root}/report.html")
30
+
31
+ render layout: false
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,276 @@
1
+ <!DOCTYPE HTML SYSTEM>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>Quality Report</title>
6
+ <%= stylesheet_link_tag 'quality_meter/quality_meter' %>
7
+ <%= javascript_include_tag 'quality_meter/jquery-v1.11.2' %>
8
+ <%= javascript_include_tag 'quality_meter/quality_meter' %>
9
+ <script type="text/javascript">
10
+ // Custom JS
11
+ // Get previous report data
12
+ var data = <%= raw @previous_reports.to_json %>;
13
+
14
+ // Transpose array
15
+ var newArray = data[0].map(function(col, i) {
16
+ return data.map(function(row) {
17
+ return row[i]
18
+ })
19
+ });
20
+
21
+
22
+ // Get time intervals
23
+ time = newArray[newArray.length-1]
24
+
25
+ // Get data of each modules
26
+ arr_flog = newArray[newArray.length-5]
27
+ arr_stats = newArray[newArray.length-4]
28
+ arr_best_practise = newArray[newArray.length-3]
29
+ arr_security_warnings = newArray[newArray.length-2]
30
+
31
+ // Parse flog & stats data into float
32
+ arr_flog_hash = [];
33
+ for( var i = 0, len = arr_flog.length; i < len; i++ ) {
34
+ arr_flog_hash[i] = {X: time[i] , Y: parseFloat( arr_flog[i] ) };
35
+ }
36
+ arr_stats_hash = [];
37
+ for( var i = 0, len = arr_stats.length; i < len; i++ ) {
38
+ arr_stats_hash[i] = {X: time[i], Y: parseFloat( arr_stats[i] )};
39
+ }
40
+ arr_best_practise_hash = [];
41
+ for( var i = 0, len = arr_best_practise.length; i < len; i++ ) {
42
+ arr_best_practise_hash[i] ={X: time[i], Y: parseInt( arr_best_practise[i] )};
43
+ }
44
+ arr_security_warnings_hash = [];
45
+ for( var i = 0, len = arr_security_warnings.length; i < len; i++ ) {
46
+ arr_security_warnings_hash[i] ={X: time[i], Y: parseInt( arr_security_warnings[i] )};
47
+ }
48
+
49
+ var graphdata1 = {
50
+ linecolor: "Random",
51
+ values: arr_flog_hash
52
+ };
53
+
54
+ var graphdata2 = {
55
+ linecolor: "Random",
56
+ values: arr_stats_hash
57
+ };
58
+
59
+ var graphdata3 = {
60
+ linecolor: "Random",
61
+ values: arr_security_warnings_hash
62
+ };
63
+
64
+ var graphdata4 = {
65
+ linecolor: "Random",
66
+ title: 'rails practise',
67
+ values: arr_best_practise_hash
68
+ };
69
+
70
+ $(function () {
71
+ $("#Linegraph").SimpleChart({
72
+ toolwidth: "150",
73
+ toolheight: "25",
74
+ axiscolor: "#E6E6E6",
75
+ textcolor: "#6E6E6E",
76
+ title: 'flog',
77
+ data: [graphdata1],
78
+ });
79
+
80
+ $("#Linegraph1").SimpleChart({
81
+ toolwidth: "150",
82
+ toolheight: "25",
83
+ axiscolor: "#E6E6E6",
84
+ textcolor: "#6E6E6E",
85
+ title: 'stats',
86
+ data: [graphdata2],
87
+ });
88
+
89
+ $("#Linegraph2").SimpleChart({
90
+ toolwidth: "150",
91
+ toolheight: "25",
92
+ axiscolor: "#E6E6E6",
93
+ textcolor: "#6E6E6E",
94
+ title: 'security warnings',
95
+ data: [graphdata3],
96
+ });
97
+
98
+ $("#Linegraph3").SimpleChart({
99
+ toolwidth: "150",
100
+ toolheight: "25",
101
+ axiscolor: "#E6E6E6",
102
+ textcolor: "#6E6E6E",
103
+ title: 'rails practise',
104
+ data: [graphdata4],
105
+ });
106
+ });
107
+ </script>
108
+ </head>
109
+ <body class="quality_meter">
110
+ <h2 class="tophead"> Q-meter Dashboard</h2>
111
+ <%if @app_data.present?%>
112
+ <fieldset>
113
+ <legend>App Info</legend>
114
+ <table>
115
+
116
+ <%#@app_data.each do |k,v|%>
117
+ <tr>
118
+ <td><%=@app_data.keys[0].to_s.humanize%> : </td>
119
+ <td colspan="1"> <%=@app_data.values[0]%></td>
120
+ <td><%=@app_data.keys[1].to_s.humanize%> : </td>
121
+ <td colspan="1"> <%=@app_data.values[1]%></td>
122
+ </tr>
123
+ <tr>
124
+ <td><%=@app_data.keys[2].to_s.humanize%> : </td>
125
+ <td colspan="1"> <%=@app_data.values[2]%></td>
126
+ <td><%=@app_data.keys[3].to_s.humanize%> : </td>
127
+ <td colspan="1"> <%=@app_data.values[3]%></td>
128
+ </tr>
129
+ <tr>
130
+ <td><%=@app_data.keys[4].to_s.humanize%> : </td>
131
+ <td colspan="1"> <%=@app_data.values[4]%></td>
132
+ <td><%=@app_data.keys[5].to_s.humanize%> : </td>
133
+ <td colspan="1"> <%=@app_data.values[5]%></td>
134
+ </tr>
135
+ <%#end%>
136
+ </table>
137
+ </fieldset>
138
+ <%end%>
139
+ <fieldset>
140
+ <legend>Quick View</legend>
141
+ <table class="headings" align="left">
142
+ <tr>
143
+ <th>Stat</th>
144
+ <th >Rails Best Practise</th>
145
+ <th>Code Complexity</th>
146
+ <th>Security Warnings</th>
147
+ </tr>
148
+
149
+ <tr >
150
+ <th>
151
+ <a href="/metric_fu/stats.html" target="_blank">
152
+ <div class="pie" style="<%= @stats_rgy %>">
153
+ <div class="title"></div>
154
+ <div class="outer-right mask" id= "10deg">
155
+ <div class="inner-right"></div>
156
+ </div>
157
+
158
+ <div class="outer-left mask">
159
+ <div class="inner-left"></div>
160
+ </div>
161
+ <div class="content">
162
+ <span><%= @stats_code_to_test_ratio %></span>
163
+ </div>
164
+ </div>
165
+ </a>
166
+ <p></p>
167
+ <a href="/metric_fu/stats.html" target="_blank">Details</a>
168
+ </th>
169
+ <th>
170
+ <a href="/metric_fu/rails_best_practices.html" target="_blank">
171
+ <div class="pie" style="<%= @rails_best_practices_rgy %>">
172
+ <div class="title"></div>
173
+ <div class="outer-right mask" id= "10deg">
174
+ </div>
175
+
176
+ <div class="outer-left mask">
177
+ <div class="inner-left"></div>
178
+ </div>
179
+ <div class="content">
180
+ <span><%= @rails_best_practices_total %></span>
181
+ </div>
182
+ </div>
183
+ </a>
184
+ <p></p>
185
+ <a href="/metric_fu/rails_best_practices.html" target="_blank">Details</a>
186
+ </th>
187
+ <th>
188
+ <a href="/metric_fu/flog.html" target="_blank">
189
+ <div class="pie" style="<%= @flog_rgy %>">
190
+ <div class="title"></div>
191
+ <div class="outer-right mask" id= "10deg">
192
+ <div class="inner-right"></div>
193
+ </div>
194
+
195
+ <div class="outer-left mask">
196
+ <div class="inner-left"></div>
197
+ </div>
198
+ <div class="content">
199
+ <span><%= @flog_average_complexity %></span>
200
+ </div>
201
+ </div>
202
+ </a>
203
+ <p></p>
204
+ <a href="/metric_fu/flog.html" target="_blank">Details</a>
205
+ </th>
206
+ <th>
207
+ <a href="report.html" target="_blank">
208
+ <div class="pie" style="<%= @brakeman_warnings_rgy %>">
209
+ <div class="title"></div>
210
+ <div class="outer-right mask" id= "10deg"></div>
211
+ <div class="inner-right"></div>
212
+
213
+ <div class="outer-left mask">
214
+ <div class="inner-left"></div>
215
+ </div>
216
+ <div class="content">
217
+ <span><%= @warnings_count %></span>
218
+ </div>
219
+ </div>
220
+ </a>
221
+ <p></p>
222
+ <a href="report.html" target="_blank">Details</a>
223
+ </th>
224
+ </tr>
225
+ <tr><td colspan="4"></td></tr>
226
+ <tr>
227
+ <td colspan="4">
228
+ <div class="small-box green-box"></div><span class="small_span">Nice</span>
229
+ <div class="small-box yellow-box"></div><span class="small_span">Good</span>
230
+ <div class="small-box orange-box"></div><span class="small_span">Medium</span>
231
+ <div class="small-box red-box"></div><span class="small_span">Needs Improvement (Low)</span>
232
+ </td>
233
+ </tr>
234
+ </table>
235
+
236
+ </fieldset>
237
+ <fieldset>
238
+ <legend> Security Warning in Detail </legend>
239
+ <table align="right">
240
+ <% unless @brakeman_warnings.blank? %>
241
+ <% @brakeman_warnings.each do |warning| %>
242
+ <tr>
243
+ <td><%= warning[0] %></td>
244
+ <td align="right" style="font-weight:700"><%= warning[1] %></td>
245
+ </tr>
246
+ <% end %>
247
+ <% else %>
248
+ <tr><td>No Security Warnings</td></tr>
249
+ <% end %>
250
+ </table>
251
+ </fieldset>
252
+ <fieldset>
253
+ <legend> Commit Wise Reports (History) </legend>
254
+ <table align="center">
255
+ <tr>
256
+ <% unless @previous_reports.blank? %>
257
+ <tr>
258
+ <th><div id="Linegraph2" style=" height: 200px"></div></th>
259
+ <tr><th> <div id="Linegraph3" style=" height: 200px"></div></th>
260
+ </tr>
261
+ <tr>
262
+ <th><div id="Linegraph" style="height: 200px"></div></th>
263
+ </tr>
264
+ <tr><th><div id="Linegraph1" style="height: 200px"></div></th></tr>
265
+ <!-- tr bgcolor="#A5FF88">
266
+ <td colspan="2" align="center" style="font-size: 9pt;"><%#= "Generated on #{Time.now}" %></td>
267
+ </tr> -->
268
+ <% else %>
269
+ <div class='git-commit'>No commits with quality_meter yet</div>
270
+ <% end %>
271
+ </table> <!-- -->
272
+ </fieldset>
273
+
274
+ <body>
275
+ </html>
276
+
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ QualityMeter::Engine.routes.draw do
2
+ get 'qmeter' => 'quality_meter/report#index'
3
+ get 'qmeter/js_cs' => 'quality_meter/report#js_cs'
4
+ end
@@ -0,0 +1,170 @@
1
+ require "qmeter/version"
2
+ require 'qmeter/railtie' if defined?(Rails)
3
+ require "csv"
4
+ require "qmeter/engine"
5
+
6
+ module QualityMeter
7
+ def initialize_thresholds(thresholds)
8
+ # Initialize threshold values
9
+ @security_warnings_min = thresholds['security_warnings_min']
10
+ @security_warnings_max = thresholds['security_warnings_max']
11
+
12
+ @rails_best_practices_min = thresholds['rails_best_practices_min']
13
+ @rails_best_practices_max = thresholds['rails_best_practices_max']
14
+
15
+ @flog_complexity_min = thresholds['flog_complexity_min']
16
+ @flog_complexity_max = thresholds['flog_complexity_max']
17
+
18
+ @stats_ratio_min = thresholds['stats_ratio_min']
19
+ @stats_ratio_max = thresholds['stats_ratio_max']
20
+
21
+ @app_data = []
22
+ end
23
+
24
+ def collect_brakeman_details
25
+ # Breakman source file
26
+ file = check_and_assign_file_path('report.json')
27
+ if file
28
+ data_hash = JSON.parse(file)
29
+ ### change array to hash and check it contain warnings or not
30
+ if data_hash.present? && data_hash.class == Hash ? data_hash.has_key?('warnings') : data_hash[0].has_key?('warnings')
31
+ warning_type = data_hash['warnings'].map {|a| a = a['warning_type'] }
32
+ assign_warnings(warning_type, data_hash['warnings'].count)
33
+ elsif data_hash[0].has_key?('warning_type')
34
+ assign_warnings([data_hash[0]['warning_type']])
35
+ end
36
+ end
37
+ end
38
+
39
+ def collect_app_data
40
+ @app_data = {app_path: "/home/arpit/applications/G8way/g8way",rails_version: "3.2.11",security_warnings: 84}
41
+ # Breakman source file
42
+ file = check_and_assign_file_path('report.json')
43
+ if file
44
+ data_hash = JSON.parse(file)
45
+ # change array to hash and check it contain warnings or not
46
+ if data_hash.present? && data_hash.has_key?('scan_info')
47
+ @app_data = {application: data_hash['scan_info']['app_path'].split("/").last, ruby_version: data_hash['scan_info']['ruby_version'], rails_version: data_hash['scan_info']['rails_version'], number_of_models: data_hash['scan_info']['number_of_models'], number_of_controllers: data_hash['scan_info']['number_of_controllers'], number_of_templates: data_hash['scan_info']['number_of_templates']}
48
+ end
49
+ end
50
+ end
51
+
52
+ ### Assign warnings to @breakeman_warnings ###
53
+ def assign_warnings(warning_type, warnings_count=1)
54
+ @brakeman_warnings = Hash.new(0)
55
+ # warning_type = data_hash[0]['warning_type']
56
+ @warnings_count = warnings_count
57
+ warning_type.each do |v|
58
+ @brakeman_warnings[v] += 1
59
+ end
60
+ end
61
+
62
+ def collect_metric_fu_details
63
+ # parsing metric_fu report from .yml file
64
+ file = check_and_assign_file_path('tmp/metric_fu/report.yml')
65
+ if file
66
+ @surveys = YAML.load(ERB.new(file).result)
67
+ @surveys.each do |survey|
68
+ assign_status(survey) if survey.present?
69
+ end
70
+ end
71
+ end
72
+
73
+ ### assing ration ,complexity and bestpractice of code ###
74
+ def assign_status(survey)
75
+ case survey[0]
76
+ when :flog
77
+ @flog_average_complexity = survey[1][:average].round(1)
78
+ when :stats
79
+ @stats_code_to_test_ratio = survey[1][:code_to_test_ratio]
80
+ when :rails_best_practices
81
+ @rails_best_practices_total = survey[1][:total].first.gsub(/[^\d]/, '').to_i
82
+ end
83
+ end
84
+
85
+ def generate_final_report
86
+ collect_app_data
87
+ collect_metric_fu_details
88
+ collect_brakeman_details
89
+ @app_root = Rails.root
90
+ get_previour_result
91
+ end
92
+
93
+ def save_report
94
+ # Save report data into the CSV
95
+ ### Hide this because we are not using this currently
96
+ #flag = false
97
+ #flag = File.file?("#{Rails.root}/qmeter.csv")
98
+ CSV.open("#{Rails.root}/qmeter.csv", "a") do |csv|
99
+ #csv << ['flog','stats','rails_best_practices','warnings', 'timestamp'] if flag == false
100
+ sha = `git rev-parse HEAD`
101
+ csv << [@flog_average_complexity, @stats_code_to_test_ratio, @rails_best_practices_total, @warnings_count, sha]
102
+ end
103
+ end
104
+
105
+ def get_previour_result
106
+ # Get previous report data
107
+ @previous_reports = CSV.read("#{Rails.root}/qmeter.csv").last(4) if File.file?("#{Rails.root}/qmeter.csv")
108
+ end
109
+
110
+ def choose_color
111
+ # Check threashhold
112
+ ### set color to the variables ###
113
+ @brakeman_warnings_rgy = set_color(@warnings_count, @security_warnings_max, @security_warnings_min)
114
+ @rails_best_practices_rgy = set_color(@rails_best_practices_total, @rails_best_practices_max, @rails_best_practices_min)
115
+ @flog_rgy = set_color(@flog_average_complexity, @flog_complexity_max, @flog_complexity_min)
116
+ @stats_rgy = set_stat_color(@stats_code_to_test_ratio, @stats_ratio_max, @stats_ratio_min )
117
+ end
118
+
119
+ ### method to check file is exist or not ###
120
+ def check_and_assign_file_path(path)
121
+ file = "#{Rails.root}/#{path}"
122
+ File.exist?(file) ? File.read(path) : nil
123
+ end
124
+
125
+ ### send proper color according to data ###
126
+ def set_color(count, max, min)
127
+ if count.present? && count > max
128
+ 'background-color:#D00000;'
129
+ elsif count.present? && count > min && count < max
130
+ avg = max.to_f / 2.to_f
131
+ low_avg = avg / 2.to_f
132
+ high_avg = avg + low_avg
133
+ if count >= high_avg
134
+ 'background-color:#D00000;'
135
+ elsif count >= avg && count < high_avg
136
+ 'background-color:orange;'
137
+ elsif count <= low_avg
138
+ 'background-color:green;'
139
+ elsif count >= low_avg
140
+ 'background-color:yellow;'
141
+ else
142
+ 'background-color:#D00000;'
143
+ end
144
+ else
145
+ 'background-color:#006633;'
146
+ end
147
+ end
148
+
149
+ ### @arpit: send proper color according to data ###
150
+ def set_stat_color(count, max, min)
151
+ if count.present? && count > max
152
+ 'background-color:#D00000;'
153
+ elsif count.present? && count > min && count < max
154
+ avg = max.to_f / 2.to_f
155
+ low_avg = avg / 2.to_f
156
+ if count > avg
157
+ 'background-color:green;'
158
+ elsif count < avg && count < low_avg
159
+ 'background-color:#D00000;'
160
+ elsif count < avg && count > low_avg
161
+ 'background-color:orange;'
162
+ else
163
+ 'background-color:#D00000;'
164
+ end
165
+ else
166
+ 'background-color:#006633;'
167
+ end
168
+
169
+ end
170
+ end