ai_refactor 0.3.1 → 0.5.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -2
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +169 -1
  5. data/README.md +169 -43
  6. data/Rakefile +1 -1
  7. data/ai_refactor.gemspec +1 -0
  8. data/examples/.gitignore +1 -0
  9. data/examples/ex1_convert_a_rspec_test_to_minitest.yml +7 -0
  10. data/examples/ex1_input_spec.rb +32 -0
  11. data/examples/rails_helper.rb +21 -0
  12. data/examples/test_helper.rb +14 -0
  13. data/exe/ai_refactor +139 -52
  14. data/lib/ai_refactor/cli.rb +138 -0
  15. data/lib/ai_refactor/command_file_parser.rb +27 -0
  16. data/lib/ai_refactor/context.rb +33 -0
  17. data/lib/ai_refactor/file_processor.rb +34 -17
  18. data/lib/ai_refactor/prompt.rb +84 -0
  19. data/lib/ai_refactor/prompts/diff.md +17 -0
  20. data/lib/ai_refactor/prompts/input.md +1 -0
  21. data/lib/ai_refactor/refactors/base_refactor.rb +183 -0
  22. data/lib/ai_refactor/refactors/custom.rb +43 -0
  23. data/lib/ai_refactor/refactors/minitest/write_test_for_class.md +15 -0
  24. data/lib/ai_refactor/refactors/minitest/write_test_for_class.rb +51 -0
  25. data/lib/ai_refactor/refactors/project/write_changelog_from_history.md +35 -0
  26. data/lib/ai_refactor/refactors/project/write_changelog_from_history.rb +50 -0
  27. data/lib/ai_refactor/refactors/{prompts/rspec_to_minitest_rails.md → rails/minitest/rspec_to_minitest.md} +40 -1
  28. data/lib/ai_refactor/refactors/rails/minitest/rspec_to_minitest.rb +77 -0
  29. data/lib/ai_refactor/refactors/rspec/minitest_to_rspec.rb +13 -0
  30. data/lib/ai_refactor/refactors/ruby/refactor_ruby.md +10 -0
  31. data/lib/ai_refactor/refactors/ruby/refactor_ruby.rb +29 -0
  32. data/lib/ai_refactor/refactors/ruby/write_ruby.md +7 -0
  33. data/lib/ai_refactor/refactors/ruby/write_ruby.rb +33 -0
  34. data/lib/ai_refactor/refactors.rb +13 -5
  35. data/lib/ai_refactor/run_configuration.rb +115 -0
  36. data/lib/ai_refactor/{refactors/tests → test_runners}/minitest_runner.rb +2 -2
  37. data/lib/ai_refactor/{refactors/tests → test_runners}/rspec_runner.rb +1 -1
  38. data/lib/ai_refactor/{refactors/tests → test_runners}/test_run_diff_report.rb +1 -1
  39. data/lib/ai_refactor/{refactors/tests → test_runners}/test_run_result.rb +1 -1
  40. data/lib/ai_refactor/version.rb +1 -1
  41. data/lib/ai_refactor.rb +13 -8
  42. metadata +47 -13
  43. data/lib/ai_refactor/base_refactor.rb +0 -66
  44. data/lib/ai_refactor/refactors/generic.rb +0 -113
  45. data/lib/ai_refactor/refactors/minitest_to_rspec.rb +0 -11
  46. data/lib/ai_refactor/refactors/rspec_to_minitest_rails.rb +0 -103
  47. /data/lib/ai_refactor/refactors/{prompts → rspec}/minitest_to_rspec.md +0 -0
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AIRefactor
4
+ class RunConfiguration
5
+ def self.add_new_option(key)
6
+ self.class.define_method(key) { instance_variable_get("@#{key}") }
7
+ self.class.define_method("#{key}=") { |v| instance_variable_set("@#{key}", v) }
8
+ end
9
+
10
+ attr_reader :refactor,
11
+ :input_file_paths,
12
+ :output_file_path,
13
+ :output_template_path,
14
+ :context_file_paths,
15
+ :context_text,
16
+ :review_prompt,
17
+ :prompt,
18
+ :prompt_file_path,
19
+ :ai_max_attempts,
20
+ :ai_model,
21
+ :ai_temperature,
22
+ :ai_max_tokens,
23
+ :ai_timeout,
24
+ :overwrite,
25
+ :diff,
26
+ :verbose,
27
+ :debug
28
+
29
+ def set!(hash)
30
+ hash.each do |key, value|
31
+ raise StandardError, "Invalid option: #{key}" unless respond_to?("#{key}=")
32
+ send("#{key}=", value)
33
+ end
34
+ end
35
+
36
+ attr_writer :refactor
37
+
38
+ # @deprecated
39
+ def [](key)
40
+ send(key)
41
+ end
42
+
43
+ def input_file_paths=(paths)
44
+ @input_file_paths ||= []
45
+ paths = [paths] unless paths.is_a?(Array)
46
+ @input_file_paths.concat(paths)
47
+ end
48
+
49
+ attr_writer :output_file_path
50
+
51
+ attr_writer :output_template_path
52
+
53
+ def context_file_paths=(paths)
54
+ @context_file_paths ||= []
55
+ paths = [paths] unless paths.is_a?(Array)
56
+ @context_file_paths.concat(paths)
57
+ end
58
+
59
+ def context_text=(text)
60
+ @context_text ||= ""
61
+ @context_text += text
62
+ end
63
+
64
+ attr_writer :review_prompt
65
+ attr_writer :prompt
66
+ attr_writer :prompt_file_path
67
+
68
+ def rspec_run_command
69
+ @rspec_run_command || "bundle exec rspec __FILE__"
70
+ end
71
+
72
+ def minitest_run_command
73
+ @minitest_run_command || "ruby __FILE__"
74
+ end
75
+
76
+ attr_writer :rspec_run_command
77
+ attr_writer :minitest_run_command
78
+
79
+ def ai_max_attempts=(value)
80
+ @ai_max_attempts = value || 3
81
+ end
82
+
83
+ def ai_model=(value)
84
+ @ai_model = value || "gpt-4"
85
+ end
86
+
87
+ def ai_temperature=(value)
88
+ @ai_temperature = value || 0.7
89
+ end
90
+
91
+ def ai_max_tokens=(value)
92
+ @ai_max_tokens = value || 1500
93
+ end
94
+
95
+ def ai_timeout=(value)
96
+ @ai_timeout = value || 60
97
+ end
98
+
99
+ def overwrite=(value)
100
+ @overwrite = value || "a"
101
+ end
102
+
103
+ attr_writer :diff
104
+
105
+ attr_writer :verbose
106
+
107
+ attr_writer :debug
108
+
109
+ def to_options
110
+ instance_variables.each_with_object({}) do |var, hash|
111
+ hash[var.to_s.delete("@").to_sym] = instance_variable_get(var)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -3,9 +3,9 @@
3
3
  require "open3"
