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 ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ quality
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in koality.gemspec
4
+ gemspec
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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
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