ci-queue 0.22.1 → 0.24.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.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/dev.yml +1 -1
- data/{railgun.yml → isogun.yml} +0 -3
- data/lib/ci/queue/configuration.rb +15 -3
- data/lib/ci/queue/redis/base.rb +10 -0
- data/lib/ci/queue/redis/build_record.rb +2 -0
- data/lib/ci/queue/redis/grind_record.rb +2 -0
- data/lib/ci/queue/redis/supervisor.rb +19 -3
- data/lib/ci/queue/redis/test_time_record.rb +2 -0
- data/lib/ci/queue/redis/worker.rb +11 -0
- data/lib/ci/queue/version.rb +1 -1
- data/lib/minitest/queue/runner.rb +38 -1
- data/lib/rspec/queue.rb +9 -0
- metadata +4 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5f51b9eaf62e347a724e6e1fc533c26d504cca7922a4296b750ae2599c7cfa6e
         | 
| 4 | 
            +
              data.tar.gz: 0b9833d46d95e90d67663a2ff5bea2a8ad17c781b812a9f8b4ec7485bf0789d0
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b627008782774ad37ae5dbd5a2db0ae24df1f3fcda1dae9e0c0064f7c8df7890b926734855fd0f35d440e5e03d25441b6b9dc60c48bcaa19b8c5537c5d33c98b
         | 
| 7 | 
            +
              data.tar.gz: e3d1c41abfe02341deb545fda1e6eebb94826801ca104788d2aa48fab1886e6093acd402ef097f58c6b2bc4f403568386e45d1b8032f1323d4f7cfbf6f7f381b
         | 
    
        data/README.md
    CHANGED
    
    | @@ -70,3 +70,9 @@ rspec-queue --queue redis://example.com --timeout 600 --report | |
| 70 70 | 
             
            #### Limitations
         | 
| 71 71 |  | 
| 72 72 | 
             
            Because of how `ci-queue` executes the examples, `before(:all)` and `after(:all)` hooks are not supported. `rspec-queue` will explicitly reject them.
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            ## Custom Redis Expiry
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            `ci-queue` expects the Redis server to have an [eviction policy](https://redis.io/docs/manual/eviction/#eviction-policies) of `allkeys-lru`.
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            You can also use `--redis-ttl` to set a custom expiration time for all CI Queue keys, this defaults to 8 hours (28,800 seconds)
         | 
    
        data/dev.yml
    CHANGED
    
    
    
        data/{railgun.yml → isogun.yml}
    RENAMED
    
    
| @@ -5,10 +5,10 @@ module CI | |
| 5 5 | 
             
                  attr_accessor :timeout, :worker_id, :max_requeues, :grind_count, :failure_file
         | 
| 6 6 | 
             
                  attr_accessor :requeue_tolerance, :namespace, :failing_test, :statsd_endpoint
         | 
| 7 7 | 
             
                  attr_accessor :max_test_duration, :max_test_duration_percentile, :track_test_duration
         | 
| 8 | 
            -
                  attr_accessor :max_test_failed
         | 
| 8 | 
            +
                  attr_accessor :max_test_failed, :redis_ttl
         | 
| 9 9 | 
             
                  attr_reader :circuit_breakers
         | 
| 10 10 | 
             
                  attr_writer :seed, :build_id
         | 
| 11 | 
            -
                  attr_writer :queue_init_timeout
         | 
| 11 | 
            +
                  attr_writer :queue_init_timeout, :report_timeout, :inactive_workers_timeout
         | 
| 12 12 |  | 
| 13 13 | 
             
                  class << self
         | 
| 14 14 | 
             
                    def from_env(env)
         | 
| @@ -18,6 +18,7 @@ module CI | |
| 18 18 | 
             
                        seed: env['CIRCLE_SHA1'] || env['BUILDKITE_COMMIT'] || env['TRAVIS_COMMIT'] || env['HEROKU_TEST_RUN_COMMIT_VERSION'] || env['SEMAPHORE_GIT_SHA'],
         | 
| 19 19 | 
             
                        flaky_tests: load_flaky_tests(env['CI_QUEUE_FLAKY_TESTS']),
         | 
| 20 20 | 
             
                        statsd_endpoint: env['CI_QUEUE_STATSD_ADDR'],
         | 
| 21 | 
            +
                        redis_ttl: env['CI_QUEUE_REDIS_TTL']&.to_i ||  8 * 60 * 60,
         | 
| 21 22 | 
             
                      )
         | 
| 22 23 | 
             
                    end
         | 