4
4
 
5
5
  module AIRefactor
6
- module Tests
6
+ module TestRunners
7
7
  class MinitestRunner
8
- def initialize(file_path, command_template: "bundle exec rails test __FILE__")
8
+ def initialize(file_path, command_template: "ruby __FILE__")
9
9
  @file_path = file_path
10
10
  @command_template = command_template
11
11
  end
@@ -3,7 +3,7 @@
3
3
  require "open3"
4
4
 
5
5
  module AIRefactor
6
- module Tests
6
+ module TestRunners
7
7
  class RSpecRunner
8
8
  def initialize(file_path, command_template: "bundle exec rspec __FILE__")
9
9
  @file_path = file_path
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AIRefactor
4
- module Tests
4
+ module TestRunners
5
5
  class TestRunDiffReport
6
6
  def initialize(previous_test_run_result, test_run_result)
7
7
  @current = test_run_result
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AIRefactor
4
- module Tests
4
+ module TestRunners
5
5
  class TestRunResult
6
6
  attr_reader :stdout, :stderr, :example_count, :failure_count, :pending_count
7
7
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AIRefactor
4
- VERSION = "0.3.1"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/ai_refactor.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "ai_refactor/version"
3
+ require "zeitwerk"
4
+ loader = Zeitwerk::Loader.for_gem
5
+ loader.inflector.inflect(
6
+ "ai_refactor" => "AIRefactor",
7
+ "rspec_runner" => "RSpecRunner"
8
+ )
9
+ loader.setup # ready!
4
10
 
