maximus 0.1.4 → 0.1.5

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.
@@ -1,2 +1,60 @@
1
- lints: true
2
- statistics: true
1
+ paths:
2
+ home: '/'
3
+
4
+ scsslint: true
5
+
6
+ rubocop: true
7
+
8
+ railsbp: true
9
+
10
+ brakeman: true
11
+
12
+ jshint:
13
+ browser: true
14
+ esnext: true
15
+ globals: {}
16
+ globalstrict: true
17
+ undef: true
18
+ unused: true
19
+ jquery: true
20
+
21
+ phantomas:
22
+ block-domain: 'google-analytics.com'
23
+ skip-modules:
24
+ - 'Caching'
25
+ - 'localStorage'
26
+ - 'Cookies'
27
+ - 'assetsWithQueryString'
28
+ - 'nodesWithInlineCSS'
29
+
30
+ stylestats:
31
+ published: false
32
+ paths: false
33
+ stylesheets: false
34
+ styleElements: true
35
+ size: true
36
+ dataUriSize: true
37
+ ratioOfDataUriSize: true
38
+ gzippedSize: false
39
+ simplicity: true
40
+ rules: true
41
+ selectors: true
42
+ mostIdentifier: true
43
+ mostIdentifierSelector: true
44
+ lowestCohesion: true
45
+ lowestCohesionSelector: true
46
+ totalUniqueFontSizes: true
47
+ uniqueFontSize: true
48
+ totalUniqueColors: true
49
+ uniqueColor: true
50
+ idSelectors: true
51
+ universalSelectors: true
52
+ unqualifiedAttributeSelectors: true
53
+ javascriptSpecificSelectors: "[#\\.]js\\-"
54
+ importantKeywords: true
55
+ floatProperties: true
56
+ mediaQueries: true
57
+ propertiesCount: 10
58
+ requestOptions: {}
59
+
60
+ wraith: true
@@ -1,3 +1,5 @@
1
+ /*global phantom */
2
+
1
3
  var system = require('system');
2
4
  var page = require('webpage').create();
3
5
  var fs = require('fs');
@@ -25,7 +27,7 @@ page.settings.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleW
25
27
  // page.customHeaders = {
26
28
 
27
29
  // 'X-Candy-OVERRIDE': 'https://api.live.bbc.co.uk/'
28
-
30
+
29
31
  // };
30
32
 
31
33
  // If you want to set a cookie, just add your details below in the following way.
@@ -1,3 +1,5 @@
1
+ /*global phantom */
2
+
1
3
  var system = require('system');
2
4
  var page = require('webpage').create();
3
5
  var fs = require('fs');
@@ -25,7 +27,7 @@ page.settings.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleW
25
27
  // page.customHeaders = {
26
28
 
27
29
  // 'X-Candy-OVERRIDE': 'https://api.live.bbc.co.uk/'
28
-
30
+
29
31
  // };
30
32
 
31
33
  // If you want to set a cookie, just add your details below in the following way.
@@ -14,18 +14,29 @@ module Maximus
14
14
  # @option opts [String] :commit accepts sha, "working", "last", or "master".
15
15
  def initialize(opts = {})
16
16
  opts[:config] ||= Maximus::Config.new({ commit: opts[:commit] })
17
- @config ||= opts[:config]
18
- @settings ||= @config.settings
19
- @psuedo_commit = (!@settings[:commit].blank? && (@settings[:commit] == 'working' || @settings[:commit] == 'last' || @settings[:commit] == 'master') )
20
- @g = Git.open(@settings[:root_dir], :log => @settings[:git_log])
17
+ @config = opts[:config]
18
+
19
+ @settings = @config.settings
20
+ @psuedo_commit = ( !@settings[:commit].blank? && %w(working last master).include?(@settings[:commit]) )
21
+
22
+ @g = Git.open(@settings[:root_dir])
21
23
  end
22
24
 
23
25
  # 30,000 foot view of a commit
24
- # @param commit_sha [String] the sha of the commit
26
+ # @param commit_sha [String] (head_sha) the sha of the commit
25
27
  # @return [Hash] commit data
