maximus 0.1.5.1 → 0.1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,13 @@ module Maximus
17
17
  defined?(Rails)
18
18
  end
19
19
 
20
+ # See if project is a Middleman app
21
+ # @since 0.1.7
22
+ # @return [Boolean]
23
+ def is_middleman?
24
+ Gem::Specification::find_all_by_name('middleman').any?
25
+ end
26
+
20
27
  # Get root directory of file being called
21
28
  # @return [String] absolute path to root directory
22
29
  def root_dir
@@ -37,20 +44,11 @@ module Maximus
37
44
  end
38
45
  end
39
46
 
40
- # Look for a file in the config directory
41
- #
42
- # @since 0.1.0
43
- # @param file [String] filename with extension to search for
44
- # @return [String] path to default config file or file in user's directory
45
- def check_default_config_path(file)
46
- File.exist?(file) ? file : File.join(File.dirname(__FILE__), file)
47
- end
48
-
49
47
  # Grab the absolute path of the reporter file
50
48
  # @param filename [String]
51
49
  # @return [String] absolute path to the reporter file
52
50
  def reporter_path(filename)
53
- File.join(File.dirname(__FILE__), "reporter/#{filename}")
51
+ File.join(File.dirname(__FILE__), 'reporter', filename)
54
52
  end
55
53
 
56
54
  # Find all files that were linted by extension
@@ -99,25 +97,6 @@ module Maximus
99
97
  STDIN.gets
100
98
  end
101
99
 
102
- # Convert the array from lines_added into spelled-out ranges
103
- # This is a GitControl helper but it's used in Lint
104
- # @see GitControl#lines_added
105
- # @see Lint#relevant_lint
106
- #
107
- # @example typical output
108
- # lines_added = {changes: ['0..10', '11..14']}
109
- # lines_added_to_range(lines_added)
110
- # # output
111
- # [0,1,2,3,4,5,6,7,8,9,10, 11,12,13,14]
112
- #
113
- # @todo I'm sure there's a better way of doing this
114
- # @todo figure out a better place to put this than in Helper
115
- # @return [Hash] changes_array of spelled-out arrays of integers
116
- def lines_added_to_range(file)
117
- changes_array = file[:changes].map { |ch| ch.split("..").map(&:to_i) }
118
- changes_array.map { |e| (e[0]..e[1]).to_a }.flatten!
119
- end
120
-
121
100
  # Ensure path exists
122
101
  # @param path [String, Array] path to files can be directory or glob
123
102
  # @return [Boolean]
@@ -131,6 +110,7 @@ module Maximus
131
110
  end
132
111
  end
133
112
  else
113
+ path = path.gsub('/**', '').gsub('/*', '').split('.')[0..1].first if path.include?('*')
134
114
  if File.exist?(path)
135
115
  return true
136
116
  else
@@ -140,5 +120,22 @@ module Maximus
140
120
  end
141
121
  end
142
122
 
123
+ # Default paths to check for lints and some stats
124
+ # @since 0.1.7
125
+ # @param root [String] base directory
126
+ # @param folder [String] nested folder to search for for Rails or Middleman
127
+ # @param extension [String] file glob type to search for if neither
128
+ # @return [String] path to desired files
129
+ def discover_path(root = @config.working_dir, folder = '', extension = '')
130
+ return @path unless @path.blank?
131
+ if is_rails?
132
+ File.join(root, 'app', 'assets', folder)
133
+ elsif is_middleman?
134
+ File.join(root, 'source', folder)
135
+ else
136
+ extension.blank? ? File.join(root) : File.join(root, '/**', "/*.#{extension}")
137
+ end
138
+ end
139
+
143
140
  end
144
141
  end
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require 'rainbow'
2
3
 
3
4
  module Maximus
4
5
 
@@ -48,27 +49,18 @@ module Maximus
48
49
  # @param data [Hash] unfiltered lint data
49
50
  # @return [Hash] refined lint data and all the other bells and whistles
50
51
  def refine(data)
52
+ @task ||= ''
51
53
 