5
- require_relative "ai_refactor/logger"
6
- require_relative "ai_refactor/file_processor"
11
+ module AIRefactor
12
+ class NoOutputError < StandardError; end
13
+ # Your code goes here...
14
+ end
7
15
 
8
- require_relative "ai_refactor/refactors"
9
- require_relative "ai_refactor/base_refactor"
10
- require_relative "ai_refactor/refactors/generic"
11
- require_relative "ai_refactor/refactors/rspec_to_minitest_rails"
12
- require_relative "ai_refactor/refactors/minitest_to_rspec"
16
+ # We eager load here to ensure that all Refactor classes are loaded at startup so they can be registered
17
+ loader.eager_load
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai_refactor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-25 00:00:00.000000000 Z
11
+ date: 2023-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '5.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: zeitwerk
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.6'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.6'
61
75
  description: Use OpenAI's ChatGPT to automate converting Rails RSpec tests to minitest
62
76
  (ActiveSupport::TestCase).
63
77
  email:
@@ -75,21 +89,41 @@ files:
75
89
  - README.md
76
90
  - Rakefile
77
91
  - ai_refactor.gemspec
92
+ - examples/.gitignore
93
+ - examples/ex1_convert_a_rspec_test_to_minitest.yml
94
+ - examples/ex1_input_spec.rb
95
+ - examples/rails_helper.rb
96
+ - examples/test_helper.rb
78
97
  - exe/ai_refactor
79
98
  - lib/ai_refactor.rb
80
- - lib/ai_refactor/base_refactor.rb
99
+ - lib/ai_refactor/cli.rb
100
+ - lib/ai_refactor/command_file_parser.rb
101
+ - lib/ai_refactor/context.rb
81
102
  - lib/ai_refactor/file_processor.rb
82
103
  - lib/ai_refactor/logger.rb
104
+ - lib/ai_refactor/prompt.rb
105
+ - lib/ai_refactor/prompts/diff.md
106
+ - lib/ai_refactor/prompts/input.md
83
107
  - lib/ai_refactor/refactors.rb
84
- - lib/ai_refactor/refactors/generic.rb
85
- - lib/ai_refactor/refactors/minitest_to_rspec.rb
86
- - lib/ai_refactor/refactors/prompts/minitest_to_rspec.md
87
- - lib/ai_refactor/refactors/prompts/rspec_to_minitest_rails.md
88
- - lib/ai_refactor/refactors/rspec_to_minitest_rails.rb
89
- - lib/ai_refactor/refactors/tests/minitest_runner.rb
90
- - lib/ai_refactor/refactors/tests/rspec_runner.rb
91
- - lib/ai_refactor/refactors/tests/test_run_diff_report.rb
92
- - lib/ai_refactor/refactors/tests/test_run_result.rb
108
+ - lib/ai_refactor/refactors/base_refactor.rb
109
+ - lib/ai_refactor/refactors/custom.rb
110
+ - lib/ai_refactor/refactors/minitest/write_test_for_class.md
111
+ - lib/ai_refactor/refactors/minitest/write_test_for_class.rb
112
+ - lib/ai_refactor/refactors/project/write_changelog_from_history.md
113
+ - lib/ai_refactor/refactors/project/write_changelog_from_history.rb
114
+ - lib/ai_refactor/refactors/rails/minitest/rspec_to_minitest.md
115
+ - lib/ai_refactor/refactors/rails/minitest/rspec_to_minitest.rb
116
+ - lib/ai_refactor/refactors/rspec/minitest_to_rspec.md
117
+ - lib/ai_refactor/refactors/rspec/minitest_to_rspec.rb
118
+ - lib/ai_refactor/refactors/ruby/refactor_ruby.md
119
+ - lib/ai_refactor/refactors/ruby/refactor_ruby.rb
120
+ - lib/ai_refactor/refactors/ruby/write_ruby.md
121
+ - lib/ai_refactor/refactors/ruby/write_ruby.rb
122
+ - lib/ai_refactor/run_configuration.rb
123
+ - lib/ai_refactor/test_runners/minitest_runner.rb
124
+ - lib/ai_refactor/test_runners/rspec_runner.rb
125
+ - lib/ai_refactor/test_runners/test_run_diff_report.rb
126
+ - lib/ai_refactor/test_runners/test_run_result.rb
93
127
  - lib/ai_refactor/version.rb