26
- def commit_export(commit_sha = sha)
27
- ce_commit = vccommit(commit_sha)
28
- ce_diff = diff(ce_commit, @g.object('HEAD^'))
28
+ def commit_export(commit_sha = head_sha)
29
+ commit_sha = commit_sha.to_s
30
+
31
+ ce_commit = @g.gcommit(commit_sha)
32
+
33
+ if first_commit == commit_sha
34
+ ce_diff = diff_initial(first_commit)
35
+ else
36
+ last_commit = @g.gcommit(previous_commit(commit_sha))
37
+ ce_diff = diff(last_commit, ce_commit)
38
+ end
39
+
29
40
  {
30
41
  commit_sha: commit_sha,
31
42
  branch: branch,
@@ -52,58 +63,23 @@ module Maximus
52
63
  # }
53
64
  # }
54
65
  # }
55
- #
66
+ # @param sha1 [String]
67
+ # @param sha2 [String]
56
68
  # @return [Hash] diff_return files changed grouped by file extension and line number
57
- def compare(sha1 = master_commit.sha, sha2 = sha)
69
+ def compare(sha1 = master_commit.sha, sha2 = head_sha)
58
70
  diff_return = {}
59
71
 
60
- if @settings[:commit]
61
- sha1 = case @settings[:commit]
62
- when 'master' then master_commit.sha
63
- when 'last' then @g.object('HEAD^').sha
64
- when 'working' then 'working'
65
- else @settings[:commit]
66
- end
67
- end
68
-
69
- # If working directory, just have a single item array.
70
- # The space here is important because git-lines checks for a second arg,
71
- # and if one is present, it runs git diff without a commit
72
- # or a comparison to a commit.
73
- git_diff = @psuedo_commit ? ["git #{sha1}"] : `git rev-list #{sha1}..#{sha2} --no-merges`.split("\n")
74
-
75
- # Include the first sha because rev-list is doing a traversal
76
- # So sha1 is never included
77
- git_diff << sha1 unless @psuedo_commit
78
-
72
+ sha1 = set_psuedo_commit if @settings[:commit]
79
73
  # Reverse so that we go in chronological order
80
- git_diff.reverse.each do |git_sha|
81
- new_lines = lines_added(git_sha)
74
+ git_spread = commit_range(sha1, sha2).reverse
82
75
 
83
- # Grab all files in that commit and group them by extension
84
- # If working copy, just give the diff names of the files changed
85
- files = @psuedo_commit ? `git diff --name-only` : `git show --pretty="format:" --name-only #{git_sha}`
86
- files = files.split("\n").group_by { |f| f.split('.').pop }
76
+ git_spread.each do |git_sha|
87
77
 
88
- # Don't worry about files that we don't have a lint or a statistic for
89
- flat_associations = associations.clone.flatten(2)
90
- files.delete_if { |k,v| !flat_associations.include?(k) || k.nil? }
78
+ # Grab all files in that commit and group them by extension
79
+ # If working copy, just give the diff names of the files changed
80
+ files = @psuedo_commit ? `git -C #{@settings[:root_dir]} diff --name-only` : `git -C #{@settings[:root_dir]} show --pretty="format:" --name-only #{git_sha}`
91
81
 
92
- associations.each do |ext, related|
93
- files[ext] ||= []
94
- related.each do |child|
95
- unless files[child].blank?
96
- files[child].each do |c|
97
- # hack to ignore deleted files
98
- files[child] = new_lines[c].blank? ? [] : [ filename: "#{@settings[:root_dir]}/#{c}", changes: new_lines[c] ]
99
- end
100
- files[ext].concat(files[child])
101
- files.delete(child)
102
- end
103
- end
104
- end
105
- files.delete_if { |k,v| v.blank? }
106
- diff_return[git_sha.to_sym] = files
82
+ diff_return[git_sha.to_s] = match_associations(git_sha, files)
107
83
  end
108
84
  diff_return
109
85
  end
@@ -124,37 +100,48 @@ module Maximus
124
100
  # 'sha'...
125
101
  # }
126
102
  #
103
+ # @see compare
104
+ # @param lint_by_path [Boolean] only lint by files in git commit and
105
+ # not the commit as a whole
106
+ # @param git_shas [Hash] (#compare) a hash of gitcommit shas
107
+ # and relevant file types in the commit
108
+ # @param nuclear [Boolean] do everything regardless of what's in the commit
127
109
  # @return [Hash] data all data grouped by task
128
- def lints_and_stats(lint_by_path = false, git_shas = compare)
110
+ def lints_and_stats(lint_by_path = false, git_shas = compare, nuclear = false)
129
111
  return false if git_shas.blank?
130
112
  base_branch = branch
131
113
  git_output = {}
132
114
  git_shas.each do |sha, exts|
133
- # @todo better way to silence git, in case there's a real error?
134
- quietly { `git checkout #{sha} -b maximus_#{sha}` } unless @psuedo_commit
135
- puts sha.to_s.color(:blue) if @config.is_dev?
136
- git_output[sha.to_sym] = {
137
- lints: {},
138
- statistics: {}
139
- }
140
- lints = git_output[sha.to_sym][:lints]
141
- statistics = git_output[sha.to_sym][:statistics]
142
- lint_opts = {}
115
+ create_branch(sha) unless @psuedo_commit
116
+ sha = sha.to_s
117
+ puts sha.color(:blue)
118
+ git_output[sha] = {lints: {}, statistics: {}}
119
+ lints = git_output[sha][:lints]
120
+ statistics = git_output[sha][:statistics]
143
121
 
144
122
  # This is where everything goes down
145
123
  exts.each do |ext, files|
124
+
146
125
  # For relevant_lines data
147
126
  lint_opts = {
148
127
  git_files: files,
149
- config: @config
128
+ config: @config,
129
+ file_paths: (lint_file_paths(files, ext) if lint_by_path)
150
130
  }
151
- lint_opts[:file_paths] = lint_file_paths(files, ext) if lint_by_path
152
- case ext
153
- when :scss
154
- lints[:scsslint] = Maximus::Scsslint.new(lint_opts).result
155
131
 
156
- # Do not run statistics if called from command line
157
- if lint_opts[:commit].blank?
132
+ if nuclear
133
+ lints[:scsslint] = Maximus::Scsslint.new(lint_opts).result
134
+ lints[:jshint] = Maximus::Jshint.new(lint_opts).result
135
+ lints[:rubocop] = Maximus::Rubocop.new(lint_opts).result
136
+ lints[:railsbp] = Maximus::Railsbp.new(lint_opts).result
137
+ lints[:brakeman] = Maximus::Brakeman.new(lint_opts).result
138
+ statistics[:stylestat] = Maximus::Stylestats.new({config: @config}).result
139
+ statistics[:phantomas] = Maximus::Phantomas.new({config: @config}).result
140
+ statistics[:wraith] = Maximus::Wraith.new({config: @config}).result
141
+ else
142
+ case ext
143
+ when :scss
144
+ lints[:scsslint] = Maximus::Scsslint.new(lint_opts).result
158
145
 
159
146
  # @todo stylestat is singular here because model name in Rails is singular.
160
147
  # But adding a .classify when it's converted to a model chops off the end s on 'phantomas',
@@ -164,27 +151,105 @@ module Maximus
164
151
  # @todo double pipe here is best way to say, if it's already run, don't run again, right?
165
152
  statistics[:phantomas] ||= Maximus::Phantomas.new({config: @config}).result
166
153
  statistics[:wraith] ||= Maximus::Wraith.new({config: @config}).result
167
- end
168
- when :js
169
- lints[:jshint] = Maximus::Jshint.new(lint_opts).result
170
-
171
- # Do not run statistics if called from command line
172
- if lint_opts[:commit].blank?
154
+ when :js
155
+ lints[:jshint] = Maximus::Jshint.new(lint_opts).result
173
156
 
174
157
  statistics[:phantomas] ||= Maximus::Phantomas.new({config: @config}).result
175
158
 
176
159
  # @todo double pipe here is best way to say, if it's already run, don't run again, right?
177
160
  statistics[:wraith] ||= Maximus::Wraith.new({config: @config}).result
178
- end
179
- when :ruby
180
- lints[:rubocop] = Maximus::Rubocop.new(lint_opts).result
181
- lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result
182
- lints[:brakeman] = Maximus::Brakeman.new(lint_opts).result
183
- when :rails
184
- lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result
161
+ when :ruby
162
+ lints[:rubocop] = Maximus::Rubocop.new(lint_opts).result
163
+ lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result
164
+ lints[:brakeman] = Maximus::Brakeman.new(lint_opts).result
165
+ when :rails
166
+ lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result
167
+ end
185
168
  end
186
169
  end
187
- # @todo better way to silence git, in case there's a real error?
170
+ destroy_branch(base_branch, sha) unless @psuedo_commit
171
+ end
172
+ git_output
173
+ end
174
+
175
+ # Find first commit
176
+ # @since 0.1.5
177
+ # @return [String]
178
+ def first_commit
179
+ `git -C #{@settings[:root_dir]} rev-list --max-parents=0 HEAD`.strip!
180
+ end
181
+
182
+ # Get commit before current
183
+ # @since 0.1.5
184
+ # @param current_commit [String] (head_sha) commit to start at
185
+ # @param previous_by [Integer] (1) commit n commits ago
186
+ # @return [String]
187
+ def previous_commit(current_commit = head_sha, previous_by = 1)
188
+ `git -C #{@settings[:root_dir]} rev-list --max-count=#{previous_by + 1} #{current_commit} --reverse | head -n1`.strip!
189
+ end
190
+
191
+ # Define associations to linters based on file extension
192
+ # @return [Hash] linters and extension arrays
193
+ def associations
194
+ {
195
+ scss: ['scss', 'sass'],
196
+ js: ['js'],
197
+ ruby: ['rb', 'Gemfile', 'lock', 'yml', 'Rakefile', 'ru', 'rdoc', 'rake', 'Capfile'],
198
+ rails: ['slim', 'haml', 'jbuilder', 'erb']
199
+ }
200
+ end
201
+
202
+
203
+ protected
204
+
205
+ # Retrieve shas of all commits to be evaluated
206
+ # @since 0.1.5
207
+ #
208
+ # If working directory, just have a single item array.
209
+ # The space here is important because git-lines checks for a second arg,
210
+ # and if one is present, it runs git diff without a commit
211
+ # or a comparison to a commit.
212
+ #
213
+ # Include the first sha because rev-list is doing a traversal
214
+ # So sha1 is never included
215
+ #
216
+ # @param sha1 [String]
217
+ # @param sha2 [String]
218
+ # @return [Array] shas
219
+ def commit_range(sha1, sha2)
220
+ git_spread = @psuedo_commit ? "git #{sha1}" : `git -C #{@settings[:root_dir]} rev-list #{sha1}..#{sha2} --no-merges`
221
+ git_spread = git_spread.nil? ? [] : git_spread.split("\n")
222
+
223
+ git_spread << sha1 unless @psuedo_commit
224
+ git_spread
225
+ end
226
+
227
+ # Get sha if words passed for :commit config option
228
+ # @since 0.1.5
229
+ # @return [String] commit sha
230
+ def set_psuedo_commit
231
+ case @settings[:commit]
232
+ when 'master' then master_commit.sha
233
+ when 'last' then previous_commit(head_sha)
234
+ when 'working' then 'working'
235
+ else @settings[:commit]
236
+ end
237
+ end
238
+
239
+ # Create branch to run report on
240
+ # @todo better way to silence git, in case there's a real error?
241
+ # @since 0.1.5
242
+ # @param sha [String]
243
+ def create_branch(sha)
244
+ quietly { `git -C #{@settings[:root_dir]} checkout #{sha} -b maximus_#{sha}` }
245
+ end
246
+
247
+ # Destroy created branch
248
+ # @todo better way to silence git, in case there's a real error?
249
+ # @since 0.1.5
250
+ # @param base_branch [String] branch we started on
251
+ # @param sha [String] used to check against created branch name
252
+ def destroy_branch(base_branch, sha)
188
253
  quietly {
189
254
  if base_branch == "maximus_#{sha}"
190
255
  @g.branch('master').checkout
@@ -192,16 +257,10 @@ module Maximus
192
257
  @g.branch(base_branch).checkout
193
258
  end
194
259
  @g.branch("maximus_#{sha}").delete
195
- } unless @psuedo_commit
260
+ }
196
261
  end