52
- # Prevent abortive empty JSON.parse error
53
- data = '{}' if data.blank?
54
- return puts "Error from #{@task}: #{data}" if data.is_a?(String) && data.include?('No such')
55
-
56
- data = data.is_a?(String) ? JSON.parse(data) : data
57
-
58
- @output[:relevant_lints] = relevant_lints( data, @git_files ) unless @git_files.blank?
59
- unless @settings[:commit].blank?
60
- data = @output[:relevant_lints]
61
- end
54
+ data = parse_data(data)
55
+ return puts data if data.is_a?(String)
62
56
 
63
57
  evaluate_severities(data)
64
58
 
65
- lint_count = (@output[:lint_errors].length + @output[:lint_warnings].length + @output[:lint_conventions].length + @output[:lint_refactors].length)
66
-
67
59
  puts lint_summarize
68
60
 
69
61
  if @config.is_dev?
70
- puts lint_dev_format(data) unless data.blank?
71
- lint_ceiling lint_count
62
+ puts lint_dev_format(data)
63
+ lint_ceiling
72
64
  else
73
65
  # Because this should be returned in the format it was received
74
66
  @output[:raw_data] = data.to_json
@@ -84,7 +76,7 @@ module Maximus
84
76
  # @param delimiter [String] comma or space separated
85
77
  # @param remove [String] remove from all file names
86
78
  # @return all_files [Array<string>] list of file names
87
- def files_inspected(ext, delimiter = ',', remove = @settings[:root_dir])
79
+ def files_inspected(ext, delimiter = ',', remove = @config.working_dir)
88
80
  @path.is_a?(Array) ? @path.split(delimiter) : file_list(@path, ext, remove)
89
81
  end
90
82
 
@@ -98,24 +90,26 @@ module Maximus
98
90
 
99
91
  # sometimes data will be blank but this is good - it means no errors were raised in the lint
100
92
  next if lint.blank?
101
- lint_file = lint[file[:filename].to_s]
93
+ lint_file = lint[file[:filename]]
94
+
95
+ next if lint_file.blank?
102
96
 
103
97
  expanded = lines_added_to_range(file)
104
- revert_name = file[:filename].gsub("#{@settings[:root_dir]}/", '')
105
- unless lint_file.blank?
106
- all_files[revert_name] = []
107
-
108
- # @todo originally I tried .map and delete_if, but this works,
109
- # and the other method didn't cover all bases.
110
- # Gotta be a better way to write this though
111
- lint_file.each do |l|
112
- if expanded.include?(l['line'].to_i)
113
- all_files[revert_name] << l
114
- end
98
+ revert_name = strip_working_dir(file[:filename])
99
+
100
+ all_files[revert_name] = []
101
+
102
+ # @todo originally I tried .map and delete_if, but this works,
103
+ # and the other method didn't cover all bases.
104
+ # Gotta be a better way to write this though
105
+ lint_file.each do |l|
106
+ if expanded.include?(l['line'].to_i)
107
+ all_files[revert_name] << l
115
108
  end
116
- # If there's nothing there, then it definitely isn't a relevant lint
117
- all_files.delete(revert_name) if all_files[revert_name].blank?
118
109
  end
110
+
111
+ # If there's nothing there, then it definitely isn't a relevant lint
112
+ all_files.delete(revert_name) if all_files[revert_name].blank?
119
113
  end
120
114
  @output[:files_linted] = all_files.keys
121
115
  all_files
@@ -138,36 +132,56 @@ module Maximus
138
132
  @output[:lint_errors] = []
139
133
  @output[:lint_conventions] = []
140
134
  @output[:lint_refactors] = []
135
+ @output[:lint_fatals] = []
136
+
141
137
  return if data.blank?
138
+
142
139
  data.each do |filename, error_list|
143
140
  error_list.each do |message|
144
141
  # so that :raw_data remains unaffected
145
142
  message = message.clone
146
143
  message.delete('length')
147
- message['filename'] = filename.nil? ? '' : filename.gsub("#{@settings[:root_dir]}/", '')
148
- severity = message['severity']
144
+ message['filename'] = filename.nil? ? '' : strip_working_dir(filename)
145
+ severity = "lint_#{message['severity']}s".to_sym
149
146
  message.delete('severity')
150
- @output["lint_#{severity}s".to_sym] << message
147
+ @output[severity] << message if @output.key?(severity)
151
148
  end
152
149
  end
153
- return @output
150
+ @output
154
151
  end
155
152
 
