From 12ba5cc2205e5b9973f178dfe257f2a08c572e84 Mon Sep 17 00:00:00 2001
From: "yuuji.yaginuma" <yuuji.yaginuma@gmail.com>
Date: Sun, 26 Jan 2025 13:30:29 +0900
Subject: [PATCH] Add the option to skip retry

---
 README.md                   |  3 ++-
 lib/minitest/retry.rb       | 12 ++++++++++--
 test/minitest/retry_test.rb | 26 ++++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 066a3f2..382bdd5 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,8 @@ Minitest::Retry.use!(
   io: $stdout,             # Display destination of retry when the message. The default is stdout.
   exceptions_to_retry: [], # List of exceptions that will trigger a retry (when empty, all exceptions will).
   methods_to_retry:    [], # List of methods that will trigger a retry (when empty, all methods will).
-  classes_to_retry:    []  # List of classes that will trigger a retry (when empty, all classes will).
+  classes_to_retry:    [], # List of classes that will trigger a retry (when empty, all classes will).
+  methods_to_skip:     []  # List of methods that will skip a retry (when empty, all methods will retry).
 )
 ```
 
diff --git a/lib/minitest/retry.rb b/lib/minitest/retry.rb
index 9550c0a..8426bec 100644
--- a/lib/minitest/retry.rb
+++ b/lib/minitest/retry.rb
@@ -3,8 +3,8 @@
 module Minitest
   module Retry
     class << self
-      def use!(retry_count: 3, io: $stdout, verbose: true, exceptions_to_retry: [], methods_to_retry: [], classes_to_retry: [])
-        @retry_count, @io, @verbose, @exceptions_to_retry, @methods_to_retry, @classes_to_retry = retry_count, io, verbose, exceptions_to_retry, methods_to_retry, classes_to_retry
+      def use!(retry_count: 3, io: $stdout, verbose: true, exceptions_to_retry: [], methods_to_retry: [], classes_to_retry: [], methods_to_skip: [])
+        @retry_count, @io, @verbose, @exceptions_to_retry, @methods_to_retry, @classes_to_retry, @methods_to_skip = retry_count, io, verbose, exceptions_to_retry, methods_to_retry, classes_to_retry, methods_to_skip
         @failure_callback, @consistent_failure_callback, @retry_callback = nil, nil, nil
         Minitest.prepend(self)
       end
@@ -60,6 +60,10 @@ def retry_callback
         @retry_callback
       end
 
+      def methods_to_skip
+        @methods_to_skip
+      end
+
       def failure_to_retry?(failures = [], klass_method_name, klass)
         return false if failures.empty?
 
@@ -72,6 +76,10 @@ def failure_to_retry?(failures = [], klass_method_name, klass)
           return (errors & exceptions_to_retry).any?
         end
 
+        if methods_to_skip.any?
+          return !methods_to_skip.include?(klass_method_name)
+        end
+
         return true if classes_to_retry.empty?
         ancestors = klass.ancestors.map(&:to_s)
         return classes_to_retry.any? { |class_to_retry| ancestors.include?(class_to_retry) }
diff --git a/test/minitest/retry_test.rb b/test/minitest/retry_test.rb
index 9fe81d2..a6e769a 100644
--- a/test/minitest/retry_test.rb
+++ b/test/minitest/retry_test.rb
@@ -293,6 +293,32 @@ def another_fail
     end
   end
 
+  def test_retry_when_method_in_methods_to_skip
+    capture_stdout do
+      retry_test = Class.new(Minitest::Test) do
+        @@counter = 0
+
+        class << self
+          def name
+            'TestClass'
+          end
+        end
+
+        def self.counter
+          @@counter
+        end
+        Minitest::Retry.use! methods_to_skip: ["TestClass#fail"]
+        def fail
+          @@counter += 1
+          assert false, 'fail test'
+        end
+      end
+      Minitest::Runnable.run_one_method(retry_test, :fail, self.reporter)
+
+      assert_equal 1, retry_test.counter
+    end
+  end
+
   def test_run_failure_callback_on_failure
     on_failure_block_has_ran = false
     test_name, test_class, retry_test, result_in_callback = nil