197
- git_output
198
- end
199
-
200
-
201
- protected
202
262
 
203
263
  # Get list of file paths
204
- #
205
264
  # @param files [Hash] hash of files denoted by key 'filename'
206
265
  # @param ext [String] file extension - different extensions are joined different ways
207
266
  # @return [String] file paths delimited by comma or space
@@ -214,19 +273,17 @@ module Maximus
214
273
  # Determine which lines were added (where and how many) in a commit
215
274
  #
216
275
  # @example output from method
217
- # {
218
- # 'filename': [
276
+ # { 'filename': [
219
277
  # '0..10',
220
278
  # '11..14'
221
- # ]
222
- # }
279
+ # ] }
223
280
  #
224
281
  # @param git_sha [String] sha of the commit
225
282
  # @return [Hash] ranges by lines added in a commit by file name
226
283
  def lines_added(git_sha)
227
284
  new_lines = {}
228
- lines_added = `#{File.join(File.dirname(__FILE__), 'reporter/git-lines.sh')} #{git_sha}`.split("\n")
229
- lines_added.each do |filename|
285
+ git_lines = `#{File.join(File.dirname(__FILE__), 'reporter/git-lines.sh')} #{@settings[:root_dir]} #{git_sha}`.split("\n")
286
+ git_lines.each do |filename|
230
287
  fsplit = filename.split(':')