153
+ # Convert the array from lines_added into spelled-out ranges
154
+ # This is a GitControl helper but it's used in Lint
155
+ # @see GitControl#lines_added
156
+ # @see Lint#relevant_lint
157
+ #
158
+ # @example typical output
159
+ # lines_added = {changes: ['0..10', '11..14']}
160
+ # lines_added_to_range(lines_added)
161
+ # # output
162
+ # [0,1,2,3,4,5,6,7,8,9,10, 11,12,13,14]
163
+ #
164
+ # @return [Hash] changes_array of spelled-out arrays of integers
165
+ def lines_added_to_range(file)
166
+ changes_array = file[:changes].map { |ch| ch.split("..").map(&:to_i) }
167
+ changes_array.map { |e| (e[0]..e[1]).to_a }.flatten!
168
+ end
156
169
 
157
170
  private
158
171
 
159
172
  # Send abbreviated results to console or to the log
160
173
  # @return [String] console message to display
161
174
  def lint_summarize
162
- puts "#{'Warning'.color(:red)}: #{@output[:lint_errors].length} errors found in #{@task}" unless @output[:lint_errors].length
175
+ puts "#{'Warning'.color(:red)}: #{@output[:lint_errors].length} errors found in #{@task}" if @output[:lint_errors].length > 0
163
176
 
164
- success = @task.to_s.color(:green)
165
- success += ": "
166
- success += "[#{@output[:lint_warnings].length}]".color(:yellow)
167
- success += " [#{@output[:lint_errors].length}]".color(:red)
177
+ success = @task.color(:green)
178
+ success << ": "
179
+ success << "[#{@output[:lint_warnings].length}]".color(:yellow)
180
+ success << " [#{@output[:lint_errors].length}]".color(:red)
168
181
  if @task == 'rubocop'
169
- success += " [#{@output[:lint_conventions].length}]".color(:cyan)
170
- success += " [#{@output[:lint_refactors].length}]".color(:white)
182
+ success << " [#{@output[:lint_conventions].length}]".color(:cyan)
183
+ success << " [#{@output[:lint_refactors].length}]".color(:white)
184
+ success << " [#{@output[:lint_fatals].length}]".color(:magenta)
171
185
  end
172
186
 
173
187
  success
@@ -176,12 +190,22 @@ module Maximus
176
190
  # If there's just too much to handle, through a warning.
177
191
  # @param lint_length [Integer] count of how many lints
178
192
  # @return [String] console message to display
179
- def lint_ceiling(lint_length)
193
+ def lint_ceiling
194
+ lint_length = (@output[:lint_errors].length + @output[:lint_warnings].length + @output[:lint_conventions].length + @output[:lint_refactors].length + @output[:lint_fatals].length)
195
+
180
196
  return unless lint_length > 100
181
197
  failed_task = @task.color(:green)
182
198
  errors = "#{lint_length} failures.".color(:red)
183
- errormsg = ["You wouldn't stand a chance in Rome.\nResolve thy errors and train with #{failed_task} again.", "The gods frown upon you, mortal.\n#{failed_task}. Again.", "Do not embarrass the city. Fight another day. Use #{failed_task}.", "You are without honor. Replenish it with another #{failed_task}.", "You will never claim the throne with a performance like that.", "Pompeii has been lost.", "A wise choice. Do not be discouraged from another #{failed_task}."].sample
184
- errormsg += "\n\n"
199
+ errormsg = [
200
+ "You wouldn't stand a chance in Rome.\nResolve thy errors and train with #{failed_task} again.",
201
+ "The gods frown upon you, mortal.\n#{failed_task}. Again.",
202
+ "Do not embarrass the city. Fight another day. Use #{failed_task}.",
203
+ "You are without honor. Replenish it with another #{failed_task}.",
204
+ "You will never claim the throne with a performance like that.",
205
+ "Pompeii has been lost.",
206
+ "A wise choice. Do not be discouraged from another #{failed_task}."
207
+ ].sample
208
+ errormsg << "\n\n"
185
209
 
186
210
  go_on = prompt "\n#{errors} Continue? (y/n) "
187
211
  abort errormsg unless truthy?(go_on)
@@ -194,23 +218,48 @@ module Maximus
194
218
  return if errors.blank?
195
219
  pretty_output = ''
196
220
  errors.each do |filename, error_list|