| 23 24 |  | 
| @@ -34,7 +35,7 @@ module CI | |
| 34 35 | 
             
                    namespace: nil, seed: nil, flaky_tests: [], statsd_endpoint: nil, max_consecutive_failures: nil,
         | 
| 35 36 | 
             
                    grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
         | 
| 36 37 | 
             
                    max_test_duration_percentile: 0.5, track_test_duration: false, max_test_failed: nil,
         | 
| 37 | 
            -
                    queue_init_timeout: nil
         | 
| 38 | 
            +
                    queue_init_timeout: nil, redis_ttl: 8 * 60 * 60, report_timeout: nil, inactive_workers_timeout: nil
         | 
| 38 39 | 
             
                  )
         | 
| 39 40 | 
             
                    @build_id = build_id
         | 
| 40 41 | 
             
                    @circuit_breakers = [CircuitBreaker::Disabled]
         | 
| @@ -55,12 +56,23 @@ module CI | |
| 55 56 | 
             
                    @worker_id = worker_id
         | 
| 56 57 | 
             
                    self.max_consecutive_failures = max_consecutive_failures
         | 
| 57 58 | 
             
                    self.max_duration = max_duration
         | 
| 59 | 
            +
                    @redis_ttl = redis_ttl
         | 
| 60 | 
            +
                    @report_timeout = report_timeout
         | 
| 61 | 
            +
                    @inactive_workers_timeout = inactive_workers_timeout
         | 
| 58 62 | 
             
                  end
         | 
| 59 63 |  | 
| 60 64 | 
             
                  def queue_init_timeout
         | 
| 61 65 | 
             
                    @queue_init_timeout || timeout
         | 
| 62 66 | 
             
                  end
         | 
| 63 67 |  | 
| 68 | 
            +
                  def report_timeout
         | 
| 69 | 
            +
                    @report_timeout || timeout
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def inactive_workers_timeout
         | 
| 73 | 
            +
                    @inactive_workers_timeout || timeout
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 64 76 | 
             
                  def max_consecutive_failures=(max)
         | 
| 65 77 | 
             
                    if max
         | 
| 66 78 | 
             
                      @circuit_breakers << CircuitBreaker::MaxConsecutiveFailures.new(max_consecutive_failures: max)
         | 
    
        data/lib/ci/queue/redis/base.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ module CI | |
| 5 5 | 
             
                  class Base
         | 
| 6 6 | 
             
                    include Common
         | 
| 7 7 |  | 
| 8 | 
            +
                    TEN_MINUTES = 60 * 10
         | 
| 8 9 | 
             
                    CONNECTION_ERRORS = [
         | 
| 9 10 | 
             
                      ::Redis::BaseConnectionError,
         | 
| 10 11 | 
             
                      ::SocketError, # https://github.com/redis/redis-rb/pull/631
         | 
| @@ -20,6 +21,15 @@ module CI | |
| 20 21 | 
             
                      queue_initialized? && size == 0
         | 
| 21 22 | 
             
                    end
         | 
| 22 23 |  | 
| 24 | 
            +
                    def expired?
         | 
| 25 | 
            +
                      if (created_at = redis.get(key('master-created-at')))
         | 
| 26 | 
            +
                        (created_at.to_f + config.redis_ttl + TEN_MINUTES) < Time.now.to_f
         | 
| 27 | 
            +
                      else
         | 
| 28 | 
            +
                        # if there is no created at set anymore we assume queue is expired
         | 
| 29 | 
            +
                        true
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 23 33 | 
             
                    def size
         | 
| 24 34 | 
             
                      redis.multi do |transaction|
         | 
| 25 35 | 
             
                        transaction.llen(key('queue'))
         | 
| @@ -41,6 +41,7 @@ module CI | |
| 41 41 | 
             
                          id.dup.force_encoding(Encoding::BINARY),
         | 
| 42 42 | 
             
                          payload.dup.force_encoding(Encoding::BINARY),
         | 
| 43 43 | 
             
                        )
         | 
| 44 | 
            +
                        pipeline.expire(key('error-reports'), config.redis_ttl)
         | 
| 44 45 | 
             
                        record_stats(stats, pipeline: pipeline)
         | 
| 45 46 | 
             
                      end
         | 
| 46 47 | 
             
                      nil
         | 
| @@ -90,6 +91,7 @@ module CI | |
| 90 91 | 
             
                      return unless stats
         | 
| 91 92 | 
             
                      stats.each do |stat_name, stat_value|
         | 
| 92 93 | 
             
                        pipeline.hset(key(stat_name), config.worker_id, stat_value)
         | 
| 94 | 
            +
                        pipeline.expire(key(stat_name), config.redis_ttl)
         | 
| 93 95 | 
             
                      end
         | 