231
288
  # if file isn't already part of the array
232
289
  new_lines[fsplit[0]] ||= []
@@ -240,7 +297,7 @@ module Maximus
240
297
 
241
298
  # Get last commit on current branch
242
299
  # @return [String] sha
243
- def sha
300
+ def head_sha
244
301
  @g.object('HEAD').sha
245
302
  end
246
303
 
@@ -256,42 +313,90 @@ module Maximus
256
313
  @g.branches[:master].gcommit
257
314
  end
258
315
 
259
- # Store last commit as Ruby Git::Object
260
- # @param commit_sha [String]
261
- # @return [Git::Object]
262
- def vccommit(commit_sha = sha)
263
- @g.gcommit(commit_sha)
264
- end
265
-
266
316
  # Get general stats of commit on HEAD versus last commit on master branch
267
317
  # @modified 0.1.4
268
- # @param new_commit [Git::Object]
269
318
  # @param old_commit [Git::Object]
319
+ # @param new_commit [Git::Object]
270
320
  # @return [Git::Diff] hash of abbreviated, useful stats with added lines
271
- def diff(new_commit = vccommit, old_commit = master_commit)
272
- stats = @g.diff(new_commit, old_commit).stats
273
- return if lines.blank? || diff.blank?
321
+ def diff(old_commit, new_commit)
322
+ stats = @g.diff(old_commit, new_commit).stats
323
+ lines = lines_added(new_commit.sha)
324
+ return if !lines.is_a?(Hash) || stats.blank?
274
325
  lines.each do |filename, filelines|
