miss_cleo 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 630dc170c4e5fa41d6b7065b750dc9f07616b1bf
4
- data.tar.gz: 3add2d4e3b0a222a3e1f0f9c4736829d6e42c39a
3
+ metadata.gz: ff4da2d11102916af50405184a3d1ee99179c42a
4
+ data.tar.gz: 678874911854e9a25391e862bf25fc0b421a487e
5
5
  SHA512:
6
- metadata.gz: 44af7a7fecb387a9cd5909beb63583889b3d64450de17f2718279c454875894eae901878a35f762aeeea5a0f4c300b0a32860076353a91abd1402cbb97090ca9
7
- data.tar.gz: 986641acb95593f84854d59c17b2873d4a98e15e320a74ebc047ddf80be0983a78b20e4fc20d93950fbcf738a7a6fea1b040d8200bcc2cdf14148a767a74289f
6
+ metadata.gz: 3f4c17cc829f5f124a563f06afcef8e85e962dd57e00edab71371afc2c8368f844ff6df4c1b831f3b400758b493a42a0b19098c8d2eafecc69be00c5774de8c7
7
+ data.tar.gz: 6248365c072bfeef740ad36401decad5942a9474909bbd7a8d37e624407da27b74060c801b7037e5a46f6df5e34a0ac31daf9e4af14594f54920e45e20da4dad
data/bin/miss_cleo CHANGED
@@ -1,18 +1,32 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "miss_cleo"
4
- include ::MissCleo::CoverageMapHelper
5
4
 
6
5
  case ARGV.first
7
6
  when "build_deck"
8
- build_deck(ARGV[1..-1])
7
+ files = ARGV[1..-1]
8
+ puts "Building your deck with #{files}"
9
+ coverage_map = ::MissCleo::CoverageMap.build(files)
10
+ puts "Saving map as zip file"
11
+ ::MissCleo::CoverageMapUtilities::SaveZip.zip(coverage_map)
9
12
  when "predict"
10
13
  unless ARGV[1]
11
14
  puts "Specify a coverage map."
12
15
  puts "e.g. 'miss_cleo predict map.json.gz"
13
16
  else
14
- map = File.open(ARGV[1]).read.gunzip
15
- predict(map)
17
+ raw_map = File.open(ARGV[1]).read.gunzip
18
+ map = ::MissCleo::CoverageMap.new(JSON.parse(raw_map))
19
+ lines_changed = ::MissCleo::DiffDetector.lines_changed
20
+ tests_to_run = ::MissCleo::TestSelector.predict(map, lines_changed)
21
+ if lines_changed.empty?
22
+ puts "No line changes detected."
23
+ elsif tests_to_run.empty?
24
+ puts "No tests found. May be due to blind spot, new tests you've just written, or the changes may be untested."
25
+ else
26
+ puts "Run these tests:"
27
+ puts tests_to_run.sort.reverse
28
+ ::MissCleo::TestRunner.new(tests_to_run, lines_changed).run_tests
29
+ end
16
30
  end
17
31
  else
18
32
  puts "Please run miss_cleo with 'build_deck' or 'predict'."
data/lib/miss_cleo.rb CHANGED
@@ -11,9 +11,13 @@ require 'miss_cleo/coverage_filter'
11
11
  require 'miss_cleo/coverage_map'
12
12
  require 'miss_cleo/test_configurations/cucumber_config'
13
13
  require 'miss_cleo/test_configurations/rspec_config'
14
- require 'miss_cleo/coverage_map_helper.rb'
15
14
  require 'miss_cleo/test_configurations/rails_action_view_config'
16
15
  require 'miss_cleo/template_tracker'
16
+ require 'miss_cleo/tests_to_files_map_logger'
17
+ require 'miss_cleo/coverage_map_utilities/save_zip'
18
+ require 'miss_cleo/test_selector'
19
+ require 'miss_cleo/diff_detector'
20
+ require 'miss_cleo/test_runner'
17
21
 