| 94 96 | 
             
                    end
         | 
| 95 97 |  | 
| @@ -16,6 +16,7 @@ module CI | |
| 16 16 | 
             
                          key('error-reports'),
         | 
| 17 17 | 
             
                          payload.force_encoding(Encoding::BINARY),
         | 
| 18 18 | 
             
                        )
         | 
| 19 | 
            +
                        pipeline.expire(key('error-reports'), config.redis_ttl)
         | 
| 19 20 | 
             
                        record_stats(stats, pipeline: pipeline)
         | 
| 20 21 | 
             
                      end
         | 
| 21 22 | 
             
                      nil
         | 
| @@ -58,6 +59,7 @@ module CI | |
| 58 59 | 
             
                      return unless stats
         | 
| 59 60 | 
             
                      stats.each do |stat_name, stat_value|
         | 
| 60 61 | 
             
                        pipeline.hset(key(stat_name), config.worker_id, stat_value)
         | 
| 62 | 
            +
                        pipeline.expire(key(stat_name), config.redis_ttl)
         | 
| 61 63 | 
             
                      end
         | 
| 62 64 | 
             
                    end
         | 
| 63 65 | 
             
                  end
         | 
| @@ -21,17 +21,33 @@ module CI | |
| 21 21 |  | 
| 22 22 | 
             
                      yield if block_given?
         | 
| 23 23 |  | 
| 24 | 
            -
                      time_left = config. | 
| 25 | 
            -
                       | 
| 26 | 
            -
             | 
| 24 | 
            +
                      time_left = config.report_timeout
         | 
| 25 | 
            +
                      time_left_with_no_workers = config.inactive_workers_timeout
         | 
| 26 | 
            +
                      until exhausted? || time_left <= 0 || max_test_failed? || time_left_with_no_workers <= 0
         | 
| 27 27 | 
             
                        time_left -= 1
         | 
| 28 | 
            +
                        sleep 1
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                        if active_workers?
         | 
| 31 | 
            +
                          time_left_with_no_workers = config.inactive_workers_timeout
         | 
| 32 | 
            +
                        else
         | 
| 33 | 
            +
                          time_left_with_no_workers -= 1
         | 
| 34 | 
            +
                        end
         | 
| 28 35 |  | 
| 29 36 | 
             
                        yield if block_given?
         | 
| 30 37 | 
             
                      end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      puts "Aborting, it seems all workers died." if time_left_with_no_workers <= 0
         | 
| 31 40 | 
             
                      exhausted?
         | 
| 32 41 | 
             
                    rescue CI::Queue::Redis::LostMaster
         | 
| 33 42 | 
             
                      false
         | 
| 34 43 | 
             
                    end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    private
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def active_workers?
         | 
| 48 | 
            +
                      # if there are running jobs we assume there are still agents active
         | 
| 49 | 
            +
                      redis.zrangebyscore(key('running'), Time.now.to_f - config.timeout, "+inf", limit: [0,1]).count > 0
         | 
| 50 | 
            +
                    end
         | 
| 35 51 | 
             
                  end
         | 
| 36 52 | 
             
                end
         | 
| 37 53 | 
             
              end
         | 
| @@ -24,6 +24,7 @@ module CI | |
| 24 24 | 
             
                          test_time_key(test_name),
         | 
| 25 25 | 
             
                          duration.to_s.force_encoding(Encoding::BINARY),
         | 
| 26 26 | 
             
                        )
         | 
| 27 | 
            +
                        pipeline.expire(test_time_key(test_name), config.redis_ttl)
         | 
| 27 28 | 
             
                      end
         | 
| 28 29 | 
             
                      nil
         | 
| 29 30 | 
             
                    end
         | 
| @@ -34,6 +35,7 @@ module CI | |
| 34 35 | 
             
                          all_test_names_key,
         | 
| 35 36 | 
             
                          test_name.dup.force_encoding(Encoding::BINARY),
         | 
| 36 37 | 
             
                        )
         | 
| 38 | 
            +
                        pipeline.expire(all_test_names_key, config.redis_ttl)
         | 
| 37 39 | 
             
                      end
         | 
| 38 40 | 
             
                      nil
         | 
| 39 41 | 
             
                    end
         | 
| @@ -53,6 +53,10 @@ module CI | |
| 53 53 | 
             
                          sleep 0.05
         | 
| 54 54 | 
             
                        end
         | 
| 55 55 | 
             
                      end
         | 
| 56 | 
            +
                      redis.pipelined do |pipeline|
         | 
| 57 | 
            +
                        pipeline.expire(key('worker', worker_id, 'queue'), config.redis_ttl)
         | 