275
326
  stats[:files][filename][:lines_added] = filelines if stats[:files].has_key?(filename)
276
327
  end
277
328
  stats
278
329
  end
279
330
 
331
+ # Get diff stats on just the initial commit
332
+ # Ruby-git doesn't support this well
333
+ # @see diff
334
+ # @since 0.1.5
335
+ # @param commit_sha [String]
336
+ # @return [Hash] stat data similar to Ruby-git's Diff.stats return
337
+ def diff_initial(commit_sha)
338
+ # Start after the commit information
339
+ data = `git -C #{@settings[:root_dir]} log --numstat --oneline #{commit_sha}`.split("\n")[1..-1]
340
+ value = {
341
+ total: {
342
+ insertions: 0,
343
+ deletions: 0,
344
+ lines: 0,
345
+ files: data.length
346
+ },
347
+ files: {}
348
+ }
349
+ data.each do |d|
350
+ item = d.split("\t")
351
+ insertions = item[0].to_i
352
+ value[:total][:insertions] += insertions
353
+ value[:total][:lines] += insertions
354
+ value[:files][item[2]] = {
355
+ insertions: insertions,
356
+ deletions: 0,
357
+ lines_added: ["0..#{item[0]}"]
358
+ }
359
+ end
360
+ value
361
+ end
362
+
280
363
  # Get remote URL
281
364
  # @return [String, nil] nil returns if remotes is blank
282
365
  def remote
283
366
  @g.remotes.first.url unless @g.remotes.blank?
284
367
  end
285
368
 
286
- # Define associations to linters based on file extension
287
- # @return [Hash] linters and extension arrays
288
- def associations
289
- {
290
- scss: ['scss', 'sass'],
291
- js: ['js'],
292
- ruby: ['rb', 'Gemfile', 'lock', 'yml', 'Rakefile', 'ru', 'rdoc'],
293
- rails: ['slim', 'haml']
294
- }
369
+ # Associate files by extension and match their changes
370
+ # @since 0.1.5
371
+ # @param git_sha [String]
372
+ # @param files [String] list of files from git return
373
+ # @return [Hash] files with matched extensions and changes
374
+ def match_associations(git_sha, files)
375
+ new_lines = lines_added(git_sha)
376
+
377
+ # File.extname is not used here in case dotfiles are encountered
378
+ files = files.split("\n").group_by { |f| f.split('.').pop }
379
+
380
+ # Don't worry about files that we don't have a lint or a statistic for
381
+ flat_associations = associations.clone.flatten(2)
382
+ files.delete_if { |k,v| !flat_associations.include?(k) || k.nil? }
383
+
384
+ associations.each do |ext, related|
385
+ files[ext] ||= []
386
+ related.each do |child|
387
+ unless files[child].blank?
388
+ files[child].each do |c|
389
+ # hack to ignore deleted files
390
+ files[child] = new_lines[c].blank? ? [] : [ filename: "#{@settings[:root_dir]}/#{c}", changes: new_lines[c] ]
391
+ end
392
+ files[ext].concat(files[child])
393
+ files.delete(child)
394
+ end
395
+ end
396
+ end
397
+
398
+ files.delete_if { |k,v| v.blank? }
399
+ files
295
400
  end
296
401
 
297
402
  end