197
- filename = filename.gsub("#{@settings[:root_dir]}/", '')
198
- pretty_output += "\n#{filename.color(:cyan).underline} \n"
221
+ filename = strip_working_dir(filename)
222
+ pretty_output << "\n#{filename.color(:cyan).underline} \n"
199
223
  error_list.each do |message|
200
- pretty_output += case message['severity']
224
+ pretty_output << case message['severity']
201
225
  when 'warning' then 'W'.color(:yellow)
202
226
  when 'error' then 'E'.color(:red)
203
227
  when 'convention' then 'C'.color(:cyan)
204
228
  when 'refactor' then 'R'.color(:white)
229
+ when 'fatal' then 'F'.color(:magenta)
205
230
  else '?'.color(:blue)
206
231
  end
207
- pretty_output += " #{message['line'].to_s.color(:blue)} #{message['linter'].color(:green)}: #{message['reason']} \n"
232
+ pretty_output << " #{message['line'].to_s.color(:blue)} #{message['linter'].color(:green)}: #{message['reason']} \n"
208
233
  end
209
234
  end
210
235
  pretty_output
211
236
  end
212
237
 
238
+ # String working directory
239
+ # @since 0.1.6
240
+ # @param path [String]
241
+ # @return [String]
242
+ def strip_working_dir(path)
243
+ path.gsub("#{@config.working_dir}/", '')
244
+ end
245
+
246
+ # Handle data and generate relevant_lints if appropriate
247
+ # @since 0.1.6
248
+ # @see #refine
249
+ # @param data [String, Hash]
250
+ # @return [String, Hash] String if error, Hash if success
251
+ def parse_data(data)
252
+ # Prevent abortive empty JSON.parse error
253
+ data = '{}' if data.blank?
254
+
255
+ return "Error from #{@task}: #{data}" if data.is_a?(String) && data.include?('No such')
213
256
 
257
+ data = JSON.parse(data) if data.is_a?(String)
258
+
259
+ @output[:relevant_lints] = relevant_lints( data, @git_files ) unless @git_files.blank?
260
+ data = @output[:relevant_lints] unless @settings[:commit].blank?
261
+ data
262
+ end
214
263
 
215
264
  end
216
265
  end
@@ -1,13 +1,13 @@
1
1
  module Maximus
2
+ # Evaluates quality of security on a Rails site
2
3
  # @since 0.1.0
3
4
  class Brakeman < Maximus::Lint
4
5
 
5
6
  # Brakeman (requires Rails)
6
7
  # @see Lint#initialize
7
8
  def result
8
-
9
9
  @task = 'brakeman'
10
- @path = @settings[:root_dir] if @path.blank?
10
+ @path = discover_path
11
11
 
12
12
  return unless is_rails? && temp_config(@task) && path_exists?(@path)
13
13
 
@@ -19,26 +19,15 @@ module Maximus
19
19
 
20
20
  unless brakeman.blank?
21
21
  bjson = JSON.parse(brakeman)
22
- @output[:ignored_warnings] = bjson['scan_info']['ignored_warnings']
23
- @output[:checks_performed] = bjson['scan_info']['checks_performed']
24
- @output[:number_of_controllers] = bjson['scan_info']['number_of_controllers']
25
- @output[:number_of_models] = bjson['scan_info']['number_of_models']
26
- @output[:number_of_templates] = bjson['scan_info']['number_of_templates']
27
- @output[:ruby_version] = bjson['scan_info']['ruby_version']
28
- @output[:rails_version] = bjson['scan_info']['rails_version']
22
+ basics(bjson)
29
23
  brakeman = {}
30
24
  ['warnings', 'errors'].each do |type|
31
25
  new_brakeman = bjson[type].group_by { |s| s['file'] }
32
26
  new_brakeman.each do |file, errors|
33
- if file
34
- brakeman[file.to_sym] = errors.map { |e| hash_for_brakeman(e, type) }
35
- end
27
+ next unless file
28
+ brakeman[file] = errors.map { |e| hash_for_brakeman(e, type) }
36
29
  end
37
30
  end
38
- # The output of brakeman is a mix of strings and symbols
39
- # but resetting the JSON like this standardizes everything.
40
- # @todo Better way to get around this?
41
- brakeman = JSON.parse(brakeman.to_json)
42
31
  end