| 58 | 
            +
                        pipeline.expire(key('processed'), config.redis_ttl)
         | 
| 59 | 
            +
                      end
         | 
| 56 60 | 
             
                    rescue *CONNECTION_ERRORS
         | 
| 57 61 | 
             
                    end
         | 
| 58 62 |  | 
| @@ -198,9 +202,16 @@ module CI | |
| 198 202 | 
             
                          transaction.lpush(key('queue'), tests) unless tests.empty?
         | 
| 199 203 | 
             
                          transaction.set(key('total'), @total)
         | 
| 200 204 | 
             
                          transaction.set(key('master-status'), 'ready')
         | 
| 205 | 
            +
                          transaction.set(key('master-created-at'), Time.now.to_f)
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                          transaction.expire(key('queue'), config.redis_ttl)
         | 
| 208 | 
            +
                          transaction.expire(key('total'), config.redis_ttl)
         | 
| 209 | 
            +
                          transaction.expire(key('master-status'), config.redis_ttl)
         | 
| 210 | 
            +
                          transaction.expire(key('master-created-at'), config.redis_ttl)
         | 
| 201 211 | 
             
                        end
         | 
| 202 212 | 
             
                      end
         | 
| 203 213 | 
             
                      register
         | 
| 214 | 
            +
                      redis.expire(key('workers'), config.redis_ttl)
         | 
| 204 215 | 
             
                    rescue *CONNECTION_ERRORS
         | 
| 205 216 | 
             
                      raise if @master
         | 
| 206 217 | 
             
                    end
         | 
    
        data/lib/ci/queue/version.rb
    CHANGED
    
    
| @@ -22,6 +22,9 @@ module Minitest | |
| 22 22 | 
             
                  def initialize(argv)
         | 
| 23 23 | 
             
                    @queue_config = CI::Queue::Configuration.from_env(ENV)
         | 
| 24 24 | 
             
                    @command, @argv = parse(argv)
         | 
| 25 | 
            +
                    if Minitest.respond_to?(:seed=)
         | 
| 26 | 
            +
                      Minitest.seed = @queue_config.seed.to_i
         | 
| 27 | 
            +
                    end
         | 
| 25 28 | 
             
                  end
         | 
| 26 29 |  | 
| 27 30 | 
             
                  def run!
         | 
| @@ -44,7 +47,10 @@ module Minitest | |
| 44 47 | 
             
                  end
         | 
| 45 48 |  | 
| 46 49 | 
             
                  def run_command
         | 
| 47 | 
            -
                    if queue.retrying?
         | 
| 50 | 
            +
                    if queue.retrying? || retry?
         | 
| 51 | 
            +
                      if queue.expired?
         | 
| 52 | 
            +
                        abort! "The test run is too old and can't be retried"
         | 
| 53 | 
            +
                      end
         | 
| 48 54 | 
             
                      reset_counters
         | 
| 49 55 | 
             
                      retry_queue = queue.retry_queue
         | 
| 50 56 | 
             
                      if retry_queue.exhausted?
         | 
| @@ -364,6 +370,24 @@ module Minitest | |
| 364 370 | 
             
                        queue_config.timeout = timeout
         | 
| 365 371 | 
             
                      end
         | 
| 366 372 |  | 
| 373 | 
            +
                      help = <<~EOS
         | 
| 374 | 
            +
                        Specify a timeout after which the report command will fail if not all tests have been processed.
         | 
| 375 | 
            +
                        Defaults to the value set for --timeout.
         | 
| 376 | 
            +
                      EOS
         | 
| 377 | 
            +
                      opts.separator ""
         | 
| 378 | 
            +
                      opts.on('--report-timeout TIMEOUT', Float, help) do |timeout|
         | 
| 379 | 
            +
                        queue_config.report_timeout = timeout
         | 
| 380 | 
            +
                      end
         | 
| 381 | 
            +
             | 
| 382 | 
            +
                      help = <<~EOS
         | 
| 383 | 
            +
                        Specify a timeout after the report will fail if all workers are inactive (e.g. died).
         | 
| 384 | 
            +
                        Defaults to the value set for --timeout.
         | 
| 385 | 
            +
                      EOS
         | 
| 386 | 
            +
                      opts.separator ""
         | 
| 387 | 
            +
                      opts.on('--inactive-workers-timeout TIMEOUT', Float, help) do |timeout|
         | 
| 388 | 
            +
                        queue_config.inactive_workers_timeout = timeout
         | 
| 389 | 
            +
                      end
         | 
| 390 | 
            +
             | 
| 367 391 | 
             
                      help = <<~EOS
         | 
