devtools 0.1.0 → 0.1.26
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 +5 -5
- data/.circleci/config.yml +41 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1 -2
- data/Gemfile +9 -2
- data/README.md +3 -3
- data/config/devtools.yml +2 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/mutant.yml +6 -2
- data/config/reek.yml +105 -106
- data/config/rubocop.yml +37 -3
- data/devtools.gemspec +27 -25
- data/lib/devtools/config.rb +74 -66
- data/lib/devtools/flay.rb +98 -0
- data/lib/devtools/project/initializer/rake.rb +11 -7
- data/lib/devtools/project/initializer/rspec.rb +30 -55
- data/lib/devtools/project/initializer.rb +2 -12
- data/lib/devtools/project.rb +27 -105
- data/lib/devtools/rake/flay.rb +155 -0
- data/lib/devtools/spec_helper.rb +1 -3
- data/lib/devtools.rb +42 -89
- data/shared/spec/shared/abstract_type_behavior.rb +0 -2
- data/shared/spec/shared/command_method_behavior.rb +0 -2
- data/shared/spec/shared/each_method_behaviour.rb +0 -2
- data/shared/spec/shared/idempotent_method_behavior.rb +2 -3
- data/shared/spec/support/ice_nine_config.rb +0 -2
- data/spec/integration/devtools/rake/flay/verify_spec.rb +196 -0
- data/spec/spec_helper.rb +4 -11
- data/spec/unit/devtools/config/yardstick_spec.rb +17 -0
- data/spec/unit/devtools/config_spec.rb +78 -0
- data/spec/unit/devtools/flay/file_list/call_spec.rb +19 -0
- data/spec/unit/devtools/flay/scale/flay_report_spec.rb +17 -0
- data/spec/unit/devtools/flay/scale/measure_spec.rb +43 -0
- data/spec/unit/devtools/project/initializer/rake_spec.rb +21 -0
- data/spec/unit/devtools/project/initializer/rspec_spec.rb +52 -0
- data/spec/unit/devtools/project_spec.rb +34 -0
- data/spec/unit/devtools_spec.rb +14 -0
- data/tasks/metrics/ci.rake +3 -7
- data/tasks/metrics/coverage.rake +2 -2
- data/tasks/metrics/flay.rake +6 -33
- data/tasks/metrics/flog.rake +10 -7
- data/tasks/metrics/reek.rake +5 -4
- data/tasks/metrics/rubocop.rake +1 -3
- data/tasks/metrics/yardstick.rake +0 -14
- data/tasks/spec.rake +1 -3
- data/tasks/yard.rake +1 -3
- metadata +124 -65
- data/.ruby-gemset +0 -1
- data/.travis.yml +0 -15
- data/TODO +0 -0
- data/bin/devtools +0 -18
- data/circle.yml +0 -7
- data/default/config/devtools.yml +0 -2
- data/default/config/flay.yml +0 -3
- data/default/config/flog.yml +0 -2
- data/default/config/mutant.yml +0 -3
- data/default/config/reek.yml +0 -103
- data/default/config/rubocop.yml +0 -91
- data/default/config/yardstick.yml +0 -2
- data/lib/devtools/platform.rb +0 -118
- data/lib/devtools/site/initializer.rb +0 -57
- data/lib/devtools/site.rb +0 -41
- data/shared/spec/shared/hash_method_behavior.rb +0 -9
- data/tasks/metrics/mutant.rake +0 -50
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
describe Devtools::Flay::FileList, '.call' do
|
|
2
|
+
subject(:output) { described_class.call([tmpdir.to_s].freeze, [exclude]) }
|
|
3
|
+
|
|
4
|
+
let(:tmpdir) { Dir.mktmpdir }
|
|
5
|
+
let(:one) { Pathname(tmpdir).join('1.rb') }
|
|
6
|
+
let(:two) { Pathname(tmpdir).join('2.erb') }
|
|
7
|
+
let(:three) { Pathname(tmpdir).join('3.rb') }
|
|
8
|
+
let(:exclude) { Pathname(tmpdir).join('3*').to_s }
|
|
9
|
+
|
|
10
|
+
around(:each) do |example|
|
|
11
|
+
[one, two, three].map(&FileUtils.method(:touch))
|
|
12
|
+
|
|
13
|
+
example.run
|
|
14
|
+
|
|
15
|
+
FileUtils.rm_rf(tmpdir)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it { should eql(Set.new([one, two])) }
|
|
19
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
describe Devtools::Flay::Scale, '#flay_report' do
|
|
2
|
+
subject(:instance) { described_class.new(minimum_mass: 0, files: []) }
|
|
3
|
+
|
|
4
|
+
let(:flay) do
|
|
5
|
+
instance_double(::Flay, process: nil, analyze: nil, masses: {})
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
allow(::Flay).to receive(:new).with(mass: 0).and_return(flay)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
specify do
|
|
13
|
+
allow(flay).to receive(:report)
|
|
14
|
+
instance.flay_report
|
|
15
|
+
expect(flay).to have_received(:report)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
describe Devtools::Flay::Scale, '#measure' do
|
|
2
|
+
subject(:measure) { instance.measure }
|
|
3
|
+
|
|
4
|
+
let(:minimum_mass) { 0 }
|
|
5
|
+
let(:files) { [instance_double(File)] }
|
|
6
|
+
let(:flay_masses) { { 0 => 5, 1 => 10 } }
|
|
7
|
+
|
|
8
|
+
let(:instance) do
|
|
9
|
+
described_class.new(minimum_mass: minimum_mass, files: files)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:flay_hashes) do
|
|
13
|
+
{
|
|
14
|
+
0 => instance_double(Array, size: 3),
|
|
15
|
+
1 => instance_double(Array, size: 11)
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
let(:flay) do
|
|
20
|
+
instance_double(
|
|
21
|
+
::Flay,
|
|
22
|
+
analyze: nil,
|
|
23
|
+
masses: flay_masses,
|
|
24
|
+
hashes: flay_hashes
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
before do
|
|
29
|
+
allow(::Flay).to receive(:new).with(mass: minimum_mass).and_return(flay)
|
|
30
|
+
allow(flay).to receive(:process).with(*files)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it { should eql([Rational(5, 3), Rational(10, 11)]) }
|
|
34
|
+
|
|
35
|
+
context 'when minimum mass is not 0' do
|
|
36
|
+
let(:minimum_mass) { 1 }
|
|
37
|
+
|
|
38
|
+
specify do
|
|
39
|
+
measure
|
|
40
|
+
expect(::Flay).to have_received(:new).with(mass: 1)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
describe Devtools::Project::Initializer::Rake do
|
|
2
|
+
describe '.call' do
|
|
3
|
+
subject do
|
|
4
|
+
described_class.call
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
it 'performs expected rake initialization' do
|
|
8
|
+
path_a = instance_double(Pathname)
|
|
9
|
+
path_b = instance_double(Pathname)
|
|
10
|
+
|
|
11
|
+
expect(FileList).to receive(:glob)
|
|
12
|
+
.with(Devtools.root.join('tasks/**/*.rake').to_s)
|
|
13
|
+
.and_return([path_a, path_b])
|
|
14
|
+
|
|
15
|
+
expect(Rake.application).to receive(:add_import).with(path_a)
|
|
16
|
+
expect(Rake.application).to receive(:add_import).with(path_b)
|
|
17
|
+
|
|
18
|
+
expect(subject).to be(described_class)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
describe Devtools::Project::Initializer::Rspec do
|
|
2
|
+
let(:spec_root) { Devtools.root.join('spec') }
|
|
3
|
+
let(:unit_test_timeout) { instance_double(Float) }
|
|
4
|
+
|
|
5
|
+
let(:project) do
|
|
6
|
+
instance_double(
|
|
7
|
+
Devtools::Project,
|
|
8
|
+
spec_root: spec_root,
|
|
9
|
+
devtools: instance_double(
|
|
10
|
+
Devtools::Config::Devtools,
|
|
11
|
+
unit_test_timeout: unit_test_timeout
|
|
12
|
+
)
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '.call' do
|
|
17
|
+
subject do
|
|
18
|
+
described_class.call(project)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'performs expected rspec initialization' do
|
|
22
|
+
called = false
|
|
23
|
+
example = -> { called = true }
|
|
24
|
+
|
|
25
|
+
expect(Dir).to receive(:glob)
|
|
26
|
+
.with(Devtools.root.join('shared/spec/{shared,support}/**/*.rb'))
|
|
27
|
+
.and_return(%w[shared-a shared-b])
|
|
28
|
+
|
|
29
|
+
expect(Kernel).to receive(:require).with('shared-a')
|
|
30
|
+
expect(Kernel).to receive(:require).with('shared-b')
|
|
31
|
+
|
|
32
|
+
expect(Dir).to receive(:glob)
|
|
33
|
+
.with(Devtools.root.join('spec/{shared,support}/**/*.rb'))
|
|
34
|
+
.and_return(%w[support-a support-b])
|
|
35
|
+
|
|
36
|
+
expect(Kernel).to receive(:require).with('support-a')
|
|
37
|
+
expect(Kernel).to receive(:require).with('support-b')
|
|
38
|
+
|
|
39
|
+
expect(Timeout).to receive(:timeout).with(unit_test_timeout) do |&block|
|
|
40
|
+
block.call
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
expect(RSpec.configuration).to receive(:around)
|
|
44
|
+
.with(file_path: %r{\bspec/unit/})
|
|
45
|
+
.and_yield(example)
|
|
46
|
+
|
|
47
|
+
expect(subject).to be(described_class)
|
|
48
|
+
|
|
49
|
+
expect(called).to be(true)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
RSpec.describe Devtools::Project do
|
|
2
|
+
let(:object) { described_class.new(Devtools.root) }
|
|
3
|
+
|
|
4
|
+
describe '#init_rspec' do
|
|
5
|
+
subject { object.init_rspec }
|
|
6
|
+
|
|
7
|
+
it 'calls the rspec initializer' do
|
|
8
|
+
expect(Devtools::Project::Initializer::Rspec)
|
|
9
|
+
.to receive(:call).with(Devtools.project)
|
|
10
|
+
expect(subject).to be(object)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
devtools: Devtools::Config::Devtools,
|
|
16
|
+
flay: Devtools::Config::Flay,
|
|
17
|
+
flog: Devtools::Config::Flog,
|
|
18
|
+
reek: Devtools::Config::Reek,
|
|
19
|
+
rubocop: Devtools::Config::Rubocop,
|
|
20
|
+
yardstick: Devtools::Config::Yardstick
|
|
21
|
+
}.each do |name, klass|
|
|
22
|
+
describe "##{name}" do
|
|
23
|
+
subject { object.send(name) }
|
|
24
|
+
|
|
25
|
+
specify { should eql(klass.new(Devtools.root.join('config'))) }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#spec_root' do
|
|
30
|
+
subject { object.spec_root }
|
|
31
|
+
|
|
32
|
+
specify { should eql(Devtools.root.join('spec')) }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
describe Devtools do
|
|
2
|
+
describe '.project' do
|
|
3
|
+
specify do
|
|
4
|
+
expect(Devtools.project).to equal(Devtools::PROJECT)
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe '.init_rake_tasks' do
|
|
9
|
+
specify do
|
|
10
|
+
expect(Devtools::Project::Initializer::Rake).to receive(:call)
|
|
11
|
+
expect(Devtools.init_rake_tasks).to be(Devtools)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/tasks/metrics/ci.rake
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
desc 'Run all specs, metrics and mutant'
|
|
4
|
-
task ci: %w[spec ci:metrics metrics:mutant]
|
|
1
|
+
desc 'Run all specs and metrics'
|
|
2
|
+
task ci: %w[ci:metrics]
|
|
5
3
|
|
|
6
4
|
namespace :ci do
|
|
7
5
|
tasks = %w[
|
|
@@ -11,8 +9,6 @@ namespace :ci do
|
|
|
11
9
|
metrics:flog
|
|
12
10
|
metrics:flay
|
|
13
11
|
metrics:reek
|
|
12
|
+
spec:integration
|
|
14
13
|
]
|
|
15
|
-
|
|
16
|
-
desc 'Run metrics (except mutant)'
|
|
17
|
-
task metrics: tasks
|
|
18
14
|
end
|
data/tasks/metrics/coverage.rake
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
namespace :metrics do
|
|
4
2
|
desc 'Measure code coverage'
|
|
5
3
|
task :coverage do
|
|
6
4
|
begin
|
|
5
|
+
# rubocop:disable Style/ParallelAssignment
|
|
7
6
|
original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
|
|
7
|
+
# rubocop:enable Style/ParallelAssignment
|
|
8
8
|
Rake::Task['spec:unit'].execute
|
|
9
9
|
ensure
|
|
10
10
|
ENV['COVERAGE'] = original
|
data/tasks/metrics/flay.rake
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
namespace :metrics do
|
|
4
2
|
require 'flay'
|
|
5
3
|
|
|
@@ -12,37 +10,12 @@ namespace :metrics do
|
|
|
12
10
|
task :flay do
|
|
13
11
|
threshold = config.threshold
|
|
14
12
|
total_score = config.total_score
|
|
15
|
-
files = Flay.expand_dirs_to_files(config.lib_dirs).sort
|
|
16
|
-
|
|
17
|
-
# Run flay first to ensure the max mass matches the threshold
|
|
18
|
-
flay = Flay.new(fuzzy: false, verbose: false, mass: 0)
|
|
19
|
-
flay.process(*files)
|
|
20
|
-
flay.analyze
|
|
21
|
-
|
|
22
|
-
masses = flay.masses.map do |hash, mass|
|
|
23
|
-
Rational(mass, flay.hashes[hash].size)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
max = (masses.max || 0).to_i
|
|
27
|
-
unless max >= threshold
|
|
28
|
-
Devtools.notify_metric_violation "Adjust flay threshold down to #{max}"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
total = masses.inject(:+).to_i
|
|
32
|
-
unless total == total_score
|
|
33
|
-
Devtools.notify_metric_violation "Flay total is now #{total}, but expected #{total_score}"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Run flay a second time with the threshold set
|
|
37
|
-
flay = Flay.new(fuzzy: false, verbose: false, mass: threshold.succ)
|
|
38
|
-
flay.process(*files)
|
|
39
|
-
flay.analyze
|
|
40
|
-
|
|
41
|
-
mass_size = flay.masses.size
|
|
42
13
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
14
|
+
Devtools::Rake::Flay.call(
|
|
15
|
+
threshold: threshold,
|
|
16
|
+
total_score: total_score,
|
|
17
|
+
lib_dirs: config.lib_dirs,
|
|
18
|
+
excludes: config.excludes
|
|
19
|
+
)
|
|
47
20
|
end
|
|
48
21
|
end
|
data/tasks/metrics/flog.rake
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# rubocop:disable Metrics/BlockLength
|
|
3
2
|
namespace :metrics do
|
|
4
3
|
require 'flog'
|
|
5
4
|
require 'flog_cli'
|
|
@@ -13,11 +12,13 @@ namespace :metrics do
|
|
|
13
12
|
task :flog do
|
|
14
13
|
threshold = config.threshold.to_f.round(1)
|
|
15
14
|
flog = Flog.new
|
|
16
|
-
flog.flog(*
|
|
15
|
+
flog.flog(*PathExpander.new(config.lib_dirs.dup, '**/*.rb').process)
|
|
17
16
|
|
|
18
|
-
totals = flog
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
totals = flog
|
|
18
|
+
.totals
|
|
19
|
+
.reject { |name, _score| name.end_with?('#none') }
|
|
20
|
+
.map { |name, score| [name, score.round(1)] }
|
|
21
|
+
.sort_by { |_name, score| score }
|
|
21
22
|
|
|
22
23
|
if totals.any?
|
|
23
24
|
max = totals.last[1]
|
|
@@ -26,7 +27,8 @@ namespace :metrics do
|
|
|
26
27
|
end
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
bad_methods = totals.select { |
|
|
30
|
+
bad_methods = totals.select { |_name, score| score > threshold }
|
|
31
|
+
|
|
30
32
|
if bad_methods.any?
|
|
31
33
|
bad_methods.reverse_each do |name, score|
|
|
32
34
|
printf "%8.1f: %s\n", score, name
|
|
@@ -38,3 +40,4 @@ namespace :metrics do
|
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
end
|
|
43
|
+
# rubocop:enable Metrics/BlockLength
|
data/tasks/metrics/reek.rake
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
namespace :metrics do
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
require 'reek/rake/task'
|
|
3
|
+
|
|
4
|
+
Reek::Rake::Task.new do |reek|
|
|
5
|
+
reek.source_files = '{app,lib}/**/*.rb'
|
|
6
|
+
reek.config_file = 'config/reek.yml'
|
|
6
7
|
end
|
|
7
8
|
end
|
data/tasks/metrics/rubocop.rake
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
namespace :metrics do
|
|
4
2
|
desc 'Check with code style guide'
|
|
5
3
|
task :rubocop do
|
|
6
4
|
require 'rubocop'
|
|
7
5
|
config = Devtools.project.rubocop
|
|
8
6
|
begin
|
|
9
|
-
exit_status = RuboCop::CLI.new.run(%W[--config #{config.config_file
|
|
7
|
+
exit_status = RuboCop::CLI.new.run(%W[--config #{config.config_file}])
|
|
10
8
|
fail 'Rubocop not successful' unless exit_status.zero?
|
|
11
9
|
rescue Encoding::CompatibilityError => exception
|
|
12
10
|
Devtools.notify_metric_violation exception.message
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
namespace :metrics do
|
|
4
2
|
namespace :yardstick do
|
|
5
3
|
require 'yardstick/rake/measurement'
|
|
6
4
|
require 'yardstick/rake/verify'
|
|
7
5
|
|
|
8
|
-
# Enable the legacy parser for JRuby until ripper is fully supported
|
|
9
|
-
if Devtools.jruby?
|
|
10
|
-
# Remove when https://github.com/lsegal/yard/issues/681 is resolved
|
|
11
|
-
# This code first requires ripper, then removes the constant so
|
|
12
|
-
# that it does not trigger a bug in YARD where if it checks if Ripper
|
|
13
|
-
# is available and assumes other constants are defined, when JRuby's
|
|
14
|
-
# implementation does not yet.
|
|
15
|
-
require 'ripper'
|
|
16
|
-
Object.send(:remove_const, :Ripper)
|
|
17
|
-
YARD::Parser::SourceParser.parser_type = :ruby18
|
|
18
|
-
end
|
|
19
|
-
|
|
20
6
|
options = Devtools.project.yardstick.options
|
|
21
7
|
|
|
22
8
|
Yardstick::Rake::Measurement.new(:measure, options)
|
data/tasks/spec.rake
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
begin
|
|
4
2
|
require 'rspec/core/rake_task'
|
|
5
3
|
|
|
@@ -28,7 +26,7 @@ begin
|
|
|
28
26
|
rescue LoadError
|
|
29
27
|
%w[spec spec:unit spec:integration].each do |name|
|
|
30
28
|
task name do
|
|
31
|
-
|
|
29
|
+
warn "In order to run #{name}, do: gem install rspec"
|
|
32
30
|
end
|
|
33
31
|
end
|
|
34
32
|
end
|
data/tasks/yard.rake
CHANGED