18
22
  module MissCleo
19
23
  end
@@ -1,17 +1,17 @@
1
1
  module MissCleo
2
- class CoverageFilter
2
+ module CoverageFilter
3
+ module_function
3
4
  GEM_PATHS = ENV["GEM_PATH"].split(":")
4
5
  RUBY_PATH = `which ruby`.chomp.gsub("/bin/ruby","")
5
6
 
6
- def self.filter_core(result_hash)
7
-
7
+ def filter_core(result_hash)
8
8
  # Don't include gems in coverage map
9
9
  result_hash.reject do |file, line|
10
10
  ([RUBY_PATH] + GEM_PATHS).any? { |path| file.include?(path) }
11
11
  end
12
12
  end
13
13
 
14
- def self.normalize_paths(result_hash)
14
+ def normalize_paths(result_hash)
15
15
  normalized_hash = Hash.new
16
16
  result_hash.each do |key, value|
17
17
  trimmed_key = key.gsub(/#{Regexp.quote(`pwd`.chomp)}\//, "")
@@ -21,11 +21,13 @@ module MissCleo
21
21
  normalized_hash
22
22
  end
23
23
 
24
- def self.filter_and_trim(result_hash)
24
+ def filter_and_trim(result_hash)
25
25
  filtered = filter_core(result_hash)
26
26
  normalize_paths(filtered)
27
27
  end
28
28
 
29
+ private_class_method :filter_core
30
+ private_class_method :normalize_paths
29
31
  end
30
32
 
31
33
  end
@@ -1,6 +1,23 @@
1
1
  module MissCleo
2
2
  class CoverageMap
3
3
 
4
+ def self.build(file_names)
5
+ cov_map = self.new
6
+ file_names.each do |file_name|
7
+ File.open(file_name, "r") do |f|
8
+ f.read
9
+ end.tap do |contents|
10
+ begin
11
+ cov_map.add_to_coverage_map(JSON.parse(contents))
12
+ rescue
13
+ puts "#{file_name} is malformed, this may affect test predictons"
14
+ end
15
+ end
16
+ end
17
+
18
+ cov_map
19
+ end
20
+
4
21
  attr_reader :map
5
22
 
6
23
  def initialize(map = nil)
@@ -0,0 +1,13 @@
1
+ module MissCleo
2
+ module CoverageMapUtilities
3
+ module SaveZip
4
+ module_function
5
+
6
+ def zip(coverage_map)
7
+ File.open("total_coverage_map.json.gz", "w") do |f|
8
+ f.write(JSON.dump(coverage_map.map).gzip)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ module MissCleo
2
+ module DiffDetector
3
+ module_function
4
+ def lines_changed
5
+ Set.new.tap do |changed_lines|
6
+ repo = Rugged::Repository.new '.'
7
+ repo.index.diff.each_patch do |patch|
8
+ file = patch.delta.old_file[:path]
9
+
10
+ patch.each_hunk do |hunk|
11
+ hunk.each_line do |line|
12
+ case line.line_origin
13
+ when :addition
14
+ changed_lines << [file, line.new_lineno] unless exclude_from_map?(file)
15
+ when :deletion
16
+ changed_lines << [file, line.old_lineno] unless exclude_from_map?(file)
17
+ when :context
18
+ # do nothing
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+
28
+ def exclude_from_map?(file_name)
29
+ # Let's add a configuration for ignored files
30
+ file_name == "db/structure.sql"
31
+ end
32
+
33
+ private_class_method :exclude_from_map?
34
+ end
35
+ end
@@ -2,27 +2,25 @@ module MissCleo
2
2
  module TestConfigurations
3
3
  class CucumberConfig
4
4
  CUCUMBER_MAP = "cucumber_map.json"
5
- LOGS = []
6
5
 
7
6
  def self.setup_hooks(context)
8
- if ENV["COVERAGE"]
9
- MissCleo::TemplateTracker.initialize_tracker
10
- ActionView::Template.prepend MissCleo::TestConfigurations::ActionViewConfig if defined? ActionView::Template
11
- Coverage.start
12
- context.Around do |scenario, execute|
13
- MissCleo::TemplateTracker.clear_templates
14
- before = Coverage.peek_result
15
- execute.call
16
- after = Coverage.peek_result
17
- templates = MissCleo::TemplateTracker.templates.uniq
18
- if file_and_line = scenario.try(:file_colon_line)
19
- LOGS << [ file_and_line, { before: CoverageFilter.filter_and_trim(before), after: CoverageFilter.filter_and_trim(after), templates: templates } ]
20
- end
7
+ map_logger = MissCleo::TestsToFilesMapLogger.new(CUCUMBER_MAP)
8
+ MissCleo::TemplateTracker.initialize_tracker
9
+ ActionView::Template.prepend MissCleo::TestConfigurations::ActionViewConfig if defined? ActionView::Template
10
+ Coverage.start
11
+ context.Around do |scenario, execute|
12
+ MissCleo::TemplateTracker.clear_templates
13
+ before = Coverage.peek_result
14
+ execute.call
15
+ after = Coverage.peek_result
16
+ templates = MissCleo::TemplateTracker.templates.uniq
17
+ if file_and_line = scenario.try(:file_colon_line)
18
+ map_logger.add_to_log(file_and_line, before, after, templates)
21
19
  end
20
+ end
22
21
 
23
- at_exit do
24
- File.open(CUCUMBER_MAP, 'w') { |f| f.write JSON.dump LOGS }
25
- end
22
+ at_exit do
23
+ map_logger.export_logs
26
24
  end
27
25
  end
28
26
  end
@@ -2,29 +2,23 @@ module MissCleo
2
2
  module TestConfigurations
3
3
  class RspecConfig
4
4
  RSPEC_MAP = "rspec_map.json"
5
- LOGS = []
6
5
 
7
- def self.setup_hooks(context)
8
- if ENV["COVERAGE"]
9
- MissCleo::TemplateTracker.initialize_tracker
10
- ActionView::Template.prepend MissCleo::TestConfigurations::ActionViewConfig if defined? ActionView::Template
11
- Coverage.start
12
- RSpec.configuration.after(:suite) do
13
- File.open(RSPEC_MAP, 'w') { |f| f.write JSON.dump LOGS }
14
- end
6
+ def self.setup_hooks
7
+ logger = MissCleo::TestsToFilesMapLogger.new(RSPEC_MAP)
8
+ MissCleo::TemplateTracker.initialize_tracker
9
+ ActionView::Template.prepend MissCleo::TestConfigurations::ActionViewConfig if defined? ActionView::Template
10
+ Coverage.start
11
+ RSpec.configuration.after(:suite) do
12
+ logger.export_logs
13
+ end
15
14
 
16
- RSpec.configuration.around(:example) do |example|
17
- MissCleo::TemplateTracker.clear_templates
18
- before = Coverage.peek_result
19
- example.call
20
- after = Coverage.peek_result
21
- templates = MissCleo::TemplateTracker.templates.uniq
22
- LOGS << [ example.location, {
23
- before: CoverageFilter.filter_and_trim(before),
24
- after: CoverageFilter.filter_and_trim(after),
25
- templates: templates
26
- } ]
27
- end
15
+ RSpec.configuration.around(:example) do |example|
16
+ MissCleo::TemplateTracker.clear_templates
17
+ before = Coverage.peek_result
18
+ example.call
19
+ after = Coverage.peek_result
20
+ templates = MissCleo::TemplateTracker.templates.uniq
21
+ logger.add_to_log(example.location, before, after, templates)
28
22
  end
29
23
  end
30
24
  end
@@ -0,0 +1,38 @@
1
+ module MissCleo
2
+ class TestRunner
3
+ def initialize(tests_to_run, lines_changed)
4
+ @tests_to_run = tests_to_run
5
+ @lines_changed = lines_changed
6
+ end
7
+
8
+ def run_tests
9
+ # come up with a better way to register tests and test execution
10
+ exec_command = "bundle exec"
11
+ cukes = tests_to_run.select { |test| test.match(/^feature/) }
12
+ specs = tests_to_run.select { |test| test.match(/^\.\/spec/) }
13
+ run_cukes = cukes.empty? ? "" : "#{exec_command} cucumber #{cukes.join(" ")}"
14
+ run_specs = specs.empty? ? "" : "#{exec_command} rspec #{specs.join(" ")}"
15
+ spec_line = specs.empty? ? nil : "(s)pecs"
16
+ cuke_line = cukes.empty? ? nil : "(c)ukes"
17
+ both_line = specs.empty? || cukes.empty? ? nil : "(B)oth cukes and specs"
18
+ puts "Run: " + [spec_line, cuke_line, both_line].compact.join(", ") + " or (n)othing:"
19
+ response = STDIN.gets.chomp
20
+ case response
21
+ when "s"
22
+ puts "Running only specs..."
23
+ exec run_specs
24
+ when "c"
25
+ puts "Running only cukes..."
26
+ exec run_cukes
27
+ when "n"
28
+ else
29
+ puts "Running both specs and cukes..."
30
+ exec [run_cukes, run_specs].join("; ")
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :tests_to_run, :lines_changed
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ module MissCleo
2
+ module TestSelector
3
+ module_function
4
+
5
+ def predict(coverage_map, lines_changed)
6
+ tests_to_run = []
7
+ lines_changed.each do |file, line|
8
+ tests_to_run |= coverage_map.tests_for_lines(file, line)
9
+ end
10
+
11
+ tests_to_run.sort.reverse
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module MissCleo
2
+ class TestsToFilesMapLogger
3
+
4
+ def initialize(file_name)
5
+ @logs = []
6
+ @file_name = file_name
7
+ end
8
+
9
+ def add_to_log(test_file_and_line, lines_run_before, lines_run_after, templates)
10
+ logs << [ test_file_and_line, {
11
+ before: filter(lines_run_before),
12
+ after: filter(lines_run_after),
13
+ templates: templates
14
+ }]
15
+ end
16
+
17
+ def export_logs
18
+ File.open(file_name, 'w') { |f| f.write JSON.dump logs }
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :logs
24
+ attr_reader :file_name
25
+
26
+ def filter(lines_run)
27
+ MissCleo::CoverageFilter.filter_and_trim(lines_run)
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module MissCleo
2
- VERSION = "0.4.5"
2
+ VERSION = "0.4.6"
3
3
  end
data/miss_cleo.gemspec CHANGED
@@ -17,10 +17,12 @@ Gem::Specification.new do |spec|
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
18
  spec.executables = ["miss_cleo"]
19
19
  spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = '>= 2.3.0'
20
21
 
21
- spec.add_development_dependency "bundler", "~> 1.7.6"
22
+ spec.add_development_dependency "bundler"
22
23
  spec.add_development_dependency "rake", "~> 10.5.0"
23
24
  spec.add_development_dependency "pry", "~> 0.9.12"
25
+ spec.add_development_dependency "rspec"
24
26
  spec.add_runtime_dependency "rugged", "~> 0.23.3"
25
27
  spec.add_runtime_dependency "gzip", "~> 1.0"
26
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miss_cleo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Hu
@@ -10,22 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-04-08 00:00:00.000000000 Z
13
+ date: 2016-04-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 1.7.6
21
+ version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - "~>"
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 1.7.6
28
+ version: '0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rake
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -54,6 +54,20 @@ dependencies:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
56
  version: 0.9.12
57
+ - !ruby/object:Gem::Dependency
58
+ name: rspec
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
57
71
  - !ruby/object:Gem::Dependency
58
72
  name: rugged
59
73
  requirement: !ruby/object:Gem::Requirement
@@ -105,11 +119,15 @@ files:
105
119
  - lib/miss_cleo.rb
106
120
  - lib/miss_cleo/coverage_filter.rb
107
121
  - lib/miss_cleo/coverage_map.rb
108
- - lib/miss_cleo/coverage_map_helper.rb
122
+ - lib/miss_cleo/coverage_map_utilities/save_zip.rb
123
+ - lib/miss_cleo/diff_detector.rb
109
124
  - lib/miss_cleo/template_tracker.rb
110
125
  - lib/miss_cleo/test_configurations/cucumber_config.rb
111
126
  - lib/miss_cleo/test_configurations/rails_action_view_config.rb
112
127
  - lib/miss_cleo/test_configurations/rspec_config.rb
128
+ - lib/miss_cleo/test_runner.rb
129
+ - lib/miss_cleo/test_selector.rb
130
+ - lib/miss_cleo/tests_to_files_map_logger.rb
113
131
  - lib/miss_cleo/version.rb
114
132
  - miss_cleo.gemspec
115
133
  homepage: http://github.com/gust/miss_cleo
@@ -124,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
124
142
  requirements:
125
143
  - - ">="
126
144
  - !ruby/object:Gem::Version
127
- version: '0'
145
+ version: 2.3.0
128
146
  required_rubygems_version: !ruby/object:Gem::Requirement
129
147
  requirements:
130
148
  - - ">="
@@ -132,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
150
  version: '0'
133
151
  requirements: []
134
152
  rubyforge_project:
135
- rubygems_version: 2.4.3
153
+ rubygems_version: 2.5.1
136
154
  signing_key:
137
155
  specification_version: 4
138
156
  summary: Regression Test Selection
@@ -1,73 +0,0 @@
1
- module MissCleo
2
- module CoverageMapHelper
3
-
4
- def build_deck(file_names)
5
- cov_map = ::MissCleo::CoverageMap.new
6
- file_names.each do |file_name|
7
- File.open(file_name, "r") do |f|
8
- f.read
9
- end.tap do |contents|
10
- begin
11
- cov_map.add_to_coverage_map(JSON.parse(contents))
12
- rescue
13
- puts "#{file_name} is malformed, this may affect test predictons"
14
- end
15
- end
16
- end
17
-
18
- File.open("total_coverage_map.json.gz", "w") do |f|
19
- f.write(JSON.dump(cov_map.map).gzip)
20
- end
21
- end
22
-
23
- def predict(unzipped_file)
24
- coverage_map = ::MissCleo::CoverageMap.new(JSON.parse(unzipped_file))
25
- tests_to_run = []
26
- lines_changed.each do |file, line|
27
- tests_to_run |= coverage_map.tests_for_lines(file, line)
28
- end
29
- if lines_changed.empty?
30
- puts "No line changes detected."
31
- elsif tests_to_run.empty?
32
- puts "No tests found. May be due to blind spot, new tests you've just written, or the changes may be untested."
33
- else
34
- puts "Run these tests:"
35
- puts tests_to_run.sort.reverse
36
- end
37
-
38
- tests_to_run
39
- end
40
-
41
-
42
- private
43
-
44
- def exclude_from_map?(file_name)
45
- # Let's add a configuration for ignored files
46
- file_name == "db/structure.sql"
47
- end
48
-
49
-
50
- def lines_changed
51
- @_lines_changed ||= Set.new.tap do |changed_lines|
52
- repo = Rugged::Repository.new '.'
53
- repo.index.diff.each_patch do |patch|
54
- file = patch.delta.old_file[:path]
55
-
56
- patch.each_hunk do |hunk|
57
- hunk.each_line do |line|
58
- case line.line_origin
59
- when :addition
60
- changed_lines << [file, line.new_lineno] unless exclude_from_map?(file)
61
- when :deletion
62
- changed_lines << [file, line.old_lineno] unless exclude_from_map?(file)
63
- when :context
64
- # do nothing
65
- end
66
- end
67
- end
68
- end
69
-
70
- end
71
- end
72
- end
73
- end