koality 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +128 -0
- data/Rakefile +6 -0
- data/koality.gemspec +28 -0
- data/lib/koality.rb +43 -0
- data/lib/koality/options.rb +120 -0
- data/lib/koality/rake_task.rb +25 -0
- data/lib/koality/reporter/base.rb +39 -0
- data/lib/koality/reporter/cane.rb +64 -0
- data/lib/koality/reporter/rails_best_practices.rb +44 -0
- data/lib/koality/runner/cane.rb +78 -0
- data/lib/koality/runner/rails_best_practices.rb +44 -0
- data/lib/koality/simplecov.rb +2 -0
- data/lib/koality/simplecov/formatter.rb +21 -0
- data/lib/koality/version.rb +3 -0
- data/spec/koality/options_spec.rb +156 -0
- data/spec/koality/rake_task_spec.rb +25 -0
- data/spec/koality/runner/cane_spec.rb +139 -0
- data/spec/koality/runner/rails_best_practices_spec.rb +64 -0
- data/spec/koality/simplecov/formatter_spec.rb +36 -0
- data/spec/koality_spec.rb +85 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/with_constants.rb +43 -0
- metadata +190 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Jared Pace
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Koality
|
2
|
+
|
3
|
+
Runs opinionated code metric tools against your code as part of the test
|
4
|
+
suite. If the set level of desired quality is not met the build will
|
5
|
+
fail.
|
6
|
+
|
7
|
+
Beware of the drop bears.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'koality', :require => false
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install koality
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Add the following to your applications Rakefile. Place it after
|
26
|
+
`MyApp::Application.load_tasks` for Rails apps.
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'koality/rake_task'
|
30
|
+
|
31
|
+
Koality::RakeTask.new do |opts|
|
32
|
+
# configure options here
|
33
|
+
# See [koality_home]/lib/koality/options.rb for defaults
|
34
|
+
|
35
|
+
# opts.abc_threshold = 10
|
36
|
+
end
|
37
|
+
task :default => :koality
|
38
|
+
rescue LoadError
|
39
|
+
warn 'Could not load Koality, skipping Rake task.'
|
40
|
+
end
|
41
|
+
|
42
|
+
Running your test suite with Koality:
|
43
|
+
|
44
|
+
rake
|
45
|
+
|
46
|
+
Running koality on its own:
|
47
|
+
|
48
|
+
rake koality
|
49
|
+
|
50
|
+
|
51
|
+
## SimpleCov Integration (Optional)
|
52
|
+
|
53
|
+
Add the following to the top of your spec/spec_helper.rb file.
|
54
|
+
Must be before your require your application code.
|
55
|
+
|
56
|
+
require 'koality/simplecov'
|
57
|
+
SimpleCov.start
|
58
|
+
|
59
|
+
## Available options
|
60
|
+
|
61
|
+
All options are shown with their current defaults.
|
62
|
+
|
63
|
+
Koality::RakeTask.new do |opts|
|
64
|
+
opts.abc_file_pattern = '{app,lib}/**/*.rb'
|
65
|
+
opts.abc_threshold = 15
|
66
|
+
opts.abc_violations_threshold = 0
|
67
|
+
opts.abc_enabled = true
|
68
|
+
|
69
|
+
opts.style_file_pattern = '{app,lib,spec}/**/*.{rb,coffee,js}'
|
70
|
+
opts.style_line_length_threshold = 120
|
71
|
+
opts.style_violations_threshold = 0
|
72
|
+
opts.style_enabled = true
|
73
|
+
|
74
|
+
opts.doc_file_pattern = '{app,lib}/**/*.rb'
|
75
|
+
opts.doc_violations_threshold = 0
|
76
|
+
opts.doc_enabled = false
|
77
|
+
|
78
|
+
opts.code_coverage_threshold = 90
|
79
|
+
opts.code_coverage_file = 'code_coverage'
|
80
|
+
opts.code_coverage_enabled = true
|
81
|
+
|
82
|
+
opts.rails_bp_accept_patterns = []
|
83
|
+
opts.rails_bp_ignore_patterns = []
|
84
|
+
opts.rails_bp_errors_threshold = 0
|
85
|
+
opts.rails_bp_error_file = 'rails_best_practices_errors'
|
86
|
+
opts.rails_bp_enabled = true
|
87
|
+
|
88
|
+
opts.custom_thresholds = []
|
89
|
+
opts.total_violations_threshold = 0
|
90
|
+
opts.abort_on_failure = true
|
91
|
+
opts.output_directory = 'quality'
|
92
|
+
|
93
|
+
opts.colorize_output = true
|
94
|
+
end
|
95
|
+
|
96
|
+
## Configuring Rails Best Practices
|
97
|
+
|
98
|
+
Generate the config file (config/rails_best_practices.yml)
|
99
|
+
|
100
|
+
bundle exec rails_best_practices -g
|
101
|
+
|
102
|
+
Edit configuration or comment out lines to skip certain checks.
|
103
|
+
|
104
|
+
## Common Questions
|
105
|
+
|
106
|
+
* I don't want to the build to fail if I exceed any thresholds. How do I
|
107
|
+
turn that off?
|
108
|
+
|
109
|
+
opts.abort_on_failure = false
|
110
|
+
|
111
|
+
* I only want to fail the build if there are over 10 ABC errors. How do
|
112
|
+
I set that up?
|
113
|
+
|
114
|
+
opts.abc_violations_threshold = 10
|
115
|
+
opts.total_violations_threshold = -1
|
116
|
+
|
117
|
+
* How do I keep style violations from breaking the build?
|
118
|
+
|
119
|
+
opts.style_violations_threshold = -1
|
120
|
+
opts.total_violations_threshold = -1
|
121
|
+
|
122
|
+
## Contributing
|
123
|
+
|
124
|
+
1. Fork it
|
125
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
126
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
127
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
128
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/koality.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/koality/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jared Pace"]
|
6
|
+
gem.email = ["jared@thinkrelevance.com"]
|
7
|
+
gem.description = %q{Runs opinionated code quality tools as part of you test stuite}
|
8
|
+
gem.summary = %q{Runs opinionated code quality tools as part of you test stuite}
|
9
|
+
gem.homepage = "https://github.com/relevance/koality"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "koality"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Koality::VERSION
|
17
|
+
|
18
|
+
# Runtime Dependencies
|
19
|
+
gem.add_runtime_dependency 'rails_best_practices', ['~> 1.9']
|
20
|
+
gem.add_runtime_dependency 'simplecov', ['~> 0.6']
|
21
|
+
gem.add_runtime_dependency 'cane', ['~> 1.3']
|
22
|
+
gem.add_runtime_dependency 'terminal-table', ['~> 1.4']
|
23
|
+
gem.add_runtime_dependency 'term-ansicolor', ['~> 1.0']
|
24
|
+
|
25
|
+
# Developmnet Dependencies
|
26
|
+
gem.add_development_dependency 'rspec', ['~> 2.10']
|
27
|
+
gem.add_development_dependency 'mocha', ['~> 0.11']
|
28
|
+
end
|
data/lib/koality.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'koality/version'
|
2
|
+
require 'koality/options'
|
3
|
+
require 'koality/reporter/base'
|
4
|
+
require 'koality/reporter/cane'
|
5
|
+
require 'koality/reporter/rails_best_practices'
|
6
|
+
require 'koality/runner/cane'
|
7
|
+
require 'koality/runner/rails_best_practices'
|
8
|
+
|
9
|
+
module Koality
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def run
|
13
|
+
setup_environment
|
14
|
+
|
15
|
+
run_rails_bp if options.rails_bp_enabled?
|
16
|
+
|
17
|
+
success = run_cane
|
18
|
+
abort if options[:abort_on_failure] && !success
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_rails_bp
|
22
|
+
rails_bp = Koality::Runner::RailsBestPractices.new(options)
|
23
|
+
rails_bp.run
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_cane
|
27
|
+
cane = Koality::Runner::Cane.new(options)
|
28
|
+
cane.run
|
29
|
+
end
|
30
|
+
|
31
|
+
def options
|
32
|
+
@options ||= Koality::Options.new
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def setup_environment
|
38
|
+
options.ensure_output_directory_exists
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Koality
|
5
|
+
class Options
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
DEFAULTS = {
|
9
|
+
:abc_file_pattern => '{app,lib}/**/*.rb',
|
10
|
+
:abc_threshold => 15,
|
11
|
+
:abc_violations_threshold => 0,
|
12
|
+
:abc_enabled => true,
|
13
|
+
|
14
|
+
:style_file_pattern => '{app,lib,spec}/**/*.{rb,coffee,js}',
|
15
|
+
:style_line_length_threshold => 120,
|
16
|
+
:style_violations_threshold => 0,
|
17
|
+
:style_enabled => true,
|
18
|
+
|
19
|
+
:doc_file_pattern => '{app,lib}/**/*.rb',
|
20
|
+
:doc_violations_threshold => 0,
|
21
|
+
:doc_enabled => false,
|
22
|
+
|
23
|
+
:code_coverage_threshold => 90,
|
24
|
+
:code_coverage_file => 'code_coverage',
|
25
|
+
:code_coverage_enabled => true,
|
26
|
+
|
27
|
+
:rails_bp_accept_patterns => [],
|
28
|
+
:rails_bp_ignore_patterns => [],
|
29
|
+
:rails_bp_errors_threshold => 0,
|
30
|
+
:rails_bp_error_file => 'rails_best_practices_errors',
|
31
|
+
:rails_bp_enabled => true,
|
32
|
+
|
33
|
+
:custom_thresholds => [],
|
34
|
+
:total_violations_threshold => 0,
|
35
|
+
:abort_on_failure => true,
|
36
|
+
:output_directory => 'quality',
|
37
|
+
|
38
|
+
:colorize_output => true
|
39
|
+
}
|
40
|
+
|
41
|
+
attr_accessor :opts
|
42
|
+
|
43
|
+
def_delegators :@opts, :[], :[]=
|
44
|
+
|
45
|
+
def initialize(overrides = {})
|
46
|
+
self.opts = DEFAULTS.merge(overrides)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Add a threshold check. If the file exists and it contains a number,
|
50
|
+
# compare that number with the given value using the operator.
|
51
|
+
def add_threshold(file, operator, value)
|
52
|
+
custom_thresholds << [operator, file, value]
|
53
|
+
end
|
54
|
+
|
55
|
+
def thresholds
|
56
|
+
custom_thresholds + runner_thresholds
|
57
|
+
end
|
58
|
+
|
59
|
+
def runner_thresholds
|
60
|
+
runners = []
|
61
|
+
runners << rails_bp_custom_threshold if rails_bp_enabled?
|
62
|
+
runners << code_coverage_custom_threshold if code_coverage_enabled?
|
63
|
+
runners
|
64
|
+
end
|
65
|
+
|
66
|
+
def ensure_output_directory_exists
|
67
|
+
FileUtils.mkdir_p output_directory
|
68
|
+
end
|
69
|
+
|
70
|
+
def output_file(name)
|
71
|
+
File.join(output_directory, opts[name])
|
72
|
+
end
|
73
|
+
|
74
|
+
def rails_bp_enabled?
|
75
|
+
defined?(Rails) && rails_bp_enabled
|
76
|
+
end
|
77
|
+
|
78
|
+
def code_coverage_enabled?
|
79
|
+
code_coverage_enabled
|
80
|
+
end
|
81
|
+
|
82
|
+
def colorize_output?
|
83
|
+
colorize_output
|
84
|
+
end
|
85
|
+
|
86
|
+
def respond_to_missing?(method)
|
87
|
+
writer?(method) || reader?(method)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def method_missing(method, *args)
|
93
|
+
if opt = writer?(method)
|
94
|
+
opts[opt] = args.first
|
95
|
+
elsif opt = reader?(method)
|
96
|
+
opts[opt]
|
97
|
+
else
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def writer?(method)
|
103
|
+
/^(?<option>.+)=$/ =~ method.to_s
|
104
|
+
option && opts.key?(option.to_sym) && option.to_sym
|
105
|
+
end
|
106
|
+
|
107
|
+
def reader?(method)
|
108
|
+
opts.key?(method.to_sym) && method.to_sym
|
109
|
+
end
|
110
|
+
|
111
|
+
def rails_bp_custom_threshold
|
112
|
+
[:<=, output_file(:rails_bp_error_file), rails_bp_errors_threshold]
|
113
|
+
end
|
114
|
+
|
115
|
+
def code_coverage_custom_threshold
|
116
|
+
[:>=, output_file(:code_coverage_file), code_coverage_threshold]
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'koality'
|
4
|
+
|
5
|
+
module Koality
|
6
|
+
class RakeTask < ::Rake::TaskLib
|
7
|
+
|
8
|
+
def initialize(task_name = :koality)
|
9
|
+
yield Koality.options if block_given?
|
10
|
+
|
11
|
+
define_task task_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_task(task_name)
|
15
|
+
unless ::Rake.application.last_comment
|
16
|
+
desc %(Ensures various code metrics are met)
|
17
|
+
end
|
18
|
+
|
19
|
+
task task_name do
|
20
|
+
Koality.run
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
class String
|
6
|
+
include Term::ANSIColor
|
7
|
+
end
|
8
|
+
|
9
|
+
module Koality
|
10
|
+
module Reporter
|
11
|
+
class Base
|
12
|
+
|
13
|
+
def self.start(&block)
|
14
|
+
reporter = new
|
15
|
+
|
16
|
+
time = Benchmark.measure do
|
17
|
+
yield reporter
|
18
|
+
end
|
19
|
+
|
20
|
+
puts "-- #{'%0.3f' % time.real}s\n\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def color(message, color_name)
|
26
|
+
if Koality.options.colorize_output?
|
27
|
+
message.to_s.send(color_name)
|
28
|
+
else
|
29
|
+
message
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_table
|
34
|
+
Terminal::Table.new :style => {:width => 140, :padding_left => 2, :padding_right => 2}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|