maximus 0.1.5.1 → 0.1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|