supercop 0.2.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +94 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/supercop.rb +36 -0
- data/lib/supercop/actions/clean.rb +93 -0
- data/lib/supercop/actions/config_copier.rb +46 -0
- data/lib/supercop/actions/file_injector.rb +35 -0
- data/lib/supercop/actions/loaders/base.rb +58 -0
- data/lib/supercop/actions/loaders/dependency.rb +65 -0
- data/lib/supercop/checker.rb +16 -0
- data/lib/supercop/configuration.rb +61 -0
- data/lib/supercop/cop.rb +43 -0
- data/lib/supercop/generators/config_generator.rb +17 -0
- data/lib/supercop/parsers/base.rb +38 -0
- data/lib/supercop/parsers/proxy.rb +33 -0
- data/lib/supercop/parsers/rubocop.rb +11 -0
- data/lib/supercop/parsers/scss_lint.rb +13 -0
- data/lib/supercop/railtie.rb +14 -0
- data/lib/supercop/table_formatter.rb +42 -0
- data/lib/supercop/templates/supercop.yml +86 -0
- data/lib/supercop/version.rb +3 -0
- data/lib/tasks/check.rake +8 -0
- data/lib/tasks/manage_settings.rake +42 -0
- data/supercop.gemspec +34 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a69ce9a6b65284cfe4c831111c5eee5e7361d91d
|
4
|
+
data.tar.gz: c3ca2a2d82a22bd5acedaa22033a700f26ee7d4e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ec097698283f997ae6b1f0b1c66b1428c428c774b6ddb85ac1f525cee6b5599bfd0555d868c964595fa4f91a6037f7b4478445ec3c6cc84a0cf54ab1a593bba3
|
7
|
+
data.tar.gz: 7bbe552029a0dcaa38000c06db531f0d8441411327f3b5f8add50b192a643369af54e592f9ed50f7586b0305b739af83bc717ae6b74de3d82f384d51d8a5065a
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Artem Kuznetsov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# Supercop
|
2
|
+
[](https://travis-ci.org/artemasmith/supercop)
|
3
|
+
|
4
|
+
This gem allows you to combine multiple linters with their configs in one place and run all checks by one command with tabled-view summary report (see below).
|
5
|
+
You should specify which linters you would like to use, for example rubocop, reek,
|
6
|
+
scss_linter etc. Gem would load them if they are not installed and run checks.
|
7
|
+
|
8
|
+
One gem for rule them all:)
|
9
|
+
|
10
|
+
### Versions
|
11
|
+
|
12
|
+
It works for 2.2.3, 2.3.1, 2.3.3 versions of Ruby MRI.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'supercop'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install supercop
|
29
|
+
|
30
|
+
### Install into another gem
|
31
|
+
|
32
|
+
Add supercop tasks to the Rakefile:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
spec = Gem::Specification.find_by_name 'supercop'
|
36
|
+
load "#{spec.gem_dir}/lib/tasks/manage_settings.rake"
|
37
|
+
load "#{spec.gem_dir}/lib/tasks/check.rake"
|
38
|
+
```
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
After install, you should modify supercop.yml and specify prefered linters.
|
43
|
+
After that run
|
44
|
+
|
45
|
+
$ rake supercop:generate_config
|
46
|
+
|
47
|
+
for non-rails project (like gem) or
|
48
|
+
|
49
|
+
$ rails g supercop:config
|
50
|
+
|
51
|
+
for rails project
|
52
|
+
|
53
|
+
After that, please modify your supercop.yml config file, adding linters you want to use and run
|
54
|
+
|
55
|
+
$ rake supercop:load_dependencies
|
56
|
+
|
57
|
+
or you can do it manually by adding gems to your Gemfile (for other gems - to the end of file) and running bundle install.
|
58
|
+
|
59
|
+
`Note:` You should do it once.
|
60
|
+
|
61
|
+
Now you can run checks.
|
62
|
+
|
63
|
+
### Clean up
|
64
|
+
|
65
|
+
If you want to restore all affected files and clean up supercop remnants, please run
|
66
|
+
|
67
|
+
$ rake supercop:cleanup
|
68
|
+
|
69
|
+
This will delete config file and erase changes made by Supercop to your Gemfile and bundle.
|
70
|
+
|
71
|
+
### Running check
|
72
|
+
|
73
|
+
$ rake supercop:check
|
74
|
+
|
75
|
+
| linter | alerts | max | status |
|
76
|
+
| ------------------ |:------------------:|:------------------:|:------------------:|
|
77
|
+
| rubocop | 48 | 99 | ok |
|
78
|
+
| reek | 45 | 99 | ok |
|
79
|
+
| slim_lint | none | 99 | ok |
|
80
|
+
| scss_lint | none | 99 | ok |
|
81
|
+
|
82
|
+
'none' - means linter did not work correctly. To figured out why - change 'verbose' option to true
|
83
|
+
|
84
|
+
## Development
|
85
|
+
|
86
|
+
After checking out the repo, run bundle install and make your changes. After commit, create Pull Request and notify me.
|
87
|
+
|
88
|
+
## Contributing
|
89
|
+
|
90
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/artemasmith/supercop.
|
91
|
+
|
92
|
+
## License
|
93
|
+
|
94
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "supercop"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/supercop.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
+
|
5
|
+
require 'supercop/cop'
|
6
|
+
require 'supercop/version'
|
7
|
+
require 'supercop/checker'
|
8
|
+
require 'supercop/configuration'
|
9
|
+
require 'supercop/table_formatter'
|
10
|
+
require 'supercop/actions/config_copier'
|
11
|
+
require 'supercop/actions/file_injector'
|
12
|
+
require 'supercop/actions/clean'
|
13
|
+
require 'supercop/actions/loaders/base'
|
14
|
+
require 'supercop/actions/loaders/dependency'
|
15
|
+
require 'supercop/parsers/base'
|
16
|
+
require 'supercop/parsers/proxy'
|
17
|
+
require 'supercop/parsers/scss_lint'
|
18
|
+
require 'supercop/parsers/rubocop'
|
19
|
+
|
20
|
+
require 'json'
|
21
|
+
require 'yaml'
|
22
|
+
|
23
|
+
if defined?(Rails)
|
24
|
+
require 'supercop/railtie'
|
25
|
+
require 'rails/generators'
|
26
|
+
end
|
27
|
+
|
28
|
+
module Supercop
|
29
|
+
class << self
|
30
|
+
attr_accessor :configuration
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.configuration
|
34
|
+
@configuration ||= Configuration.new
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Actions
|
3
|
+
class Clean
|
4
|
+
class << self
|
5
|
+
def call
|
6
|
+
if clean_gemfile[:changed]
|
7
|
+
restore_gemfile
|
8
|
+
|
9
|
+
update_bundle
|
10
|
+
else
|
11
|
+
notify_nothing_changed
|
12
|
+
end
|
13
|
+
|
14
|
+
remove_config
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def notify_nothing_changed
|
20
|
+
puts 'Your Gemfile was not changed. Nothing to restore.'
|
21
|
+
end
|
22
|
+
|
23
|
+
def restore_gemfile
|
24
|
+
puts 'Restoring your Gemfile'
|
25
|
+
|
26
|
+
temp_file = "#{gemfile}.tmp"
|
27
|
+
|
28
|
+
File.open(temp_file, 'w') do |f|
|
29
|
+
f.print(clean_gemfile[:gemfile])
|
30
|
+
end
|
31
|
+
|
32
|
+
FileUtils.mv temp_file, gemfile
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_bundle
|
36
|
+
puts 'Updating your bundle, please wait'
|
37
|
+
|
38
|
+
Bundler.with_clean_env do
|
39
|
+
`bundle install`
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def clean_gemfile
|
44
|
+
clean_gemfile = []
|
45
|
+
changed = false
|
46
|
+
|
47
|
+
File.open(gemfile, 'r') do |f|
|
48
|
+
until (line = f.gets).nil?
|
49
|
+
if line.include?(start_comment)
|
50
|
+
changed = true
|
51
|
+
until (line = f.gets).nil?
|
52
|
+
if line.include?(end_comment)
|
53
|
+
line = f.gets
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
clean_gemfile << line
|
60
|
+
end
|
61
|
+
end
|
62
|
+
@_clean_gemfile = { gemfile: clean_gemfile.join, changed: changed }
|
63
|
+
end
|
64
|
+
|
65
|
+
def remove_config
|
66
|
+
if File.file?(supercop_config)
|
67
|
+
puts 'Removing your supercop.yml'
|
68
|
+
|
69
|
+
FileUtils.rm(supercop_config)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def gemfile
|
74
|
+
@_gemfile ||= File.join(Dir.pwd, 'Gemfile')
|
75
|
+
end
|
76
|
+
|
77
|
+
def supercop_config
|
78
|
+
root = defined?(Rails) ? File.join(Dir.pwd, 'config') : Dir.pwd
|
79
|
+
|
80
|
+
@_supercop_config ||= File.join(root, 'supercop.yml')
|
81
|
+
end
|
82
|
+
|
83
|
+
def start_comment
|
84
|
+
Supercop::Actions::Loaders::Dependency::START_COMMENT
|
85
|
+
end
|
86
|
+
|
87
|
+
def end_comment
|
88
|
+
Supercop::Actions::Loaders::Dependency::END_COMMENT
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Actions
|
3
|
+
class ConfigCopier
|
4
|
+
require 'fileutils'
|
5
|
+
CONFIG_PATH = %w[lib supercop templates].freeze
|
6
|
+
|
7
|
+
def initialize(args)
|
8
|
+
@filename = args.fetch(:filename, 'supercop.yml')
|
9
|
+
@destination = args.fetch(:destination)
|
10
|
+
@options = args.fetch(:options, {})
|
11
|
+
@source = args.fetch(:source, 'supercop.yml')
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
return "There is no destination #{destination}" if invalid_destination?
|
16
|
+
return "#{destination_file} already exists" if File.file?(destination_file)
|
17
|
+
|
18
|
+
FileUtils.copy(source_file, destination_file, options)
|
19
|
+
|
20
|
+
"file #{destination_file} was created"
|
21
|
+
rescue => e
|
22
|
+
"Could not create file. #{e.message}"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :filename, :destination, :source, :options
|
28
|
+
|
29
|
+
def invalid_destination?
|
30
|
+
destination.empty? || !Dir.exist?(destination)
|
31
|
+
end
|
32
|
+
|
33
|
+
def source_file
|
34
|
+
File.join(root, CONFIG_PATH, source)
|
35
|
+
end
|
36
|
+
|
37
|
+
def destination_file
|
38
|
+
File.join(destination, filename)
|
39
|
+
end
|
40
|
+
|
41
|
+
def root
|
42
|
+
Gem.loaded_specs['supercop'].full_gem_path
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Actions
|
3
|
+
class FileInjector
|
4
|
+
attr_reader :filename, :line
|
5
|
+
|
6
|
+
def initialize(filename:, line:)
|
7
|
+
@filename = filename
|
8
|
+
@line = line
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return if file_include?
|
13
|
+
|
14
|
+
insert_into_file
|
15
|
+
end
|
16
|
+
|
17
|
+
def file_include?
|
18
|
+
File.foreach(filename).grep(sanitized).present?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
|
24
|
+
def insert_into_file
|
25
|
+
File.open(filename, 'a') do |f|
|
26
|
+
f.write(line)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def sanitized
|
31
|
+
line.sub(/\s\n$/, '')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Actions
|
3
|
+
module Loaders
|
4
|
+
class Base
|
5
|
+
BUNDLE_REQUIRED = :bundle_required
|
6
|
+
|
7
|
+
attr_reader :gem_name, :config, :injector, :file
|
8
|
+
|
9
|
+
def initialize(gem_name)
|
10
|
+
@gem_name = gem_name
|
11
|
+
@config = Supercop.configuration.public_send(gem_name)
|
12
|
+
@injector = Supercop::Actions::FileInjector
|
13
|
+
@file = Supercop.configuration.path('Gemfile')
|
14
|
+
end
|
15
|
+
|
16
|
+
def installed?
|
17
|
+
load_gem
|
18
|
+
true
|
19
|
+
rescue LoadError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
add_gem
|
25
|
+
|
26
|
+
puts "'#{gem_name}' was added as dependency.\n"
|
27
|
+
BUNDLE_REQUIRED
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def load_gem
|
33
|
+
require gem_name.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_gem
|
37
|
+
puts "Inserting into #{file} \n"
|
38
|
+
puts "gem config #{gem_config}\n"
|
39
|
+
|
40
|
+
injector.new(filename: file, line: gem_config).call
|
41
|
+
end
|
42
|
+
|
43
|
+
def gem_config
|
44
|
+
result = ["gem '#{gem_name}'"]
|
45
|
+
result << ", #{config[:version]}" if option?(:version)
|
46
|
+
result << ", path: '#{config[:path]}'" if option?(:path)
|
47
|
+
result << ", git: '#{config[:git]}'" if option?(:git) && !option?(:path)
|
48
|
+
result << "\n"
|
49
|
+
result.join(' ')
|
50
|
+
end
|
51
|
+
|
52
|
+
def option?(option)
|
53
|
+
config.keys.include?(option)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Actions
|
3
|
+
module Loaders
|
4
|
+
class Dependency
|
5
|
+
BUNDLE_REQUIRED = :bundle_required
|
6
|
+
START_COMMENT = "####### SUPERCOP #######\n".freeze
|
7
|
+
END_COMMENT = "#### ENDOF SUPERCOP ####\n".freeze
|
8
|
+
|
9
|
+
attr_reader :gem_list, :loader, :file_injector
|
10
|
+
|
11
|
+
def initialize(loader = nil)
|
12
|
+
@gem_list = Supercop.configuration.cops_settings.keys
|
13
|
+
@loader = loader || Base
|
14
|
+
@file_injector = Supercop::Actions::FileInjector
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
puts 'Loading dependecies, please wait..'
|
19
|
+
|
20
|
+
if gems_to_add.empty?
|
21
|
+
say_nothing_needed
|
22
|
+
else
|
23
|
+
wrap_for_gemfile do
|
24
|
+
gems_to_add.each { |gem_name| loader.new(gem_name).call }
|
25
|
+
end
|
26
|
+
|
27
|
+
install
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alias load_dependencies call
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def gems_to_add
|
36
|
+
gem_list.select { |gem_name| !loaded?(gem_name) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def loaded?(gem_name)
|
40
|
+
loader.new(gem_name).installed? ? true : false
|
41
|
+
end
|
42
|
+
|
43
|
+
def install
|
44
|
+
puts 'Updating your bundle, please wait'
|
45
|
+
Bundler.with_clean_env do
|
46
|
+
`bundle install`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def say_nothing_needed
|
51
|
+
puts 'No need to install anything.'
|
52
|
+
end
|
53
|
+
|
54
|
+
def wrap_for_gemfile(&_block)
|
55
|
+
file = Supercop.configuration.path('Gemfile')
|
56
|
+
file_injector.new(filename: file, line: START_COMMENT).call
|
57
|
+
|
58
|
+
yield
|
59
|
+
|
60
|
+
file_injector.new(filename: file, line: END_COMMENT).call
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Supercop
|
2
|
+
class Checker
|
3
|
+
attr_reader :linters, :printer, :cop
|
4
|
+
def initialize(printer = TableFormatter)
|
5
|
+
@linters = Supercop.configuration.cops_settings.keys
|
6
|
+
@printer = printer
|
7
|
+
@cop = Cop
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
checks_result = linters.map { |linter| cop.new(linter).handle }
|
12
|
+
|
13
|
+
printer.new.print_table(checks_result)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Supercop
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :cops_settings, :verbose, :file_path
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@cops_settings = config_file.fetch(:config)
|
7
|
+
@verbose = config_file.fetch(:verbose)
|
8
|
+
@file_path = config_path
|
9
|
+
end
|
10
|
+
|
11
|
+
def path(file_path)
|
12
|
+
defined?(Rails) ? Rails.root.join(file_path) : File.join(Dir.pwd, file_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def config_file
|
18
|
+
@_config_file ||= YAML.load_file(config_path).with_indifferent_access
|
19
|
+
rescue => e
|
20
|
+
puts "Can't find or read config file, did you run initialize command? #{e.message}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def config_path
|
24
|
+
@_config_path ||= defined?(Rails) ? rails_path : other_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def rails_path
|
28
|
+
Rails.root.join('config', 'supercop.yml')
|
29
|
+
end
|
30
|
+
|
31
|
+
def other_path
|
32
|
+
File.join(Dir.pwd, 'supercop.yml')
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(m, *args, &block)
|
36
|
+
define_dig unless cops_settings.methods.include?(:dig)
|
37
|
+
|
38
|
+
cops_settings.dig(m) || super
|
39
|
+
end
|
40
|
+
|
41
|
+
# FYI: dirty hack for ruby < 2.3
|
42
|
+
def define_dig
|
43
|
+
new_method = <<-NEW
|
44
|
+
class ::Hash
|
45
|
+
def dig(*path)
|
46
|
+
path.inject(self) do |location, key|
|
47
|
+
location.is_a?(Hash) ? location[key] : nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
NEW
|
52
|
+
|
53
|
+
eval(new_method)
|
54
|
+
end
|
55
|
+
|
56
|
+
# https://robots.thoughtbot.com/always-define-respond-to-missing-when-overriding
|
57
|
+
def respond_to_missing?(method_name, include_private = false)
|
58
|
+
cops_settings.keys.include?(method_name) || super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/supercop/cop.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Supercop
|
2
|
+
class Cop
|
3
|
+
attr_reader :linter, :cop_config, :parser, :config
|
4
|
+
|
5
|
+
def initialize(linter)
|
6
|
+
@linter = linter
|
7
|
+
@parser = Supercop::Parsers::Proxy
|
8
|
+
@config = Supercop.configuration
|
9
|
+
@cop_config = config.public_send(linter)
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle
|
13
|
+
result = parse_cop_config
|
14
|
+
|
15
|
+
output = %i[linter warnings_actual warnings_max].map { |key| result[key] }
|
16
|
+
output << linter_status(result[:warnings_actual], result[:warnings_max])
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def linter_status(actual, max)
|
22
|
+
actual.to_i < max ? 'ok' : 'fail'
|
23
|
+
end
|
24
|
+
|
25
|
+
def actual_warnings_count
|
26
|
+
output = `#{cop_config.fetch('cmd')} #{cop_config.fetch('options')}`
|
27
|
+
|
28
|
+
parser.new(output, linter).parse.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_cop_config
|
32
|
+
return if linter.blank?
|
33
|
+
|
34
|
+
{ warnings_actual: actual_warnings_count,
|
35
|
+
warnings_max: cop_config.fetch('max'),
|
36
|
+
linter: linter }
|
37
|
+
rescue => e
|
38
|
+
puts "Problems with linter config load. #{e.message}" if config.verbose
|
39
|
+
|
40
|
+
{ linter: linter, warnings_actual: 0, warnings_max: 0 }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < ::Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __dir__)
|
5
|
+
|
6
|
+
puts '=> Creates a Supercop idefault config for your application.'
|
7
|
+
|
8
|
+
def copy_config_file
|
9
|
+
destination = 'config/supercop.yml'
|
10
|
+
|
11
|
+
puts "=> Copy config file to #{destination}"
|
12
|
+
|
13
|
+
copy_file 'supercop.yml', destination
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Parsers
|
3
|
+
class Base
|
4
|
+
attr_reader :json, :config
|
5
|
+
|
6
|
+
def initialize(json)
|
7
|
+
@json = json
|
8
|
+
@config = Supercop.configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
warnings_count
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def parse
|
18
|
+
JSON.parse(json).count
|
19
|
+
end
|
20
|
+
|
21
|
+
def warnings_count
|
22
|
+
parse
|
23
|
+
rescue => e
|
24
|
+
parse_error(e)
|
25
|
+
|
26
|
+
'none'
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_error(e)
|
30
|
+
msg = %Q[Wrong configuration for linter,
|
31
|
+
please check the path and options provided.
|
32
|
+
Error: #{e.message}]
|
33
|
+
|
34
|
+
puts msg if config.verbose
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Supercop
|
2
|
+
module Parsers
|
3
|
+
class Proxy
|
4
|
+
RUBOCOP = %w[SlimLint HamlLint].freeze
|
5
|
+
|
6
|
+
attr_reader :json, :linter, :parser
|
7
|
+
|
8
|
+
def initialize(json, linter)
|
9
|
+
@linter = linter
|
10
|
+
@json = json
|
11
|
+
@parser = find_parser
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse
|
15
|
+
parser.call
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def find_parser
|
21
|
+
return Rubocop.new(json) if rubocop_like_parser?
|
22
|
+
|
23
|
+
('Supercop::Parsers::' + linter.classify).constantize.new(json)
|
24
|
+
rescue NameError
|
25
|
+
Base.new(json)
|
26
|
+
end
|
27
|
+
|
28
|
+
def rubocop_like_parser?
|
29
|
+
RUBOCOP.include?(linter.classify)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Supercop
|
2
|
+
# FYI: Here we defined rake tasks and generators for Rails use
|
3
|
+
require 'rails/railtie'
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
rake_tasks do
|
6
|
+
load 'tasks/manage_settings.rake'
|
7
|
+
load 'tasks/check.rake'
|
8
|
+
end
|
9
|
+
|
10
|
+
generators do
|
11
|
+
require_relative 'generators/config_generator'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Supercop
|
2
|
+
class TableFormatter
|
3
|
+
CELL_WIDTH = 20
|
4
|
+
DEFAULT_COLUMNS = %w[linter alerts max status].freeze
|
5
|
+
|
6
|
+
def initialize(columns = nil)
|
7
|
+
@columns = columns || DEFAULT_COLUMNS
|
8
|
+
end
|
9
|
+
|
10
|
+
def print_table(lines)
|
11
|
+
puts header
|
12
|
+
|
13
|
+
lines.each { |elements| puts line(elements) }
|
14
|
+
|
15
|
+
puts footer
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def header
|
21
|
+
dash_line + "\n" + line(@columns) + "\n" + dash_line
|
22
|
+
end
|
23
|
+
|
24
|
+
def dash_line
|
25
|
+
line = '+'
|
26
|
+
@columns.count.times { line += Array.new(CELL_WIDTH, '-').join + '+' }
|
27
|
+
line
|
28
|
+
end
|
29
|
+
|
30
|
+
def footer
|
31
|
+
dash_line
|
32
|
+
end
|
33
|
+
|
34
|
+
def line(elements)
|
35
|
+
'|' + elements.map { |element| cell(element.to_s) }.join
|
36
|
+
end
|
37
|
+
|
38
|
+
def cell(word)
|
39
|
+
word.center(word.length + (CELL_WIDTH - word.length).abs) + '|'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# FYI: 'cmd', 'options' and 'max' are required.
|
2
|
+
# 'path', 'git', 'version' and 'path' are optional params for installation.
|
3
|
+
# 'version' would not work with 'path' param.
|
4
|
+
# 'path' option is more priority and overrides 'git' option.
|
5
|
+
#
|
6
|
+
# File Format:
|
7
|
+
#
|
8
|
+
# linter: - gem name of linter to download
|
9
|
+
# cmd*: - command that run in command line
|
10
|
+
# option*: - options for cmd command to run. Please spcify here json output for normal parsing
|
11
|
+
# version: - version of gem to install
|
12
|
+
# git: - repo for gem download
|
13
|
+
# path: - local file system path to gem. It overrides git option
|
14
|
+
# max*: - maximum errors for linter to define ok or fail status of check
|
15
|
+
#
|
16
|
+
# * - required
|
17
|
+
#
|
18
|
+
# `Please note`, that you should specify JSON output param for correct parsing
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# rubocop:
|
23
|
+
# cmd: 'rubocop'
|
24
|
+
# options: '--jormat default'
|
25
|
+
# path: '/home/developer/rubocopgem/'
|
26
|
+
# version: '1.0.1'
|
27
|
+
# max: 20
|
28
|
+
#
|
29
|
+
# With git param:
|
30
|
+
#
|
31
|
+
# rubocop:
|
32
|
+
# cmd: 'rubocop'
|
33
|
+
# options: '--jormat default'
|
34
|
+
# git: 'git@github.com/developer/rubocop.git'
|
35
|
+
# version: '1.0.1'
|
36
|
+
#
|
37
|
+
# `Important!`
|
38
|
+
#
|
39
|
+
# Please use gem names for the configuration keys, like you add it to your gemfile
|
40
|
+
# For example:
|
41
|
+
# Correct:
|
42
|
+
#
|
43
|
+
# sccs_lint:
|
44
|
+
# cmd: 'scss-lint'
|
45
|
+
# version: '0.69'
|
46
|
+
#
|
47
|
+
# Incorrect - it wouldn't work
|
48
|
+
#
|
49
|
+
# scss-lint:
|
50
|
+
# cmd: 'scss-lint'
|
51
|
+
# version: '0.69'
|
52
|
+
#
|
53
|
+
# Template config fo rails project with slim
|
54
|
+
# max: &max_quantity
|
55
|
+
# max: 99
|
56
|
+
# verbose: false
|
57
|
+
# config:
|
58
|
+
# rubocop:
|
59
|
+
# cmd: 'rubocop'
|
60
|
+
# options: '--format json'
|
61
|
+
# git: 'git@github.com:bbatsov/rubocop.git'
|
62
|
+
# version: '~0.49'
|
63
|
+
# <<: *max_quantity
|
64
|
+
# slim_lint:
|
65
|
+
# cmd: 'slim-lint'
|
66
|
+
# options: 'app/views --reporter json'
|
67
|
+
# version: '~> 0.13.0'
|
68
|
+
# <<: *max_quantity
|
69
|
+
# scss_lint:
|
70
|
+
# cmd: 'scss-lint'
|
71
|
+
# options: 'app/assets --format JSON'
|
72
|
+
# <<: *max_quantity
|
73
|
+
|
74
|
+
max: &max_quantity
|
75
|
+
max: 99
|
76
|
+
verbose: false
|
77
|
+
config:
|
78
|
+
rubocop:
|
79
|
+
cmd: 'rubocop'
|
80
|
+
options: '--format json'
|
81
|
+
git: 'git@github.com:bbatsov/rubocop.git'
|
82
|
+
<<: *max_quantity
|
83
|
+
reek:
|
84
|
+
cmd: 'reek'
|
85
|
+
options: '--format json'
|
86
|
+
<<: *max_quantity
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'supercop'
|
2
|
+
|
3
|
+
namespace :supercop do
|
4
|
+
desc 'Create config file in your project, and load dependecies'
|
5
|
+
task :generate_config do
|
6
|
+
if defined?(Rails)
|
7
|
+
generate_for_rails
|
8
|
+
else
|
9
|
+
generate_for_other
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Add missing dependencies to your Gemfile and run bundle install'
|
14
|
+
task :load_dependencies do
|
15
|
+
loader.load_dependencies
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Clean up changes made by supercop: config, gems'
|
19
|
+
task :cleanup do
|
20
|
+
cleaner.call
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_for_rails
|
24
|
+
puts 'Please, use rails generator instead!'
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_for_other
|
28
|
+
puts 'Generate config for your supercop linters'
|
29
|
+
|
30
|
+
destination = Dir.pwd
|
31
|
+
|
32
|
+
puts Supercop::Actions::ConfigCopier.new(destination: destination).call
|
33
|
+
end
|
34
|
+
|
35
|
+
def loader
|
36
|
+
Supercop::Actions::Loaders::Dependency.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def cleaner
|
40
|
+
Supercop::Actions::Clean
|
41
|
+
end
|
42
|
+
end
|
data/supercop.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'supercop/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'supercop'
|
8
|
+
spec.version = Supercop::VERSION
|
9
|
+
spec.authors = ['Artem Kuznetsov']
|
10
|
+
spec.email = ['artemasmith@gmailcom']
|
11
|
+
|
12
|
+
spec.summary = %q{Utility for get easy and simple code quality report
|
13
|
+
based on different linters, like rubocop or reek}
|
14
|
+
spec.description = %q{This gem allows you to use multiply lnters to check
|
15
|
+
your code quality and get nice table-view report}
|
16
|
+
spec.homepage = 'http://github.com/artemasmith/supercop'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
21
|
+
end
|
22
|
+
spec.bindir = 'exe'
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ['lib']
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '>= 1.13'
|
27
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
28
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
29
|
+
spec.add_development_dependency 'rspec-its'
|
30
|
+
spec.add_development_dependency 'pry'
|
31
|
+
spec.add_development_dependency 'fakefs'
|
32
|
+
spec.add_development_dependency 'activesupport'
|
33
|
+
spec.add_development_dependency 'json'
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: supercop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Artem Kuznetsov
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: fakefs
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activesupport
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: json
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: |-
|
126
|
+
This gem allows you to use multiply lnters to check
|
127
|
+
your code quality and get nice table-view report
|
128
|
+
email:
|
129
|
+
- artemasmith@gmailcom
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- ".gitignore"
|
135
|
+
- ".rspec"
|
136
|
+
- ".travis.yml"
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- lib/supercop.rb
|
144
|
+
- lib/supercop/actions/clean.rb
|
145
|
+
- lib/supercop/actions/config_copier.rb
|
146
|
+
- lib/supercop/actions/file_injector.rb
|
147
|
+
- lib/supercop/actions/loaders/base.rb
|
148
|
+
- lib/supercop/actions/loaders/dependency.rb
|
149
|
+
- lib/supercop/checker.rb
|
150
|
+
- lib/supercop/configuration.rb
|
151
|
+
- lib/supercop/cop.rb
|
152
|
+
- lib/supercop/generators/config_generator.rb
|
153
|
+
- lib/supercop/parsers/base.rb
|
154
|
+
- lib/supercop/parsers/proxy.rb
|
155
|
+
- lib/supercop/parsers/rubocop.rb
|
156
|
+
- lib/supercop/parsers/scss_lint.rb
|
157
|
+
- lib/supercop/railtie.rb
|
158
|
+
- lib/supercop/table_formatter.rb
|
159
|
+
- lib/supercop/templates/supercop.yml
|
160
|
+
- lib/supercop/version.rb
|
161
|
+
- lib/tasks/check.rake
|
162
|
+
- lib/tasks/manage_settings.rake
|
163
|
+
- supercop.gemspec
|
164
|
+
homepage: http://github.com/artemasmith/supercop
|
165
|
+
licenses:
|
166
|
+
- MIT
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project:
|
184
|
+
rubygems_version: 2.5.2
|
185
|
+
signing_key:
|
186
|
+
specification_version: 4
|
187
|
+
summary: Utility for get easy and simple code quality report based on different linters,
|
188
|
+
like rubocop or reek
|
189
|
+
test_files: []
|