maximus 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/maximus.rb +0 -1
- data/lib/maximus/cli.rb +2 -1
- data/lib/maximus/constants.rb +2 -0
- data/lib/maximus/git_control.rb +94 -33
- data/lib/maximus/helper.rb +73 -36
- data/lib/maximus/lint.rb +46 -29
- data/lib/maximus/lints/brakeman.rb +11 -2
- data/lib/maximus/lints/jshint.rb +3 -0
- data/lib/maximus/lints/railsbp.rb +11 -2
- data/lib/maximus/lints/rubocop.rb +3 -0
- data/lib/maximus/lints/scsslint.rb +3 -0
- data/lib/maximus/reporter/git-lines.sh +1 -1
- data/lib/maximus/statistic.rb +22 -13
- data/lib/maximus/statistics/phantomas.rb +5 -2
- data/lib/maximus/statistics/stylestats.rb +17 -11
- data/lib/maximus/statistics/wraith.rb +8 -4
- data/lib/maximus/version.rb +1 -1
- data/maximus.gemspec +3 -4
- data/roadmap.md +2 -4
- metadata +33 -51
- data/lib/maximus/rake_tasks.rb +0 -13
- data/lib/maximus/tasks/be.rake +0 -35
- data/lib/maximus/tasks/fe.rake +0 -30
- data/lib/maximus/tasks/maximus.rake +0 -39
- data/lib/maximus/tasks/statistic.rake +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70e71aa9bf1801ab2da6baad0c7a6de45759d5b2
|
4
|
+
data.tar.gz: 1f3fc9752270915bfe051d3e76ba034816c7c42b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d24180804d7722eeaef5faedabc1ef5b0915af20ff9cee8cb30ce230cff669bd994f1de046894d6e96c35894f35aab4cce5b6248ab4a6d48b39961099bd287a
|
7
|
+
data.tar.gz: 04e6694a21cc3926fc9338b26827480f8423e104fb5562ead917959edb7a563f12a01c180ad154ded26ab4c4bb4ff6433bcc9f684d4ced8559ae98a71fc6334a
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Maximus
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/maximus.svg)](http://badge.fury.io/rb/maximus) [![Code Climate](https://codeclimate.com/github/wearefine/maximus/badges/gpa.svg)](https://codeclimate.com/github/wearefine/maximus)
|
4
|
+
|
3
5
|
The all-in-one linting solution.
|
4
6
|
|
5
7
|
Plays nice with Middleman and Rails.
|
data/lib/maximus.rb
CHANGED
data/lib/maximus/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
|
3
|
+
# @since 0.1.0
|
3
4
|
class Maximus::CLI < Thor
|
4
5
|
include Thor::Actions
|
5
6
|
class_option :path, aliases: ["-p", "-u", "\--url"], default: nil, desc: "Space-separated path(s) to URLs or files"
|
@@ -46,7 +47,7 @@ class Maximus::CLI < Thor
|
|
46
47
|
return Maximus::GitControl.new({ commit: options[:commit], is_dev: true }).lints_and_stats(true)
|
47
48
|
end
|
48
49
|
|
49
|
-
#
|
50
|
+
# @todo something better than just installing in the global npm file
|
50
51
|
# and including phantomjs
|
51
52
|
desc "install", "Install all dependencies"
|
52
53
|
def install
|
data/lib/maximus/constants.rb
CHANGED
data/lib/maximus/git_control.rb
CHANGED
@@ -5,10 +5,23 @@ require 'rainbow'
|
|
5
5
|
require 'rainbow/ext/string'
|
6
6
|
|
7
7
|
module Maximus
|
8
|
+
# @since 0.1.0
|
8
9
|
class GitControl
|
9
10
|
|
10
11
|
include Helper
|
11
12
|
|
13
|
+
# Git management
|
14
|
+
#
|
15
|
+
# @param opts [Hash] the options to initialize and pass to other classes
|
16
|
+
# @option opts [Boolean] :is_dev whether or not the class was initialized from the command line
|
17
|
+
# @option opts [String] :log ('log/maximus_git.log') path to log file
|
18
|
+
# @option opts [String] :root_dir base directory
|
19
|
+
# @option opts [String] :base_url ('http://localhost:3000') the host - used for Statistics
|
20
|
+
# @option opts [String, Integer] :port port number - used for Statistics
|
21
|
+
# @option opts [String, Array] :path ('') path to files. Accepts glob notation
|
22
|
+
# @option opts [String] :commit accepts sha, "working", "last", or "master".
|
23
|
+
# Used in the command line
|
24
|
+
# @return [void] this method is used to set up instance variables
|
12
25
|
def initialize(opts = {})
|
13
26
|
opts[:is_dev] ||= false
|
14
27
|
opts[:log] = Logger.new('log/maximus_git.log') if opts[:log].nil?
|
@@ -24,7 +37,10 @@ module Maximus
|
|
24
37
|
@g = Git.open(@opts[:root_dir], :log => log)
|
25
38
|
end
|
26
39
|
|
27
|
-
#
|
40
|
+
# 30,000 foot view of a commit
|
41
|
+
#
|
42
|
+
# @param commitsha [String] the sha of the commit
|
43
|
+
# @return [Hash] commit data
|
28
44
|
def commit_export(commitsha = sha)
|
29
45
|
ce_commit = vccommit(commitsha)
|
30
46
|
ce_diff = diff(ce_commit, @g.object('HEAD^'))
|
@@ -40,8 +56,21 @@ module Maximus
|
|
40
56
|
end
|
41
57
|
|
42
58
|
# Compare two commits and get line number ranges of changed patches
|
43
|
-
#
|
44
|
-
#
|
59
|
+
#
|
60
|
+
# @example output from the method
|
61
|
+
# {
|
62
|
+
# 'sha': {
|
63
|
+
# rb: {
|
64
|
+
# filename: 'file.rb',
|
65
|
+
# changes: {
|
66
|
+
# ['0..4'],
|
67
|
+
# ['10..20']
|
68
|
+
# }
|
69
|
+
# }
|
70
|
+
# }
|
71
|
+
# }
|
72
|
+
#
|
73
|
+
# @return [Hash] diff_return files changed grouped by file extension and line number
|
45
74
|
def compare(sha1 = master_commit.sha, sha2 = sha)
|
46
75
|
diff_return = {}
|
47
76
|
|
@@ -54,10 +83,10 @@ module Maximus
|
|
54
83
|
end
|
55
84
|
end
|
56
85
|
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
86
|
+
# If working directory, just have a single item array.
|
87
|
+
# The space here is important because git-lines checks for a second arg,
|
88
|
+
# and if one is present, it runs git diff without a commit
|
89
|
+
# or a comparison to a commit.
|
61
90
|
git_diff = @psuedo_commit ? ['working directory'] : `git rev-list #{sha1}..#{sha2} --no-merges`.split("\n")
|
62
91
|
|
63
92
|
# Include the first sha because rev-list is doing a traversal
|
@@ -96,17 +125,29 @@ module Maximus
|
|
96
125
|
diff_return
|
97
126
|
end
|
98
127
|
|
99
|
-
# Run appropriate lint for every sha in commit history
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
128
|
+
# Run appropriate lint for every sha in commit history.
|
129
|
+
# For each sha a new branch is created then deleted
|
130
|
+
#
|
131
|
+
# @example sample output
|
132
|
+
# {
|
133
|
+
# 'sha': {
|
134
|
+
# lints: {
|
135
|
+
# scsslint: {
|
136
|
+
# files_inspec...
|
137
|
+
# },
|
138
|
+
# },
|
139
|
+
# statisti...
|
140
|
+
# },
|
141
|
+
# 'sha'...
|
142
|
+
# }
|
143
|
+
#
|
144
|
+
# @return [Hash] data all data grouped by task
|
104
145
|
def lints_and_stats(lint_by_path = false, git_shas = compare)
|
105
146
|
return false if git_shas.blank?
|
106
147
|
base_branch = branch
|
107
148
|
git_output = {}
|
108
149
|
git_shas.each do |sha, exts|
|
109
|
-
#
|
150
|
+
# @todo better way to silence git, in case there's a real error?
|
110
151
|
quietly { `git checkout #{sha} -b maximus_#{sha}` } unless @psuedo_commit
|
111
152
|
puts sha.to_s.color(:blue) if @@is_dev
|
112
153
|
git_output[sha.to_sym] = {
|
@@ -126,6 +167,7 @@ module Maximus
|
|
126
167
|
port: @opts[:port],
|
127
168
|
root_dir: @opts[:root_dir]
|
128
169
|
}
|
170
|
+
|
129
171
|
# This is where everything goes down
|
130
172
|
exts.each do |ext, files|
|
131
173
|
# For relevant_lines data
|
@@ -135,27 +177,27 @@ module Maximus
|
|
135
177
|
when :scss
|
136
178
|
lints[:scsslint] = Maximus::Scsslint.new(lint_opts).result
|
137
179
|
|
138
|
-
# Do not run statistics if called
|
180
|
+
# Do not run statistics if called from command line
|
139
181
|
if lint_opts[:commit].blank?
|
140
182
|
|
141
|
-
# stylestat is singular here because model name in Rails is singular.
|
142
|
-
#
|
143
|
-
#
|
183
|
+
# @todo stylestat is singular here because model name in Rails is singular.
|
184
|
+
# But adding a .classify when it's converted to a model chops off the end s on 'phantomas',
|
185
|
+
# which breaks the model name.
|
144
186
|
statistics[:stylestat] = Maximus::Stylestats.new(stat_opts).result
|
145
187
|
|
146
|
-
#
|
188
|
+
# @todo double pipe here is best way to say, if it's already run, don't run again, right?
|
147
189
|
statistics[:phantomas] ||= Maximus::Phantomas.new(stat_opts).result
|
148
190
|
statistics[:wraith] = Maximus::Wraith.new(stat_opts).result
|
149
191
|
end
|
150
192
|
when :js
|
151
193
|
lints[:jshint] = Maximus::Jshint.new(lint_opts).result
|
152
194
|
|
153
|
-
# Do not run statistics if called
|
195
|
+
# Do not run statistics if called from command line
|
154
196
|
if lint_opts[:commit].blank?
|
155
197
|
|
156
198
|
statistics[:phantomas] = Maximus::Phantomas.new(stat_opts).result
|
157
199
|
|
158
|
-
#
|
200
|
+
# @todo double pipe here is best way to say, if it's already run, don't run again, right?
|
159
201
|
statistics[:wraith] ||= Maximus::Wraith.new(stat_opts).result
|
160
202
|
end
|
161
203
|
when :ruby
|
@@ -166,7 +208,7 @@ module Maximus
|
|
166
208
|
lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result
|
167
209
|
end
|
168
210
|
end
|
169
|
-
#
|
211
|
+
# @todo better way to silence git, in case there's a real error?
|
170
212
|
quietly {
|
171
213
|
@g.branch(base_branch).checkout
|
172
214
|
@g.branch("maximus_#{sha}").delete
|
@@ -179,15 +221,28 @@ module Maximus
|
|
179
221
|
protected
|
180
222
|
|
181
223
|
# Get list of file paths
|
182
|
-
#
|
224
|
+
#
|
225
|
+
# @param files [Hash] hash of files denoted by key 'filename'
|
226
|
+
# @param ext [String] file extension - different extensions are joined different ways
|
227
|
+
# @return [String] file paths delimited by comma or space
|
183
228
|
def lint_file_paths(files, ext)
|
184
229
|
file_list = files.map { |f| f[:filename] }.compact
|
185
230
|
# Lints accept files differently
|
186
231
|
ext == :ruby ? file_list.join(' ') : file_list.join(',')
|
187
232
|
end
|
188
233
|
|
189
|
-
#
|
190
|
-
#
|
234
|
+
# Determine which lines were added (where and how many) in a commit
|
235
|
+
#
|
236
|
+
# @example output from method
|
237
|
+
# {
|
238
|
+
# 'filename': [
|
239
|
+
# '0..10',
|
240
|
+
# '11..14'
|
241
|
+
# ]
|
242
|
+
# }
|
243
|
+
#
|
244
|
+
# @param git_sha [String] sha of the commit
|
245
|
+
# @return [Hash] ranges by lines added in a commit by file name
|
191
246
|
def lines_added(git_sha)
|
192
247
|
new_lines = {}
|
193
248
|
lines_added = `#{File.join(File.dirname(__FILE__), 'reporter/git-lines.sh')} #{git_sha}`.split("\n")
|
@@ -204,44 +259,50 @@ module Maximus
|
|
204
259
|
end
|
205
260
|
|
206
261
|
# Get last commit on current branch
|
207
|
-
#
|
262
|
+
#
|
263
|
+
# @return [String] sha
|
208
264
|
def sha
|
209
265
|
@g.object('HEAD').sha
|
210
266
|
end
|
211
267
|
|
212
|
-
# Get branch name
|
213
|
-
#
|
268
|
+
# Get current branch name
|
269
|
+
#
|
270
|
+
# @return [String]
|
214
271
|
def branch
|
215
272
|
`env -i git rev-parse --abbrev-ref HEAD`.strip!
|
216
273
|
end
|
217
274
|
|
218
275
|
# Get last commit on the master branch
|
219
|
-
#
|
276
|
+
#
|
277
|
+
# @return [Git::Object]
|
220
278
|
def master_commit
|
221
279
|
@g.branches[:master].gcommit
|
222
280
|
end
|
223
281
|
|
224
282
|
# Store last commit as Ruby Git::Object
|
225
|
-
#
|
283
|
+
# @param commitsha [String]
|
284
|
+
# @return [Git::Object]
|
226
285
|
def vccommit(commitsha = sha)
|
227
286
|
@g.gcommit(commitsha)
|
228
287
|
end
|
229
288
|
|
230
289
|
# Get general stats of commit on HEAD versus last commit on master branch
|
231
|
-
#
|
232
|
-
#
|
290
|
+
#
|
291
|
+
# @return [Git::Diff]
|
233
292
|
def diff(new_commit = vccommit, old_commit = master_commit)
|
234
293
|
@g.diff(new_commit, old_commit).stats
|
235
294
|
end
|
236
295
|
|
237
296
|
# Get remote URL
|
238
|
-
#
|
297
|
+
#
|
298
|
+
# @return [String, nil] nil returns if remotes is blank
|
239
299
|
def remote
|
240
300
|
@g.remotes.first.url unless @g.remotes.blank?
|
241
301
|
end
|
242
302
|
|
243
303
|
# Define associations to linters based on file extension
|
244
|
-
#
|
304
|
+
#
|
305
|
+
# @return [Hash] linters and extension arrays
|
245
306
|
def associations
|
246
307
|
{
|
247
308
|
scss: ['scss', 'sass'],
|
data/lib/maximus/helper.rb
CHANGED
@@ -5,51 +5,70 @@ require 'active_support/core_ext/object/blank'
|
|
5
5
|
require 'yaml'
|
6
6
|
|
7
7
|
module Maximus
|
8
|
+
# @since 0.1.0
|
8
9
|
module Helper
|
9
10
|
|
10
|
-
# See if
|
11
|
-
# This will usually be stored as a class variable in the inherited class
|
12
|
-
#
|
11
|
+
# See if project linted is a Rails app
|
12
|
+
# This will usually be stored as a class variable in the inherited class
|
13
|
+
# @example class variable
|
14
|
+
# @@is_rails = is_rails?
|
15
|
+
#
|
16
|
+
# @see Lint#initialize
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
13
19
|
def is_rails?
|
14
20
|
defined?(Rails)
|
15
21
|
end
|
16
22
|
|
17
23
|
# Get root directory of file being called
|
18
|
-
#
|
24
|
+
#
|
25
|
+
# @return [String] absolute path to root directory
|
19
26
|
def root_dir
|
20
27
|
is_rails? ? Rails.root.to_s : Dir.pwd.to_s
|
21
28
|
end
|
22
29
|
|
23
|
-
# Verify that
|
24
|
-
#
|
25
|
-
|
26
|
-
|
30
|
+
# Verify that command is available on the box before continuing
|
31
|
+
#
|
32
|
+
# @param command [String] command to check
|
33
|
+
# @param install_instructions [String] how to install the missing command
|
34
|
+
# @return [void] aborts the action if command not found
|
35
|
+
def node_module_exists(command, install_instructions = 'npm install -g')
|
36
|
+
cmd = `if hash #{command} 2>/dev/null; then
|
27
37
|
echo "true"
|
28
38
|
else
|
29
39
|
echo "false"
|
30
40
|
fi`
|
31
41
|
if cmd.include? "false"
|
32
|
-
command_msg = "Missing command #{
|
33
|
-
abort "#{command_msg}: Please run `#{install_instructions} #{
|
42
|
+
command_msg = "Missing command #{command}".color(:red)
|
43
|
+
abort "#{command_msg}: Please run `#{install_instructions} #{command}` And try again\n"
|
44
|
+
exit 1
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
37
|
-
# Look for a custom config in the app's config/ directory;
|
38
|
-
#
|
39
|
-
#
|
48
|
+
# Look for a custom config in the app's config/ directory;
|
49
|
+
# otherwise, use the built-in one.
|
50
|
+
# @todo best practice that this inherits the @opts from the model it's being included in?
|
51
|
+
#
|
52
|
+
# @param filename [String]
|
53
|
+
# @return [String] absolute path to the reporter file
|
40
54
|
def check_default(filename)
|
41
55
|
user_file = "#{@opts[:root_dir]}/config/#{filename}"
|
42
56
|
File.exist?(user_file) ? user_file : File.join(File.dirname(__FILE__), "config/#{filename}")
|
43
57
|
end
|
44
58
|
|
45
59
|
# Grab the absolute path of the reporter file
|
46
|
-
#
|
60
|
+
#
|
61
|
+
# @param filename [String]
|
62
|
+
# @return [String] absolute path to the reporter file
|
47
63
|
def reporter_path(filename)
|
48
64
|
File.join(File.dirname(__FILE__),"reporter/#{filename}")
|
49
65
|
end
|
50
66
|
|
51
67
|
# Find all files that were linted by extension
|
52
|
-
#
|
68
|
+
#
|
69
|
+
# @param path [String] path to folders
|
70
|
+
# @param ext [String] file extension to search for
|
71
|
+
# @return [Array<String>] list of file paths
|
53
72
|
def file_list(path, ext = 'scss', remover = '')
|
54
73
|
# Necessary so that directories aren't counted
|
55
74
|
collect_path = path.include?("*") ? path : "#{path}/**/*.#{ext}"
|
@@ -58,20 +77,26 @@ module Maximus
|
|
58
77
|
end
|
59
78
|
|
60
79
|
# Count how many files were linted
|
61
|
-
#
|
80
|
+
#
|
81
|
+
# @param path [String] path to folders
|
82
|
+
# @param ext [String] file extension to search for
|
83
|
+
# @return [Integer] number of files matched by the path
|
62
84
|
def file_count(path, ext = 'scss')
|
63
85
|
file_list(path, ext).length
|
64
86
|
end
|
65
87
|
|
66
88
|
# Convert string to boolean
|
67
|
-
#
|
89
|
+
#
|
90
|
+
# @param str [String] the string to evaluate
|
91
|
+
# @return [Boolean] whether or not the string is true
|
68
92
|
def truthy(str)
|
69
93
|
return true if str == true || str =~ (/^(true|t|yes|y|1)$/i)
|
70
94
|
return false if str == false || str.blank? || str =~ (/^(false|f|no|n|0)$/i)
|
71
95
|
end
|
72
96
|
|
73
97
|
# Edit and save a YAML file
|
74
|
-
#
|
98
|
+
#
|
99
|
+
# @return [void]
|
75
100
|
def edit_yaml(yaml_location, &block)
|
76
101
|
d = YAML.load_file(yaml_location)
|
77
102
|
block.call(d)
|
@@ -79,41 +104,53 @@ module Maximus
|
|
79
104
|
end
|
80
105
|
|
81
106
|
# Request user input
|
82
|
-
#
|
107
|
+
#
|
108
|
+
# @param args [Array<String>] prompts to request
|
109
|
+
# @return [String] user input to use elsewhere
|
83
110
|
def prompt(*args)
|
84
111
|
print(*args)
|
85
112
|
STDIN.gets
|
86
113
|
end
|
87
114
|
|
88
|
-
# Defines base
|
89
|
-
#
|
115
|
+
# Defines base logger
|
116
|
+
#
|
117
|
+
# @return [Logger] @@log for logging use
|
90
118
|
def mlog
|
91
119
|
@@log ||= Logger.new(STDOUT)
|
92
120
|
@@log.level ||= Logger::INFO
|
93
121
|
@@log
|
94
122
|
end
|
95
123
|
|
96
|
-
# Determine if current process was called by a rake task
|
97
|
-
# Returns Boolean
|
98
|
-
# http://stackoverflow.com/questions/2467208/how-can-i-tell-if-rails-code-is-being-run-via-rake-or-script-generate
|
99
|
-
def is_rake_task?
|
100
|
-
File.basename($0) == 'rake'
|
101
|
-
end
|
102
|
-
|
103
124
|
# Convert the array from lines_added into spelled-out ranges
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
125
|
+
# This is a GitControl helper but it's used in Lint
|
126
|
+
# @see GitControl#lines_added
|
127
|
+
# @see Lint#relevant_lint
|
128
|
+
#
|
129
|
+
# @example typical output
|
130
|
+
# lines_added = {'filename' => ['0..10', '11..14']}
|
131
|
+
# lines_added_to_range(lines_added)
|
132
|
+
# # output
|
133
|
+
# {
|
134
|
+
# 'filename': {
|
135
|
+
# {
|
136
|
+
# [0,1,2,3,4,5,6,7,8,9,10],
|
137
|
+
# [11,12,13,14]
|
138
|
+
# }
|
139
|
+
# }
|
140
|
+
# }
|
141
|
+
#
|
142
|
+
# @todo I'm sure there's a better way of doing this
|
143
|
+
# @todo figure out a better place to put this than in Helper
|
144
|
+
# @return [Hash] changes_array of spelled-out arrays of integers
|
110
145
|
def lines_added_to_range(file)
|
111
146
|
changes_array = file[:changes].map { |ch| ch.split("..").map(&:to_i) }
|
112
147
|
changes_array.map { |e| (e[0]..e[1]).to_a }.flatten!
|
113
148
|
end
|
114
149
|
|
115
|
-
# Ensure
|
116
|
-
#
|
150
|
+
# Ensure path exists
|
151
|
+
#
|
152
|
+
# @param path [String, Array] path to files can be directory or glob
|
153
|
+
# @return [Boolean]
|
117
154
|
def path_exists(path = @path)
|
118
155
|
path = path.split(' ') if path.is_a?(String) && path.include?(' ')
|
119
156
|
if path.is_a?(Array)
|