43
32
 
44
33
  @output[:files_inspected] ||= files_inspected('rb', ' ')
@@ -53,14 +42,28 @@ module Maximus
53
42
  # @return [Hash]
54
43
  def hash_for_brakeman(error, type)
55
44
  {
56
- linter: error['warning_type'].delete(' '),
57
- severity: type.chomp('s'),
58
- reason: error['message'],
59
- column: 0,
60
- line: error['line'].to_i,
61
- confidence: error['confidence']
45
+ 'linter' => error['warning_type'].delete(' '),
46
+ 'severity' => type.chomp('s'),
47
+ 'reason' => error['message'],
48
+ 'column' => 0,
49
+ 'line' => error['line'].to_i,
50
+ 'confidence' => error['confidence']
62
51
  }
63
52
  end
64
53
 
54
+ # Pull out the general data brakeman provides
55
+ # @since 0.1.6
56
+ # @see #result
57
+ # @param brakeman_data [Hash]
58
+ def basics(brakeman_data)
59
+ @output[:ignored_warnings] = brakeman_data['scan_info']['ignored_warnings']
60
+ @output[:checks_performed] = brakeman_data['scan_info']['checks_performed']
61
+ @output[:number_of_controllers] = brakeman_data['scan_info']['number_of_controllers']
62
+ @output[:number_of_models] = brakeman_data['scan_info']['number_of_models']
63
+ @output[:number_of_templates] = brakeman_data['scan_info']['number_of_templates']
64
+ @output[:ruby_version] = brakeman_data['scan_info']['ruby_version']
65
+ @output[:rails_version] = brakeman_data['scan_info']['rails_version']
66
+ end
67
+
65
68
  end
66
69
  end
@@ -1,4 +1,5 @@
1
1
  module Maximus
2
+ # Evaluates quality of JavaScript
2
3
  # @since 0.1.0
3
4
  class Jshint < Maximus::Lint
4
5
 
@@ -6,14 +7,14 @@ module Maximus
6
7
  # @see Lint#initialize
7
8
  def result
8
9
  @task = 'jshint'
9
- @path = is_rails? ? "#{@settings[:root_dir]}/app/assets" : "#{@settings[:root_dir]}source/assets" if @path.blank?
10
+ @path = discover_path(@config.working_dir, 'javascripts', 'js')
10
11
 
11
12
  return unless temp_config(@task) && path_exists?(@path)
12
13
 
13
14
  node_module_exists(@task)
14
15
 
15
16
  jshint_cli = "jshint #{@path} --config=#{temp_config(@task)} --reporter=#{reporter_path('jshint.js')}"
16
- jshint_cli += " --exclude-path=#{temp_config(@settings[:jshintignore])}" if @settings.has_key?(:jshintignore)
17
+ jshint_cli << " --exclude-path=#{temp_config(@settings[:jshintignore])}" if @settings.key?(:jshintignore)
17
18
  jshint = `#{jshint_cli}`
18
19
 
19
20
  @output[:files_inspected] ||= files_inspected('js')
@@ -1,13 +1,13 @@
1
1
  module Maximus
2
+ # Evaluates quality of Rails methods
2
3
  # @since 0.1.0
3
4
  class Railsbp < Maximus::Lint
4
5
 
5
6
  # rails_best_practice (requires Rails)
6
7
  # @see Lint#initialize
7
8
  def result
8
-
9
9
  @task = 'railsbp'
10
- @path = @settings[:root_dir] if @path.blank?
10
+ @path = discover_path
11
11
 
12
12
  return unless is_rails? && temp_config(@task) && path_exists?(@path)
13
13
 
@@ -1,4 +1,5 @@
1
1
  module Maximus
2
+ # Evaluates quality of ruby
2
3
  # @since 0.1.0
3
4
  class Rubocop < Maximus::Lint
4
5
 
@@ -6,7 +7,7 @@ module Maximus
6
7
  # @see Lint#initialize
7
8
  def result
8
9
  @task = 'rubocop'
9
- @path = is_rails? ? "#{@settings[:root_dir]}/app" : "#{@settings[:root_dir]}/*.rb" if @path.blank?
10
+ @path = discover_path
10
11
 
11
12
  return unless temp_config(@task) && path_exists?(@path)
12
13