koality 1.0.0
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.
- 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
|