| 368 392 | 
             
                        Specify a timeout to elect the leader and populate the queue.
         | 
| 369 393 | 
             
                        Defaults to the value set for --timeout.
         | 
| @@ -487,6 +511,14 @@ module Minitest | |
| 487 511 | 
             
                        end
         | 
| 488 512 | 
             
                      end
         | 
| 489 513 |  | 
| 514 | 
            +
                      help = <<~EOS
         | 
| 515 | 
            +
                        Defines how long the test report remain after the test run, in seconds.
         | 
| 516 | 
            +
                        Defaults to 28,800 (8 hours)
         | 
| 517 | 
            +
                      EOS
         | 
| 518 | 
            +
                      opts.on("--redis-ttl SECONDS", Integer, help) do |time|
         | 
| 519 | 
            +
                        queue.config.redis_ttl = time
         | 
| 520 | 
            +
                      end
         | 
| 521 | 
            +
             | 
| 490 522 | 
             
                      opts.separator ""
         | 
| 491 523 | 
             
                      opts.separator "    retry: Replays a previous run in the same order."
         | 
| 492 524 |  | 
| @@ -535,6 +567,11 @@ module Minitest | |
| 535 567 | 
             
                    puts red(message)
         | 
| 536 568 | 
             
                    exit! 1 # exit! is required to avoid minitest at_exit callback
         | 
| 537 569 | 
             
                  end
         | 
| 570 | 
            +
             | 
| 571 | 
            +
                  def retry?
         | 
| 572 | 
            +
                    ENV["BUILDKITE_RETRY_COUNT"].to_i > 0 ||
         | 
| 573 | 
            +
                      ENV["SEMAPHORE_PIPELINE_RERUN"] == "true"
         | 
| 574 | 
            +
                  end
         | 
| 538 575 | 
             
                end
         | 
| 539 576 | 
             
              end
         | 
| 540 577 | 
             
            end
         | 
    
        data/lib/rspec/queue.rb
    CHANGED
    
    | @@ -157,6 +157,15 @@ module RSpec | |
| 157 157 | 
             
                      queue_config.max_consecutive_failures = Integer(max)
         | 
| 158 158 | 
             
                    end
         | 
| 159 159 |  | 
| 160 | 
            +
                    help = <<~EOS
         | 
| 161 | 
            +
                      Defines how long the test report remain after the test run, in seconds.
         | 
| 162 | 
            +
                      Defaults to 28,800 (8 hours)
         | 
| 163 | 
            +
                    EOS
         | 
| 164 | 
            +
                    parser.separator ""
         | 
| 165 | 
            +
                    parser.on("--redis-ttl SECONDS", Integer, help) do |time|
         | 
| 166 | 
            +
                      queue.config.redis_ttl = time
         | 
| 167 | 
            +
                    end
         | 
| 168 | 
            +
             | 
| 160 169 | 
             
                    parser
         | 
| 161 170 | 
             
                  end
         | 
| 162 171 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ci-queue
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.24.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jean Boussier
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-07-20 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -171,6 +171,7 @@ files: | |
| 171 171 | 
             
            - dev.yml
         | 
| 172 172 | 
             
            - exe/minitest-queue
         | 
| 173 173 | 
             
            - exe/rspec-queue
         | 
| 174 | 
            +
            - isogun.yml
         | 
| 174 175 | 
             
            - lib/ci/queue.rb
         | 
| 175 176 | 
             
            - lib/ci/queue/bisect.rb
         | 
| 176 177 | 
             
            - lib/ci/queue/build_record.rb
         | 
| @@ -218,7 +219,6 @@ files: | |
| 218 219 | 
             
            - lib/rspec/queue.rb
         | 
| 219 220 | 
             
            - lib/rspec/queue/build_status_recorder.rb
         | 
| 220 221 | 
             
            - lib/rspec/queue/order_recorder.rb
         | 
| 221 | 
            -
            - railgun.yml
         | 
| 222 222 | 
             
            homepage: https://github.com/Shopify/ci-queue
         | 
| 223 223 | 
             
            licenses:
         | 
| 224 224 | 
             
            - MIT
         | 
| @@ -239,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 239 239 | 
             
                - !ruby/object:Gem::Version
         | 
| 240 240 | 
             
                  version: '0'
         | 
| 241 241 | 
             
            requirements: []
         | 
| 242 | 
            -
            rubygems_version: 3. | 
| 242 | 
            +
            rubygems_version: 3.3.3
         | 
| 243 243 | 
             
            signing_key: 
         | 
| 244 244 | 
             
            specification_version: 4
         | 
| 245 245 | 
             
            summary: Distribute tests over many workers using a queue
         |