94
128
  homepage: https://github.com/stevegeek/ai_refactor
95
129
  licenses:
@@ -112,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
146
  - !ruby/object:Gem::Version
113
147
  version: '0'
114
148
  requirements: []
115
- rubygems_version: 3.4.10
149
+ rubygems_version: 3.4.19
116
150
  signing_key:
117
151
  specification_version: 4
118
152
  summary: Use AI to convert a Rails RSpec test suite to minitest.
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AIRefactor
4
- class BaseRefactor
5
- attr_reader :input_file, :options, :logger
6
- attr_writer :failed_message
7
-
8
- def initialize(input_file, options, logger)
9
- @input_file = input_file
10
- @options = options
11
- @logger = logger
12
- end
13
-
14
- def run
15
- raise NotImplementedError
16
- end
17
-
18
- def failed_message
19
- @failed_message || "Reason not specified"
20
- end
21
-
22
- private
23
-
24
- def can_overwrite_output_file?(output_path)
25
- logger.info "Do you wish to overwrite #{output_path}? (y/n)"
26
- answer = $stdin.gets.chomp
27
- unless answer == "y" || answer == "Y"
28
- logger.warn "Skipping #{input_file}..."
29
- self.failed_message = "Skipped as output file already exists"
30
- return false
31
- end
32
- true
33
- end
34
-
35
- def prompt_file_path
36
- file = if options && options[:prompt_file_path]&.length&.positive?
37
- options[:prompt_file_path]
38
- else
39
- File.join(File.dirname(File.expand_path(__FILE__)), "refactors", "prompts", "#{refactor_name}.md")
40
- end
41
- file.tap do |prompt|
42
- raise "No prompt file '#{prompt}' found for #{refactor_name}" unless File.exist?(prompt)
43
- end
44
- end
45
-
46
- def ai_client
47
- @ai_client ||= OpenAI::Client.new
48
- end
49
-
50
- class << self
51
- def command_line_options
52
- []
53
- end
54
-
55
- def refactor_name
56
- name.split("::")
57
- .last
58
- .gsub(/::/, "/")
59
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
60
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
61
- .tr("-", "_")
62
- .downcase
63
- end
64
- end
65
- end
66
- end
@@ -1,113 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AIRefactor
4
- module Refactors
5
- class Generic < BaseRefactor
6
- def run
7
- logger.verbose "Generic refactor to #{input_file}... (using user supplied prompt #{prompt_file_path})"
8
- logger.verbose "Write output to #{output_file_path}..." if output_file_path
9
-
10
- processor = AIRefactor::FileProcessor.new(
11
- input_path: input_file,
12
- prompt_file_path: prompt_file_path,
13
- ai_client: ai_client,
14
- logger: logger,
15
- output_path: output_file_path
16
- )
17
-
18
- if processor.output_exists?
19
- return false unless can_overwrite_output_file?(output_file_path)
20
- end
21
-
22
- logger.verbose "Converting #{input_file}..."
23
-
24
- begin
25
- output_content, finished_reason, usage = processor.process!(options)
26
- rescue => e
27
- logger.error "Request to OpenAI failed: #{e.message}"
28
- logger.warn "Skipping #{input_file}..."
29
- self.failed_message = "Request to OpenAI failed"
30
- return false
31
- end
32
-
33
- logger.verbose "OpenAI finished, with reason '#{finished_reason}'..."
34
- logger.verbose "Used tokens: #{usage["total_tokens"]}".colorize(:light_black) if usage
35
-
36
- if finished_reason == "length"
37
- logger.warn "Translation may contain an incomplete output as the max token length was reached. You can try using the '--continue' option next time to increase the length of generated output."
38
- end
39
-
40
- if !output_content || output_content.length == 0
41
- logger.warn "Skipping #{input_file}, no translated output..."
42
- logger.error "Failed to translate #{input_file}, finished reason #{finished_reason}"
43
- self.failed_message = "AI conversion failed, no output was generated"
44
- return false
45
- end
46
-
47
- output_file_path ? true : output_content
48
- end
49
-
50
- private
51
-
52
- def output_file_path
53
- return output_file_path_from_template if output_template_path
54
-
55
- path = options[:output_file_path]
56
- return unless path
57
-
58
- if path == true
59
- input_file
60
- else
61
- path
62
- end
63
- end
64
-
65
- def output_template_path
66
- options[:output_template_path]
67
- end
68
-
69
- def output_file_path_from_template
70
- path = output_template_path.gsub("[FILE]", File.basename(input_file))
71
- .gsub("[NAME]", File.basename(input_file, ".*"))
72
- .gsub("[DIR]", File.dirname(input_file))
73
- .gsub("[REFACTOR]", self.class.refactor_name)
74
- .gsub("[EXT]", File.extname(input_file))
75
- raise "Output template could not be used" unless path.length.positive?
76
- path
77
- end
78
-
79
- def prompt_file_path
80
- specified_prompt_path = options[:prompt_file_path]
81
- if specified_prompt_path&.length&.positive?
82
- if File.exist?(specified_prompt_path)
83
- return specified_prompt_path
84
- else
85
- logger.error "No prompt file '#{specified_prompt_path}' found"
86
- end
87
- else
88
- logger.error "No prompt file was specified!"
89
- end
90
- exit 1
91
- end
92
-
93
- class << self
94
- def command_line_options
95
- [
96
- {
97
- key: :output_file_path,
98
- long: "--output [FILE]",
99
- type: String,
100
- help: "Write output to file instead of stdout. If no path provided will overwrite input file (will prompt to overwrite existing files)"
101
- },
102
- {
103
- key: :output_template_path,
104
- long: "--output-template TEMPLATE",
105
- type: String,
106
- help: "Write outputs to files instead of stdout. The template is used to create the output name, where the it can have substitutions, '[FILE]', '[NAME]', '[DIR]', '[REFACTOR]' & '[EXT]'. Eg `[DIR]/[NAME]_[REFACTOR][EXT]` (will prompt to overwrite existing files)"
107
- }
108
- ]
109
- end
110
- end
111
- end
112
- end
113
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AIRefactor
4
- module Refactors
5
- class MinitestToRspec < BaseRefactor
6
- def run
7
- raise "Not implemented"
8
- end
9
- end
10
- end
11
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "tests/test_run_result"
4
- require_relative "tests/rspec_runner"
5
- require_relative "tests/minitest_runner"
6
- require_relative "tests/test_run_diff_report"
7
-
8
- module AIRefactor
9
- module Refactors
10
- class RspecToMinitestRails < BaseRefactor
11
- def run
12
- spec_runner = AIRefactor::Tests::RSpecRunner.new(input_file)
13
- logger.verbose "Run spec #{input_file}... (#{spec_runner.command})"
14
-
15
- spec_run = spec_runner.run
16
-
17
- if spec_run.failed?
18
- logger.warn "Skipping #{input_file}..."
19
- logger.error "Failed to run #{input_file}, exited with status #{spec_run.exitstatus}. Stdout: #{spec_run.stdout}\n\nStderr: #{spec_run.stderr}\n\n"
20
- self.failed_message = "Failed to run RSpec file, has errors"
21
- return false
22
- end
23
-
24
- logger.debug "Original test run results:"
25
- logger.debug ">> Examples: #{spec_run.example_count}, Failures: #{spec_run.failure_count}, Pendings: #{spec_run.pending_count}"
26
-
27
- output_path = input_file.gsub("_spec.rb", "_test.rb").gsub("spec/", "test/")
28
-
29
- processor = AIRefactor::FileProcessor.new(
30
- input_path: input_file,
31
- output_path: output_path,
32
- prompt_file_path: prompt_file_path,
33
- ai_client: ai_client,
34
- logger: logger
35
- )
36
-
37
- if processor.output_exists?
38
- return false unless can_overwrite_output_file?(output_path)
39
- end
40
-
41
- logger.verbose "Converting #{input_file}..."
42
-
43
- begin
44
- output_content, finished_reason, usage = processor.process!(options) do |content|
45
- content.gsub("```", "")
46
- end
47
- rescue => e
48
- logger.error "Request to OpenAI failed: #{e.message}"
49
- logger.warn "Skipping #{input_file}..."
50
- self.failed_message = "Request to OpenAI failed"
51
- return false
52
- end
53
-
54
- logger.verbose "OpenAI finished, with reason '#{finished_reason}'..."
55
- logger.verbose "Used tokens: #{usage["total_tokens"]}".colorize(:light_black) if usage
56
-
57
- if finished_reason == "length"
58
- logger.warn "Translation may contain an incomplete output as the max token length was reached. You can try using the '--continue' option next time to increase the length of generated output."
59
- logger.warn "Continuing to test the translated file... but it is likely to fail."
60
- end
61
-
62
- if !output_content || output_content.length == 0
63
- logger.warn "Skipping #{input_file}, no translated output..."
64
- logger.error "Failed to translate #{input_file}, finished reason #{finished_reason}"
65
- self.failed_message = "AI conversion failed, no output was generated"
66
- return false
67
- end
68
-
69
- logger.verbose "Converted #{input_file} to #{output_path}..."
70
-
71
- minitest_runner = AIRefactor::Tests::MinitestRunner.new(processor.output_path)
72
-
73
- logger.verbose "Run generated test file #{output_path} (#{minitest_runner.command})..."
74
- test_run = minitest_runner.run
75
-
76
- if test_run.failed?
77
- logger.warn "Skipping #{input_file}..."
78
- logger.error "Failed to run translated #{output_path}, exited with status #{test_run.exitstatus}. Stdout: #{test_run.stdout}\n\nStderr: #{test_run.stderr}\n\n"
79
- logger.error "Conversion failed!", bold: true
80
- self.failed_message = "Generated test file failed to run correctly"
81
- return false
82
- end
83
-
84
- logger.debug "Translated test file results:"
85
- logger.debug ">> Runs: #{test_run.example_count}, Failures: #{test_run.failure_count}, Skips: #{test_run.pending_count}"
86
-
87
- report = AIRefactor::Tests::TestRunDiffReport.new(spec_run, test_run)
88
-
89
- if report.no_differences?
90
- logger.verbose "Done converting #{input_file} to #{output_path}..."
91
- logger.success "No differences found! Conversion worked!"
92
- true
93
- else
94
- logger.warn report.diff.colorize(:yellow)
95
- logger.verbose "Done converting #{input_file} to #{output_path}..."
96
- logger.error "Differences found! Conversion failed!", bold: true
97
- self.failed_message = "Generated test file run output did not match original RSpec spec run output"
98
- false
99
- end
100
- end
101
- end
102
- end
103
- end