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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +72 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -61
- data/lib/maximus/cli.rb +23 -8
- data/lib/maximus/config.rb +37 -35
- data/lib/maximus/config/maximus.yml +11 -1
- data/lib/maximus/git_control.rb +90 -56
- data/lib/maximus/helper.rb +26 -29
- data/lib/maximus/lint.rb +96 -47
- data/lib/maximus/lints/brakeman.rb +25 -22
- data/lib/maximus/lints/jshint.rb +3 -2
- data/lib/maximus/lints/railsbp.rb +2 -2
- data/lib/maximus/lints/rubocop.rb +2 -1
- data/lib/maximus/lints/scsslint.rb +2 -2
- data/lib/maximus/reporter/git-lines.sh +0 -1
- data/lib/maximus/statistic.rb +0 -2
- data/lib/maximus/statistics/phantomas.rb +3 -3
- data/lib/maximus/statistics/stylestats.rb +37 -33
- data/lib/maximus/statistics/wraith.rb +25 -16
- data/lib/maximus/version.rb +1 -1
- data/maximus.gemspec +4 -3
- data/roadmap.md +3 -8
- data/spec/maximus/config_spec.rb +95 -16
- data/spec/maximus/git_control_spec.rb +5 -5
- data/spec/maximus/helper_spec.rb +39 -5
- data/spec/maximus/lint_spec.rb +18 -3
- data/spec/spec_helper.rb +3 -0
- data/spec/support/config_helper.rb +14 -0
- metadata +55 -38
@@ -1,4 +1,5 @@
|
|
1
1
|
module Maximus
|
2
|
+
# Evaluates quality of scss
|
2
3
|
# @since 0.1.0
|
3
4
|
class Scsslint < Maximus::Lint
|
4
5
|
|
@@ -6,8 +7,7 @@ module Maximus
|
|
6
7
|
# @see Lint#initialize
|
7
8
|
def result
|
8
9
|
@task = 'scsslint'
|
9
|
-
@path =
|
10
|
-
|
10
|
+
@path = discover_path(@config.working_dir, 'stylesheets')
|
11
11
|
return unless temp_config(@task) && path_exists?(@path)
|
12
12
|
|
13
13
|
scss = `scss-lint #{@path} -c #{temp_config(@task)} --format=JSON`
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/bin/bash
|
2
2
|
|
3
3
|
# http://stackoverflow.com/questions/8259851/using-git-diff-how-can-i-get-added-and-modified-lines-numbers
|
4
|
-
# @todo this function is tricky because I don't fully understand regex in BASH. Also, getting line hunks from git is tricky. This will likely need to be refactored
|
5
4
|
function lines-added(){
|
6
5
|
local path=
|
7
6
|
local line=
|
data/lib/maximus/statistic.rb
CHANGED
@@ -64,10 +64,8 @@ module Maximus
|
|
64
64
|
stats = JSON.parse(stats_cli)
|
65
65
|
@output[:statistics][file_path.to_s] ||= {}
|
66
66
|
|
67
|
-
# @todo is there a better way to do this?
|
68
67
|
fp = @output[:statistics][file_path.to_s]
|
69
68
|
|
70
|
-
# @todo Can I do like a self << thing here?
|
71
69
|
stats.each do |stat, value|
|
72
70
|
fp[stat.to_sym] = value
|
73
71
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Maximus
|
2
|
+
# Evaluate page performance
|
2
3
|
# @since 0.1.0
|
3
4
|
class Phantomas < Maximus::Statistic
|
4
5
|
|
5
|
-
#
|
6
|
-
#
|
6
|
+
# Run phantomas through the command line
|
7
7
|
# @see Statistic#initialize
|
8
8
|
def result
|
9
9
|
|
@@ -18,7 +18,7 @@ module Maximus
|
|
18
18
|
# Phantomas doesn't actually skip the skip-modules defined in the config BUT here's to hoping for future support
|
19
19
|
phantomas_cli = "phantomas --config=#{@settings[:phantomas]} "
|
20
20
|
phantomas_cli += @config.is_dev? ? '--colors' : '--reporter=json:no-skip'
|
21
|
-
phantomas_cli
|
21
|
+
phantomas_cli << " --proxy=#{@domain}" if @domain.include?('localhost')
|
22
22
|
@path.is_a?(Hash) ? @path.each { |label, url| phantomas_by_url(url, phantomas_cli) } : phantomas_by_url(@path, phantomas_cli)
|
23
23
|
@output
|
24
24
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Maximus
|
2
|
+
# Produce CSS statistics
|
2
3
|
# @since 0.1.0
|
3
4
|
class Stylestats < Maximus::Statistic
|
4
5
|
|
5
|
-
#
|
6
|
+
# Requires node
|
6
7
|
# @see Statistic#initialize
|
7
8
|
def result
|
8
9
|
|
@@ -11,7 +12,7 @@ module Maximus
|
|
11
12
|
node_module_exists('stylestats')
|
12
13
|
|
13
14
|
if @path.blank?
|
14
|
-
@path = is_rails? ? "#{@
|
15
|
+
@path = is_rails? ? "#{@config.working_dir}/public/assets/**/*.css" : "#{@config.working_dir}/**/*.css"
|
15
16
|
end
|
16
17
|
|
17
18
|
if @path.is_a?(Array)
|
@@ -21,20 +22,7 @@ module Maximus
|
|
21
22
|
css_files = find_css
|
22
23
|
end
|
23
24
|
|
24
|
-
css_files.each
|
25
|
-
|
26
|
-
# For Rails, we only want the name of the compiled asset, because we know it'll live in public/assets.
|
27
|
-
# If this isn't Rails, sure, give me the full path because the directory structure is likely unique
|
28
|
-
pretty_name = is_rails? ? file.split('/').pop.gsub(/(-{1}[a-z0-9]{32}*\.{1}){1}/, '.') : file
|
29
|
-
|
30
|
-
puts "#{'stylestats'.color(:green)}: #{pretty_name}\n\n"
|
31
|
-
|
32
|
-
# include JSON formatter unless we're in dev
|
33
|
-
stylestats = `stylestats #{file} --config=#{@settings[:stylestats]} #{'--type=json' unless @config.is_dev?}`
|
34
|
-
refine(stylestats, pretty_name)
|
35
|
-
|
36
|
-
File.delete(file)
|
37
|
-
end
|
25
|
+
css_files.each { |file| stylestats_report(file) }
|
38
26
|
|
39
27
|
destroy_assets if @settings[:compile_assets]
|
40
28
|
@output
|
@@ -94,23 +82,22 @@ module Maximus
|
|
94
82
|
# @return [Array] compiled css files
|
95
83
|
def compile_scss_rails
|
96
84
|
searched_files = []
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
`rake assets:precompile`
|
104
|
-
end
|
85
|
+
# I'd rather Rake::Task but it's not working in different directories
|
86
|
+
if @config.is_dev?
|
87
|
+
# @todo review that this may not be best practice, but it's really noisy in the console
|
88
|
+
quietly { `rake -f #{@config.working_dir}/Rakefile assets:precompile` }
|
89
|
+
else
|
90
|
+
`rake -f #{@config.working_dir}/Rakefile assets:precompile`
|
105
91
|
end
|
106
92
|
end
|
107
93
|
|
108
94
|
# Turn scss files into css files
|
95
|
+
# Skips if the file starts with an underscore
|
109
96
|
# @see find_css_files
|
110
97
|
# @since 0.1.5
|
111
98
|
def compile_scss_normal
|
112
99
|
Dir["#{@path}.scss"].select { |f| File.file? f }.each do |file|
|
113
|
-
|
100
|
+
next if File.basename(file).chr == '_'
|
114
101
|
scss_file = File.open(file, 'rb') { |f| f.read }
|
115
102
|
|
116
103
|
output_file = File.open( file.split('.').reverse.drop(1).reverse.join('.'), "w" )
|
@@ -124,14 +111,12 @@ module Maximus
|
|
124
111
|
def destroy_assets
|
125
112
|
|
126
113
|
if is_rails?
|
127
|
-
#
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
`rake assets:clobber`
|
134
|
-
end
|
114
|
+
# I'd rather Rake::Task but it's not working in different directories
|
115
|
+
if @config.is_dev?
|
116
|
+
# @todo review that this may not be best practice, but it's really noisy in the console
|
117
|
+
quietly { `rake -f #{@config.working_dir}/Rakefile assets:clobber` }
|
118
|
+
else
|
119
|
+
`rake -f #{@config.working_dir}/Rakefile assets:clobber`
|
135
120
|
end
|
136
121
|
end
|
137
122
|
|
@@ -144,5 +129,24 @@ module Maximus
|
|
144
129
|
Dir.glob(path).select { |f| File.file? f }.map { |file| file }
|
145
130
|
end
|
146
131
|
|
132
|
+
# Present stylestat result of a CSS file
|
133
|
+
# Deletes file at end
|
134
|
+
# @since 0.1.6
|
135
|
+
# @see #result
|
136
|
+
# @param file [String] path to file
|
137
|
+
def stylestats_report(file)
|
138
|
+
# For Rails, we only want the name of the compiled asset, because we know it'll live in public/assets.
|
139
|
+
# If this isn't Rails, sure, give me the full path because the directory structure is likely unique
|
140
|
+
pretty_name = is_rails? ? file.split('/').pop.gsub(/(-{1}[a-z0-9]{32}*\.{1}){1}/, '.') : file
|
141
|
+
|
142
|
+
puts "#{'stylestats'.color(:green)}: #{pretty_name}\n\n"
|
143
|
+
|
144
|
+
# include JSON formatter unless we're in dev
|
145
|
+
stylestats = `stylestats #{file} --config=#{@settings[:stylestats]} #{'--type=json' unless @config.is_dev?}`
|
146
|
+
refine(stylestats, pretty_name)
|
147
|
+
|
148
|
+
File.delete(file)
|
149
|
+
end
|
150
|
+
|
147
151
|
end
|
148
152
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Maximus
|
2
|
+
# Generates screenshots for visual regression testing
|
2
3
|
# @since 0.1.0
|
3
4
|
class Wraith < Maximus::Statistic
|
4
5
|
|
5
|
-
#
|
6
|
-
#
|
6
|
+
# Runs Wraith through command line
|
7
7
|
# WARNING: If you call this class from a script,
|
8
8
|
# you should delete the images generated after they've been
|
9
9
|
# created.
|
@@ -30,20 +30,8 @@ module Maximus
|
|
30
30
|
# in each wraith config file.
|
31
31
|
# @yieldparam browser [String] headless browser name
|
32
32
|
# @yieldparam configpath [String] path to temp config file (see Config#wraith_setup)
|
33
|
-
@settings[:wraith].each
|
34
|
-
next unless File.file?(configpath) # prevents abortive YAML error if it can't find the file
|
35
|
-
wraith_yaml = YAML.load_file(configpath)
|
36
|
-
if File.directory?("#{@settings[:root_dir]}/#{wraith_yaml['history_dir']}")
|
37
|
-
puts `wraith latest #{configpath}`
|
33
|
+
@settings[:wraith].each { |browser, configpath| wraith_report(browser, configpath) }
|
38
34
|
|
39
|
-
# Reset history dir
|
40
|
-
# It puts the new shots in the history folder, even with absolute paths in the config.
|
41
|
-
# Could be a bug in wraith.
|
42
|
-
FileUtils.remove_dir("#{@settings[:root_dir]}/#{wraith_yaml['history_dir']}")
|
43
|
-
end
|
44
|
-
wraith_parse browser unless @config.is_dev?
|
45
|
-
puts `wraith history #{configpath}`
|
46
|
-
end
|
47
35
|
@output
|
48
36
|
|
49
37
|
end
|
@@ -57,7 +45,7 @@ module Maximus
|
|
57
45
|
# @param browser [String] headless browser used to generate the gallery
|
58
46
|
# @return [Hash] { path: { browser, path_label, percent_changed: { size: percent_diff ] } }
|
59
47
|
def wraith_parse(browser)
|
60
|
-
Dir.glob("#{@
|
48
|
+
Dir.glob("#{@config.working_dir}/maximus_wraith_#{browser}/**/*").select { |f| File.file? f }.each do |file|
|
61
49
|
extension = File.extname(file)
|
62
50
|
next unless extension == '.png' || extension == '.txt'
|
63
51
|
|
@@ -116,5 +104,26 @@ module Maximus
|
|
116
104
|
image.path
|
117
105
|
end
|
118
106
|
|
107
|
+
# Generate thumbnails and history for each browser in the wraith config
|
108
|
+
# @since 0.1.6
|
109
|
+
# @see #result
|
110
|
+
# @param browser [String]
|
111
|
+
# @param configpath [String]
|
112
|
+
def wraith_report(browser, configpath)
|
113
|
+
return unless File.file?(configpath) # prevents abortive YAML error if it can't find the file
|
114
|
+
wraith_yaml = YAML.load_file(configpath)
|
115
|
+
if File.directory?(File.join(@config.working_dir, wraith_yaml['history_dir']))
|
116
|
+
puts `wraith latest #{configpath}`
|
117
|
+
|
118
|
+
# Reset history dir
|
119
|
+
# It puts the new shots in the history folder, even with absolute paths in the config.
|
120
|
+
# Could be a bug in wraith.
|
121
|
+
FileUtils.remove_dir(File.join(@config.working_dir, wraith_yaml['history_dir']))
|
122
|
+
end
|
123
|
+
|
124
|
+
wraith_parse browser unless @config.is_dev?
|
125
|
+
puts `wraith history #{configpath}`
|
126
|
+
end
|
127
|
+
|
119
128
|
end
|
120
129
|
end
|
data/lib/maximus/version.rb
CHANGED
data/maximus.gemspec
CHANGED
@@ -19,16 +19,17 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "git", "~> 1.2.9"
|
22
|
-
spec.add_runtime_dependency "scss-lint", "~> 0.
|
22
|
+
spec.add_runtime_dependency "scss-lint", "~> 0.34.0"
|
23
23
|
spec.add_runtime_dependency "rainbow", "2.0.0"
|
24
|
-
spec.add_runtime_dependency "rubocop", "~> 0.
|
24
|
+
spec.add_runtime_dependency "rubocop", "~> 0.29"
|
25
25
|
spec.add_runtime_dependency "rails_best_practices", "~> 1.15"
|
26
26
|
spec.add_runtime_dependency "brakeman", "~> 3.0.1"
|
27
|
-
spec.add_runtime_dependency "wraith", "~> 2.3"
|
27
|
+
spec.add_runtime_dependency "wraith", "~> 2.3.2"
|
28
28
|
spec.add_runtime_dependency "activesupport"
|
29
29
|
spec.add_runtime_dependency "thor"
|
30
30
|
|
31
31
|
spec.add_development_dependency "bundler", "~> 1.6"
|
32
|
+
spec.add_development_dependency "pry-byebug", "~> 3.0"
|
32
33
|
spec.add_development_dependency "yard", "~> 0.8"
|
33
34
|
spec.add_development_dependency "rspec", "~> 3.0"
|
34
35
|
spec.add_development_dependency "coveralls", "~> 0.7.8"
|
data/roadmap.md
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
# Roadmap
|
2
2
|
|
3
|
-
* Check for custom lint or stat hooks in a lib/maximus folder. Add custom lint path and script execution support to maximus.yml config file
|
4
|
-
* Use PhantomJS 2.0 with webfont support
|
5
3
|
* Resolve/review @todos
|
6
|
-
* Convert ruby-git to rugged (MAYBE - rugged requires libgit2)
|
7
|
-
* Add SCSS specificity graph
|
8
|
-
* Add HAML lint (maybe)
|
9
4
|
* Add CSS lint (maybe)
|
10
5
|
* Add JSLint (maybe)
|
11
6
|
* Add W3 validator (maybe)
|
12
|
-
* Add Markdown lint (maybe)
|
13
7
|
* Add Flog support (maybe)
|
14
8
|
* Add Flay support (maybe)
|
15
|
-
*
|
16
|
-
*
|
9
|
+
* Add PHP CodeSniffer (maybe)
|
10
|
+
* Add PHPMetrics (maybe)
|
11
|
+
* Use PHP's built-in linter (maybe)
|
17
12
|
* If no files to inspect in working, say so
|
data/spec/maximus/config_spec.rb
CHANGED
@@ -1,15 +1,78 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'support/config_helper'
|
2
3
|
|
3
4
|
describe Maximus::Config do
|
4
|
-
let(:config_path) { '.maximus.yml' }
|
5
5
|
|
6
|
+
include ConfigHelper
|
7
|
+
|
8
|
+
let(:config_body) { '' }
|
6
9
|
subject(:config) do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
create_config(config_body)
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) { destroy_config }
|
14
|
+
|
15
|
+
describe 'options in general', :isolated_environment do
|
16
|
+
context 'options are passed directly' do
|
17
|
+
it 'should read the options as is' do
|
18
|
+
conf = described_class.new({port: 1000})
|
19
|
+
|
20
|
+
expect(conf.settings[:port]).to eq 1000
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'options are passed through a file' do
|
25
|
+
let(:config_body) { 'port: 1000' }
|
26
|
+
it 'should parse the file accurately' do
|
27
|
+
expect(config.settings[:port]).to eq 1000
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'options are passed through a file and directly' do
|
32
|
+
let(:config_body) { 'port: 1000' }
|
33
|
+
it 'should prefer the direct options' do
|
34
|
+
conf = described_class.new({port: 1001, config_file: '.maximus.yml'})
|
35
|
+
expect(conf.settings[:port]).to eq 1001
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
10
39
|
end
|
11
40
|
|
12
|
-
describe '
|
41
|
+
describe 'config file loading (load_confg_file)', :isolated_environment do
|
42
|
+
|
43
|
+
context 'only maximus.yml is available' do
|
44
|
+
it 'should take the settings in maximus.yml' do
|
45
|
+
create_config('port: 1001', 'maximus.yml')
|
46
|
+
conf = described_class.new
|
47
|
+
|
48
|
+
expect(conf.settings[:port]).to eq 1001
|
49
|
+
destroy_config('maximus.yml')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context '.maximus.yml and maximus.yml are available' do
|
54
|
+
it 'should prefer .maximus.yml' do
|
55
|
+
create_config('port: 1000', '.maximus.yml')
|
56
|
+
create_config('port: 1001', 'maximus.yml')
|
57
|
+
conf = described_class.new
|
58
|
+
|
59
|
+
expect(conf.settings[:port]).to eq 1000
|
60
|
+
destroy_config('maximus.yml')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '.working_dir', :isolated_environment do
|
67
|
+
context 'root_dir is applied in the config' do
|
68
|
+
let(:config_body) { 'root_dir: some/fake/directory' }
|
69
|
+
it 'should equal the config setting' do
|
70
|
+
expect(config.working_dir).to eq 'some/fake/directory'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.is_dev?', :isolated_environment do
|
13
76
|
context 'setting root value is_dev to true' do
|
14
77
|
let(:config_body) { 'is_dev: true' }
|
15
78
|
it 'should be true' do
|
@@ -18,32 +81,30 @@ describe Maximus::Config do
|
|
18
81
|
end
|
19
82
|
|
20
83
|
context 'is blank/not supplied' do
|
21
|
-
let(:config_body) { '' }
|
22
84
|
it 'should default to false' do
|
23
85
|
expect(config.is_dev?).to be false
|
24
86
|
end
|
25
87
|
end
|
26
88
|
end
|
27
89
|
|
28
|
-
describe '
|
90
|
+
describe '.initialize', :isolated_environment do
|
29
91
|
|
30
92
|
context 'setting a linter to be true' do
|
31
93
|
let(:config_body) { 'scsslint: true' }
|
32
94
|
it 'scsslint should exist' do
|
33
|
-
expect(config.settings.
|
95
|
+
expect(config.settings.key?(:scsslint)).to be true
|
34
96
|
end
|
35
97
|
end
|
36
98
|
|
37
99
|
context 'not supplying a linter but relying on the default' do
|
38
|
-
let(:config_body) { '' }
|
39
100
|
it 'should include a linter' do
|
40
|
-
expect(config.settings.
|
101
|
+
expect(config.settings.key?(:scsslint)).to be true
|
41
102
|
end
|
42
103
|
end
|
43
104
|
|
44
105
|
end
|
45
106
|
|
46
|
-
describe '
|
107
|
+
describe '.domain', :isolated_environment do
|
47
108
|
|
48
109
|
context 'domain is provided' do
|
49
110
|
|
@@ -83,7 +144,7 @@ describe Maximus::Config do
|
|
83
144
|
|
84
145
|
end
|
85
146
|
|
86
|
-
describe '
|
147
|
+
describe '.split_paths', :isolated_environment do
|
87
148
|
|
88
149
|
context 'an array is provided' do
|
89
150
|
let(:config_body) { "paths: \n - '/'\n - '/about'"}
|
@@ -100,7 +161,6 @@ describe Maximus::Config do
|
|
100
161
|
end
|
101
162
|
|
102
163
|
context 'nothing is provided' do
|
103
|
-
let(:config_body) { '' }
|
104
164
|
it 'should return the default path with label' do
|
105
165
|
expect( config.settings[:paths] ).to eq ({ 'home' => '/'})
|
106
166
|
end
|
@@ -111,10 +171,29 @@ describe Maximus::Config do
|
|
111
171
|
describe '#load_config', :isolated_environment do
|
112
172
|
|
113
173
|
context 'a file path is provided' do
|
114
|
-
|
115
|
-
|
116
|
-
|
174
|
+
|
175
|
+
context 'at a local address' do
|
176
|
+
let(:config_body) { 'rubocop: spec/support/rubocop.yml' }
|
177
|
+
it 'should load the file' do
|
178
|
+
expect( YAML.load_file(config.settings[:rubocop])['Rubolinter'] ).to be true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'at an available remote address' do
|
183
|
+
let(:config_body) { 'rubocop: "https://raw.githubusercontent.com/wearefine/standards/master/linters/.rubocop.yml" ' }
|
184
|
+
it 'should load the file' do
|
185
|
+
expect( YAML.load_file(config.settings[:rubocop]) ).to be_a(Hash)
|
186
|
+
end
|
117
187
|
end
|
188
|
+
|
189
|
+
context 'at an unavailable remote address' do
|
190
|
+
let(:config_body) { 'rubocop: "http://raw.githubusercontent.com/wearefine/standards/master/linters/nonexistent_file.yml" ' }
|
191
|
+
it 'should report an error and return an empty hash' do
|
192
|
+
STDOUT.should_receive(:puts).with('http://raw.githubusercontent.com/wearefine/standards/master/linters/nonexistent_file.yml not accessible')
|
193
|
+
expect( YAML.load_file(config.settings[:rubocop]) ).to eq({})
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
118
197
|
end
|
119
198
|
|
120
199
|
context 'settings are provided' do
|