From 87f307d658d7e63cccfe0c57de7d6ad09e0652ab Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 29 Jul 2025 14:11:39 +0200 Subject: [PATCH 01/29] feat: rof --- .circleci/config.yml | 38 +++-- lib/knapsack_pro.rb | 15 +- lib/knapsack_pro/adapters/rspec_adapter.rb | 2 +- lib/knapsack_pro/client/api/action.rb | 10 +- lib/knapsack_pro/client/api/v2/queues.rb | 50 ++++++ lib/knapsack_pro/config/ci/base.rb | 3 + lib/knapsack_pro/config/ci/circle.rb | 12 ++ lib/knapsack_pro/config/ci/github_actions.rb | 4 + lib/knapsack_pro/config/ci/gitlab_ci.rb | 10 ++ lib/knapsack_pro/config/env.rb | 11 ++ lib/knapsack_pro/formatters/time_tracker.rb | 31 ++-- .../formatters/time_tracker_fetcher.rb | 4 +- lib/knapsack_pro/queue_allocator.rb | 79 ++++++++-- lib/knapsack_pro/runners/queue/base_runner.rb | 3 +- .../runners/queue/rspec_runner.rb | 16 +- lib/knapsack_pro/urls.rb | 4 +- .../integration/runners/queue/rspec_runner.rb | 4 +- .../queue/rspec_runner_fallback_spec.rb | 1 + .../knapsack_pro/client/api/v2/queues_spec.rb | 143 ++++++++++++++++++ spec/knapsack_pro/config/ci/circle_spec.rb | 15 ++ .../config/ci/github_actions_spec.rb | 13 ++ spec/knapsack_pro/config/ci/gitlab_ci_spec.rb | 15 ++ spec/knapsack_pro/config/env_spec.rb | 54 +++++++ .../formatters/time_tracker_fetcher_spec.rb | 10 +- .../formatters/time_tracker_spec.rb | 51 ++++++- .../runners/queue/base_runner_spec.rb | 2 +- 26 files changed, 520 insertions(+), 80 deletions(-) create mode 100644 lib/knapsack_pro/client/api/v2/queues.rb create mode 100644 spec/knapsack_pro/client/api/v2/queues_spec.rb diff --git a/.circleci/config.yml b/.circleci/config.yml index 32deb36d..6f9714ee 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -213,6 +213,7 @@ jobs: RACK_ENV: test KNAPSACK_PRO_ENDPOINT: https://api-staging.knapsackpro.com KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: $KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC + KNAPSACK_PRO_LOG_LEVEL: debug EXTRA_TEST_FILES_DELAY: 10 - image: cimg/postgres:14.7 environment: @@ -239,26 +240,22 @@ jobs: - run: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue" + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue" bundle exec rake knapsack_pro:queue:rspec - run: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | - # run 0 tests as queue is consumed || - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=false - bundle exec rake knapsack_pro:queue:rspec - - run: - working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro - command: | - # retry the same split || - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true + # run 0 tests because nothing failed in the previous step || + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue" bundle exec rake knapsack_pro:queue:rspec - run: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | # fallback || + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--fallback" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--fallback" export KNAPSACK_PRO_ENDPOINT=https://api-fake.knapsackpro.com export KNAPSACK_PRO_MAX_REQUEST_RETRIES=1 bundle exec rake knapsack_pro:queue:rspec @@ -266,8 +263,8 @@ jobs: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | # split by test examples above the slow test file threshold || - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split-above-slow-test-file-threshold" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--split-above-slow-test-file-threshold" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--split-above-slow-test-file-threshold" export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true export KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD=1 bundle exec rake knapsack_pro:queue:rspec @@ -275,8 +272,8 @@ jobs: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | # split by test examples AND a single CI node || - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split--single-node--$CIRCLE_NODE_INDEX" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--split--single-node" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--split--single-node" export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true export KNAPSACK_PRO_CI_NODE_TOTAL=1 export KNAPSACK_PRO_CI_NODE_INDEX=0 @@ -285,7 +282,8 @@ jobs: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | # split custom files by test examples AND the --tag option passed || - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split-custom-files--tag-option" + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--split-custom-files--tag-option" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--split-custom-files--tag-option" export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/bar_spec.rb" export SKIP_ME_OR_I_WILL_FAIL=true @@ -296,8 +294,8 @@ jobs: # turnip || mv .rspec .rspec.off cp .rspec.turnip .rspec - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--turnip" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--turnip" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--turnip" export KNAPSACK_PRO_TEST_DIR=turnip export KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature" export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="turnip/acceptance/foo.feature" @@ -312,8 +310,8 @@ jobs: # turnip retry || mv .rspec .rspec.off cp .rspec.turnip .rspec - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--turnip" - export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--turnip" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--turnip" export KNAPSACK_PRO_TEST_DIR=turnip export KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature" export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="turnip/acceptance/foo.feature" diff --git a/lib/knapsack_pro.rb b/lib/knapsack_pro.rb index f02d7aa3..a401afa8 100644 --- a/lib/knapsack_pro.rb +++ b/lib/knapsack_pro.rb @@ -33,7 +33,6 @@ require_relative 'knapsack_pro/client/api/v1/base' require_relative 'knapsack_pro/client/api/v1/build_distributions' require_relative 'knapsack_pro/client/api/v1/build_subsets' -require_relative 'knapsack_pro/client/api/v1/queues' require_relative 'knapsack_pro/client/connection' require_relative 'knapsack_pro/repository_adapters/base_adapter' require_relative 'knapsack_pro/repository_adapters/env_adapter' @@ -84,6 +83,20 @@ require_relative 'knapsack_pro/crypto/digestor' require_relative 'knapsack_pro/pure/queue/rspec_pure' +module KnapsackPro + module Client + module API + module V1 + autoload(:Queues, 'knapsack_pro/client/api/v1/queues') + end + + module V2 + autoload(:Queues, 'knapsack_pro/client/api/v2/queues') + end + end + end +end + require 'knapsack_pro/railtie' if defined?(Rails::Railtie) module KnapsackPro diff --git a/lib/knapsack_pro/adapters/rspec_adapter.rb b/lib/knapsack_pro/adapters/rspec_adapter.rb index 1edcc594..f25d44de 100644 --- a/lib/knapsack_pro/adapters/rspec_adapter.rb +++ b/lib/knapsack_pro/adapters/rspec_adapter.rb @@ -138,7 +138,7 @@ def bind_regular_mode_time_tracker ::RSpec.configure do |config| config.append_before(:suite) do time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call - time_tracker.scheduled_paths = KnapsackPro::Adapters::RSpecAdapter.scheduled_paths + time_tracker.schedule(KnapsackPro::Adapters::RSpecAdapter.scheduled_paths) end end end diff --git a/lib/knapsack_pro/client/api/action.rb b/lib/knapsack_pro/client/api/action.rb index a362737f..b5652def 100644 --- a/lib/knapsack_pro/client/api/action.rb +++ b/lib/knapsack_pro/client/api/action.rb @@ -3,15 +3,7 @@ module KnapsackPro module Client module API - class Action - attr_reader :endpoint_path, :http_method, :request_hash - - def initialize(args) - @endpoint_path = args.fetch(:endpoint_path) - @http_method = args.fetch(:http_method) - @request_hash = args.fetch(:request_hash) - end - end + Action = Struct.new(:endpoint_path, :http_method, :request_hash, keyword_init: true) end end end diff --git a/lib/knapsack_pro/client/api/v2/queues.rb b/lib/knapsack_pro/client/api/v2/queues.rb new file mode 100644 index 00000000..c2f39b27 --- /dev/null +++ b/lib/knapsack_pro/client/api/v2/queues.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module KnapsackPro + module Client + module API + module V2 + class Queues < KnapsackPro::Client::API::V1::Base + CODE_ATTEMPT_CONNECT_TO_QUEUE_FAILED = 'ATTEMPT_CONNECT_TO_QUEUE_FAILED' + + class << self + def queue(args) + request_hash = { + fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split, + can_initialize_queue: args.fetch(:can_initialize_queue), + attempt_connect_to_queue: args.fetch(:attempt_connect_to_queue), + commit_hash: args.fetch(:commit_hash), + branch: args.fetch(:branch), + node_total: args.fetch(:node_total), + node_index: args.fetch(:node_index), + user_seat: KnapsackPro::Config::Env.masked_user_seat, + test_queue_id: KnapsackPro::Config::Env.test_queue_id, + node_uuid: KnapsackPro::Config::Env.node_uuid + } + + if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] + request_hash.merge!( + test_files: args.fetch(:test_files), + build_author: KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author, + commit_authors: KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors + ) + end + + if !request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] + request_hash.merge!( + failed_paths: args.fetch(:failed_paths) + ) + end + + action_class.new( + endpoint_path: '/v2/queues/queue', + http_method: :post, + request_hash: request_hash + ) + end + end + end + end + end + end +end diff --git a/lib/knapsack_pro/config/ci/base.rb b/lib/knapsack_pro/config/ci/base.rb index 6d533911..69392cb9 100644 --- a/lib/knapsack_pro/config/ci/base.rb +++ b/lib/knapsack_pro/config/ci/base.rb @@ -49,6 +49,9 @@ def ci_provider nil end + + def test_queue_id + end end end end diff --git a/lib/knapsack_pro/config/ci/circle.rb b/lib/knapsack_pro/config/ci/circle.rb index 31c2f718..3ca760ca 100644 --- a/lib/knapsack_pro/config/ci/circle.rb +++ b/lib/knapsack_pro/config/ci/circle.rb @@ -43,6 +43,18 @@ def fixed_queue_split def ci_provider "CircleCI" end + + def test_queue_id + # CIRCLE_PIPELINE_NUMBER does not exist in Circle, set it with: + # `CIRCLE_PIPELINE_NUMBER: << pipeline.number >>` + pipeline_number = ENV['CIRCLE_PIPELINE_NUMBER'] + return nil if pipeline_number.nil? + + job = ENV['CIRCLE_JOB'] + return nil if job.nil? + + "#{pipeline_number}:#{job}" + end end end end diff --git a/lib/knapsack_pro/config/ci/github_actions.rb b/lib/knapsack_pro/config/ci/github_actions.rb index a34347e8..fafaa71c 100644 --- a/lib/knapsack_pro/config/ci/github_actions.rb +++ b/lib/knapsack_pro/config/ci/github_actions.rb @@ -57,6 +57,10 @@ def fixed_queue_split def ci_provider "GitHub Actions" end + + def test_queue_id + node_build_id + end end end end diff --git a/lib/knapsack_pro/config/ci/gitlab_ci.rb b/lib/knapsack_pro/config/ci/gitlab_ci.rb index 060e26aa..2fa8f12f 100644 --- a/lib/knapsack_pro/config/ci/gitlab_ci.rb +++ b/lib/knapsack_pro/config/ci/gitlab_ci.rb @@ -51,6 +51,16 @@ def fixed_queue_split def ci_provider "Gitlab CI" end + + def test_queue_id + pipeline_id = ENV['CI_PIPELINE_ID'] + return nil if pipeline_id.nil? + + job = ENV['CI_JOB_NAME'] + return nil if job.nil? + + "#{pipeline_id}:#{job}" + end end end end diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index ba3b50ff..aefe9ea4 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -260,6 +260,17 @@ def fallback_mode_error_exit_code ENV.fetch('KNAPSACK_PRO_FALLBACK_MODE_ERROR_EXIT_CODE', 1).to_i end + def test_queue_id + env_name = 'KNAPSACK_PRO_TEST_QUEUE_ID' + env_for(env_name, :test_queue_id) || + raise("Missing environment variable #{env_name}. Read more at #{KnapsackPro::Urls::KNAPSACK_PRO_TEST_QUEUE_ID}") + end + + def node_uuid + env_name = 'KNAPSACK_PRO_NODE_UUID' + ENV[env_name] || raise("Missing environment variable #{env_name}. Please report this as a bug: #{KnapsackPro::Urls::SUPPORT}") + end + private def required_env(env_name) diff --git a/lib/knapsack_pro/formatters/time_tracker.rb b/lib/knapsack_pro/formatters/time_tracker.rb index 24ff0821..22dd4538 100644 --- a/lib/knapsack_pro/formatters/time_tracker.rb +++ b/lib/knapsack_pro/formatters/time_tracker.rb @@ -23,17 +23,24 @@ def initialize(_output) @group = {} @paths = {} @suite_started = now - @scheduled_paths = [] + @batched_scheduled_paths = [] @split_by_test_example_file_paths = Set.new + @current_batch_failed_examples = [] end - def scheduled_paths=(scheduled_paths) - @scheduled_paths = scheduled_paths - @scheduled_paths.each do |path| - if KnapsackPro::Adapters::RSpecAdapter.id_path?(path) - file_path = KnapsackPro::Adapters::RSpecAdapter.parse_file_path(path) - @split_by_test_example_file_paths << file_path - end + def failed_test_id_paths + @current_batch_failed_examples.map { |example| KnapsackPro::TestFileCleaner.clean(example.id) } + end + + def schedule(paths) + @current_batch_failed_examples = [] + @batched_scheduled_paths << paths + + paths.each do |path| + next unless KnapsackPro::Adapters::RSpecAdapter.id_path?(path) + + file_path = KnapsackPro::Adapters::RSpecAdapter.parse_file_path(path) + @split_by_test_example_file_paths << file_path end end @@ -68,7 +75,7 @@ def queue KnapsackPro::Adapters::RSpecAdapter.parse_file_path(example[:path]) end - missing = (@scheduled_paths - recorded_paths).each_with_object({}) do |path, object| + missing = (@batched_scheduled_paths.flatten - recorded_paths).each_with_object({}) do |path, object| object[path] = { path: path, time_execution: 0.0 } end @@ -87,12 +94,12 @@ def duration now - @suite_started end - def unexecuted_test_files + def unexecuted_test_paths pending_paths = @paths.values .filter { |example| example[:time_execution] == 0.0 } .map { |example| example[:path] } - not_run_paths = @scheduled_paths - + not_run_paths = @batched_scheduled_paths.flatten - @paths.values .map { |example| example[:path] } @@ -123,6 +130,8 @@ def record_example(accumulator, example, started_at) path = path_for(example) return if path.nil? + @current_batch_failed_examples << example if example.execution_result.status.to_s == "failed" + time_execution = time_execution_for(example, started_at) if accumulator.key?(path) accumulator[path][:time_execution] += time_execution diff --git a/lib/knapsack_pro/formatters/time_tracker_fetcher.rb b/lib/knapsack_pro/formatters/time_tracker_fetcher.rb index db392edb..393a0fc4 100644 --- a/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +++ b/lib/knapsack_pro/formatters/time_tracker_fetcher.rb @@ -10,10 +10,10 @@ def self.call .find { |f| f.class.to_s == "KnapsackPro::Formatters::TimeTracker" } end - def self.unexecuted_test_files + def self.unexecuted_test_paths time_tracker = call return [] unless time_tracker - time_tracker.unexecuted_test_files + time_tracker.unexecuted_test_paths end end end diff --git a/lib/knapsack_pro/queue_allocator.rb b/lib/knapsack_pro/queue_allocator.rb index 841e2534..45d99b9b 100644 --- a/lib/knapsack_pro/queue_allocator.rb +++ b/lib/knapsack_pro/queue_allocator.rb @@ -41,26 +41,26 @@ def initialize(args) @fallback_mode = false end - def test_file_paths(can_initialize_queue, executed_test_files, batch_uuid: SecureRandom.uuid) + def test_file_paths(can_initialize_queue, executed_test_files, batch_uuid: SecureRandom.uuid, time_tracker: nil) return [] if @fallback_mode - batch = pull_tests_from_queue(can_initialize_queue, batch_uuid) + batch = pull_tests_from_queue(can_initialize_queue, batch_uuid, time_tracker: time_tracker) return switch_to_fallback_mode(executed_test_files: executed_test_files) if batch.connection_failed? return normalize_test_files(batch.test_files) if batch.queue_exists? test_files_result = test_suite.calculate_test_files - return try_initializing_queue(test_files_result.test_files, batch_uuid) if test_files_result.quick? + return try_initializing_queue(test_files_result.test_files, batch_uuid, time_tracker: time_tracker) if test_files_result.quick? # The tests to run were found slowly. By that time, the queue could have already been initialized by another CI node. # Attempt to pull tests from the queue to avoid the attempt to initialize the queue unnecessarily (queue initialization is an expensive request with a big test files payload). - batch = pull_tests_from_queue(can_initialize_queue, batch_uuid) + batch = pull_tests_from_queue(can_initialize_queue, batch_uuid, time_tracker: time_tracker) return switch_to_fallback_mode(executed_test_files: executed_test_files) if batch.connection_failed? return normalize_test_files(batch.test_files) if batch.queue_exists? - try_initializing_queue(test_files_result.test_files, batch_uuid) + try_initializing_queue(test_files_result.test_files, batch_uuid, time_tracker: time_tracker) end private @@ -80,7 +80,7 @@ def normalize_test_files(test_files) KnapsackPro::TestFilePresenter.paths(decrypted_test_files) end - def build_action(can_initialize_queue:, attempt_connect_to_queue:, batch_uuid:, test_files: nil) + def build_action_v1(can_initialize_queue:, attempt_connect_to_queue:, batch_uuid:, test_files: nil) if can_initialize_queue && !attempt_connect_to_queue raise 'Test files are required when initializing a new queue.' if test_files.nil? test_files = KnapsackPro::Crypto::Encryptor.call(test_files) @@ -99,23 +99,78 @@ def build_action(can_initialize_queue:, attempt_connect_to_queue:, batch_uuid:, ) end - def pull_tests_from_queue(can_initialize_queue, batch_uuid) - action = build_action(can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: can_initialize_queue, batch_uuid: batch_uuid) + def build_action_v2(can_initialize_queue:, attempt_connect_to_queue:, time_tracker:, batch_uuid:, test_files: nil) + if can_initialize_queue && !attempt_connect_to_queue + raise 'Test files are required when initializing a new queue.' if test_files.nil? + test_files = KnapsackPro::Crypto::Encryptor.call(test_files) + end + + KnapsackPro::Client::API::V2::Queues.queue( + can_initialize_queue: can_initialize_queue, + attempt_connect_to_queue: attempt_connect_to_queue, + commit_hash: repository_adapter.commit_hash, + branch: encrypted_branch, + node_total: ci_node_total, + node_index: ci_node_index, + test_files: test_files, + failed_paths: time_tracker.failed_test_id_paths, + batch_uuid: batch_uuid + ) + end + + def pull_tests_from_queue(can_initialize_queue, batch_uuid, time_tracker: nil) + if time_tracker.nil? + pull_tests_from_queue_v1(can_initialize_queue, batch_uuid) + else + pull_tests_from_queue_v2(can_initialize_queue, batch_uuid, time_tracker) + end + end + + def pull_tests_from_queue_v1(can_initialize_queue, batch_uuid) + action = build_action_v1(can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: can_initialize_queue, batch_uuid: batch_uuid) + connection = KnapsackPro::Client::Connection.new(action) + response = connection.call + Batch.new(connection, response) + end + + def pull_tests_from_queue_v2(can_initialize_queue, batch_uuid, time_tracker) + action = build_action_v2(can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: can_initialize_queue, batch_uuid: batch_uuid, time_tracker: time_tracker) connection = KnapsackPro::Client::Connection.new(action) response = connection.call Batch.new(connection, response) end - def initialize_queue(tests_to_run, batch_uuid) - action = build_action(can_initialize_queue: true, attempt_connect_to_queue: false, batch_uuid: batch_uuid, test_files: tests_to_run) + def initialize_queue_v1(tests_to_run, batch_uuid) + action = build_action_v1(can_initialize_queue: true, attempt_connect_to_queue: false, batch_uuid: batch_uuid, test_files: tests_to_run) connection = KnapsackPro::Client::Connection.new(action) response = connection.call Batch.new(connection, response) end - def try_initializing_queue(tests, batch_uuid) - result = initialize_queue(tests, batch_uuid) + def initialize_queue_v2(tests_to_run, batch_uuid, time_tracker) + action = build_action_v2(can_initialize_queue: true, attempt_connect_to_queue: false, batch_uuid: batch_uuid, test_files: tests_to_run, time_tracker: time_tracker) + connection = KnapsackPro::Client::Connection.new(action) + response = connection.call + Batch.new(connection, response) + end + + def try_initializing_queue(tests, batch_uuid, time_tracker: nil) + if time_tracker.nil? + try_initializing_queue_v1(tests, batch_uuid) + else + try_initializing_queue_v2(tests, batch_uuid, time_tracker) + end + end + + def try_initializing_queue_v1(tests, batch_uuid) + result = initialize_queue_v1(tests, batch_uuid) + return switch_to_fallback_mode(executed_test_files: []) if result.connection_failed? + + normalize_test_files(result.test_files) + end + def try_initializing_queue_v2(tests, batch_uuid, time_tracker) + result = initialize_queue_v2(tests, batch_uuid, time_tracker) return switch_to_fallback_mode(executed_test_files: []) if result.connection_failed? normalize_test_files(result.test_files) diff --git a/lib/knapsack_pro/runners/queue/base_runner.rb b/lib/knapsack_pro/runners/queue/base_runner.rb index 42cb0a25..491b1a8a 100644 --- a/lib/knapsack_pro/runners/queue/base_runner.rb +++ b/lib/knapsack_pro/runners/queue/base_runner.rb @@ -26,7 +26,8 @@ def initialize(adapter_class) def test_file_paths(args) can_initialize_queue = args.fetch(:can_initialize_queue) executed_test_files = args.fetch(:executed_test_files) - allocator.test_file_paths(can_initialize_queue, executed_test_files) + time_tracker = args.fetch(:time_tracker, nil) + allocator.test_file_paths(can_initialize_queue, executed_test_files, time_tracker: time_tracker) end def test_dir diff --git a/lib/knapsack_pro/runners/queue/rspec_runner.rb b/lib/knapsack_pro/runners/queue/rspec_runner.rb index fb03f24f..1219364f 100644 --- a/lib/knapsack_pro/runners/queue/rspec_runner.rb +++ b/lib/knapsack_pro/runners/queue/rspec_runner.rb @@ -13,6 +13,7 @@ def self.run(args, stream_error = $stderr, stream_out = $stdout) KnapsackPro::Extensions::RSpecExtension.setup! ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec + ENV['KNAPSACK_PRO_NODE_UUID'] = SecureRandom.uuid rspec_pure = KnapsackPro::Pure::Queue::RSpecPure.new @@ -64,7 +65,7 @@ def run KnapsackPro.logger.error("Exception message: #{exception.message}") KnapsackPro.logger.error("Exception backtrace: #{exception.backtrace&.join("\n")}") - message = @rspec_pure.exit_summary(unexecuted_test_files) + message = @rspec_pure.exit_summary(unexecuted_test_paths) KnapsackPro.logger.warn(message) if message exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code) @@ -178,15 +179,14 @@ def ensure_no_deprecated_run_all_when_everything_filtered_option! end def pull_tests_from_queue(can_initialize_queue: false) + time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call test_file_paths = test_file_paths( can_initialize_queue: can_initialize_queue, - executed_test_files: @node_test_file_paths + executed_test_files: @node_test_file_paths, + time_tracker: time_tracker ) @node_test_file_paths += test_file_paths - - time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call - time_tracker.scheduled_paths = @node_test_file_paths - + time_tracker.schedule(test_file_paths) test_file_paths end @@ -225,8 +225,8 @@ def log_info_messages(messages) end end - def unexecuted_test_files - KnapsackPro::Formatters::TimeTrackerFetcher.unexecuted_test_files + def unexecuted_test_paths + KnapsackPro::Formatters::TimeTrackerFetcher.unexecuted_test_paths end end end diff --git a/lib/knapsack_pro/urls.rb b/lib/knapsack_pro/urls.rb index a6f1e4de..fe65f528 100644 --- a/lib/knapsack_pro/urls.rb +++ b/lib/knapsack_pro/urls.rb @@ -18,7 +18,7 @@ module Urls INSTALLATION_GUIDE = "#{HOST}/perma/ruby/installation-guide" - KNAPSACK_PRO_CI_NODE_BUILD_ID= "#{HOST}/perma/ruby/knapsack-pro-ci-node-build-id" + KNAPSACK_PRO_CI_NODE_BUILD_ID = "#{HOST}/perma/ruby/knapsack-pro-ci-node-build-id" QUEUE_MODE__CONNECTION_ERROR_WITH_FALLBACK_ENABLED_FALSE = "#{HOST}/perma/ruby/queue-mode-connection-error-with-fallback-enabled-false" @@ -35,5 +35,7 @@ module Urls SPLIT_BY_TEST_EXAMPLES = "#{HOST}/perma/ruby/split-by-test-examples" TEST_UNIT__TEST_FILE_PATH_DETECTION = "#{HOST}/perma/ruby/test-unit-test-file-path-detection" + + KNAPSACK_PRO_TEST_QUEUE_ID = "#{HOST}/perma/ruby/knapsack-pro-test-queue-id" end end diff --git a/spec/integration/runners/queue/rspec_runner.rb b/spec/integration/runners/queue/rspec_runner.rb index c75787aa..29296630 100644 --- a/spec/integration/runners/queue/rspec_runner.rb +++ b/spec/integration/runners/queue/rspec_runner.rb @@ -20,14 +20,14 @@ def self.log(message) module KnapsackProExtensions module QueueAllocatorExtension # Succeeds to initialize on the first request - def initialize_queue(tests_to_run, batch_uuid) + def initialize_queue_v2(tests_to_run, batch_uuid, time_tracker) # Ensure the stubbed batches match the tests Knapsack Pro wants to run raise unless tests_to_run.map { _1["path"] }.sort == BATCHES.flatten.sort test__pull end # On the first request it fails, but succeeds on the second request - def pull_tests_from_queue(can_initialize_queue, batch_uuid) + def pull_tests_from_queue_v2(can_initialize_queue, batch_uuid, time_tracker) if can_initialize_queue connection = OpenStruct.new(success?: true, api_code: KnapsackPro::Client::API::V1::Queues::CODE_ATTEMPT_CONNECT_TO_QUEUE_FAILED) KnapsackPro::QueueAllocator::Batch.new(connection, {}) diff --git a/spec/integration/runners/queue/rspec_runner_fallback_spec.rb b/spec/integration/runners/queue/rspec_runner_fallback_spec.rb index a13cd025..dccf2c8d 100644 --- a/spec/integration/runners/queue/rspec_runner_fallback_spec.rb +++ b/spec/integration/runners/queue/rspec_runner_fallback_spec.rb @@ -38,6 +38,7 @@ def log(stdout, stderr, status) ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC'] = SecureRandom.hex ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = SecureRandom.uuid + ENV['KNAPSACK_PRO_TEST_QUEUE_ID'] = SecureRandom.uuid #{KnapsackPro::Runners::Queue::RSpecRunner}.run('') CONTENT diff --git a/spec/knapsack_pro/client/api/v2/queues_spec.rb b/spec/knapsack_pro/client/api/v2/queues_spec.rb new file mode 100644 index 00000000..eb57eee7 --- /dev/null +++ b/spec/knapsack_pro/client/api/v2/queues_spec.rb @@ -0,0 +1,143 @@ +describe KnapsackPro::Client::API::V2::Queues do + describe '.queue' do + let(:fixed_queue_split) { double } + let(:commit_hash) { double } + let(:branch) { double } + let(:node_total) { double } + let(:node_index) { double } + let(:test_files) { double } + let(:masked_user_seat) { double } + let(:can_initialize_queue) { [false, true].sample } + let(:attempt_connect_to_queue) { [false, true].sample } + let(:test_queue_id) { "123:abc" } + let(:node_uuid) { SecureRandom.uuid } + + before(:each) do + expect(KnapsackPro::Config::Env).to receive(:fixed_queue_split).and_return(fixed_queue_split) + expect(KnapsackPro::Config::Env).to receive(:masked_user_seat).and_return(masked_user_seat) + expect(KnapsackPro::Config::Env).to receive(:test_queue_id).and_return(test_queue_id) + expect(KnapsackPro::Config::Env).to receive(:node_uuid).and_return(node_uuid) + end + + context 'when can_initialize_queue=true and attempt_connect_to_queue=true' do + let(:can_initialize_queue) { true } + let(:attempt_connect_to_queue) { true } + + it do + expected = KnapsackPro::Client::API::Action.new( + endpoint_path: '/v2/queues/queue', + http_method: :post, + request_hash: { + fixed_queue_split: fixed_queue_split, + can_initialize_queue: true, + attempt_connect_to_queue: true, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + user_seat: masked_user_seat, + test_queue_id: test_queue_id, + node_uuid: node_uuid + } + ) + + actual = described_class.queue( + can_initialize_queue: can_initialize_queue, + attempt_connect_to_queue: attempt_connect_to_queue, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + test_files: test_files + ) + + expect(actual).to eq(expected) + end + end + + context 'when can_initialize_queue=true and attempt_connect_to_queue=false' do + let(:can_initialize_queue) { true } + let(:attempt_connect_to_queue) { false } + let(:build_author) { '3v0*4 ' } + let(:commit_authors) { [{ commits: 2, author: build_author }] } + + before(:each) do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:build_author).and_return(build_author) + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:commit_authors).and_return(commit_authors) + end + + it do + expected = KnapsackPro::Client::API::Action.new( + endpoint_path: '/v2/queues/queue', + http_method: :post, + request_hash: { + fixed_queue_split: fixed_queue_split, + can_initialize_queue: true, + attempt_connect_to_queue: false, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + user_seat: masked_user_seat, + test_files: test_files, + build_author: build_author, + commit_authors: commit_authors, + test_queue_id: test_queue_id, + node_uuid: node_uuid + } + ) + + actual = described_class.queue( + can_initialize_queue: can_initialize_queue, + attempt_connect_to_queue: attempt_connect_to_queue, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + test_files: test_files + ) + + expect(actual).to eq(expected) + end + end + + context 'when can_initialize_queue=false and attempt_connect_to_queue=false' do + let(:can_initialize_queue) { false } + let(:attempt_connect_to_queue) { false } + let(:failed_paths) { ['spec/a_spec.rb[1:1]'] } + + it do + expected = KnapsackPro::Client::API::Action.new( + endpoint_path: '/v2/queues/queue', + http_method: :post, + request_hash: { + fixed_queue_split: fixed_queue_split, + can_initialize_queue: false, + attempt_connect_to_queue: false, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + user_seat: masked_user_seat, + test_queue_id: test_queue_id, + node_uuid: node_uuid, + failed_paths: failed_paths + } + ) + + actual = described_class.queue( + can_initialize_queue: can_initialize_queue, + attempt_connect_to_queue: attempt_connect_to_queue, + commit_hash: commit_hash, + branch: branch, + node_total: node_total, + node_index: node_index, + test_files: test_files, + failed_paths: failed_paths + ) + + expect(actual).to eq(expected) + end + end + end +end diff --git a/spec/knapsack_pro/config/ci/circle_spec.rb b/spec/knapsack_pro/config/ci/circle_spec.rb index 448a90f9..37fac8c4 100644 --- a/spec/knapsack_pro/config/ci/circle_spec.rb +++ b/spec/knapsack_pro/config/ci/circle_spec.rb @@ -119,4 +119,19 @@ it { should be nil } end end + + [ + [{ 'CIRCLE_PIPELINE_NUMBER' => '123', 'CIRCLE_JOB' => 'test' }, '123:test'], + [{ 'CIRCLE_PIPELINE_NUMBER' => '123' }, nil], + [{ 'CIRCLE_JOB' => 'test' }, nil], + [{}, nil] + ].each do |env, expected| + describe '#test_queue_id' do + subject { described_class.new.test_queue_id } + + let(:env) { env } + + it { should eql expected } + end + end end diff --git a/spec/knapsack_pro/config/ci/github_actions_spec.rb b/spec/knapsack_pro/config/ci/github_actions_spec.rb index 52bf9444..804c4084 100644 --- a/spec/knapsack_pro/config/ci/github_actions_spec.rb +++ b/spec/knapsack_pro/config/ci/github_actions_spec.rb @@ -137,4 +137,17 @@ it { should be nil } end end + + describe '#test_queue_id' do + subject { described_class.new.test_queue_id } + + context 'when the environment exists' do + let(:env) { { 'GITHUB_RUN_ID' => 2706 } } + it { should eql 2706 } + end + + context "when the environment doesn't exist" do + it { should be nil } + end + end end diff --git a/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb b/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb index 24d55569..e6a20d98 100644 --- a/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb +++ b/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb @@ -134,4 +134,19 @@ it { should be nil } end end + + [ + [{ 'CI_PIPELINE_ID' => '123', 'CI_JOB_NAME' => 'test' }, '123:test'], + [{ 'CI_PIPELINE_ID' => '123' }, nil], + [{ 'CI_JOB_NAME' => 'test' }, nil], + [{}, nil] + ].each do |env, expected| + describe '#test_queue_id' do + subject { described_class.new.test_queue_id } + + let(:env) { env } + + it { should eql expected } + end + end end diff --git a/spec/knapsack_pro/config/env_spec.rb b/spec/knapsack_pro/config/env_spec.rb index 27457fc6..ce855c6f 100644 --- a/spec/knapsack_pro/config/env_spec.rb +++ b/spec/knapsack_pro/config/env_spec.rb @@ -1219,4 +1219,58 @@ end end end + + describe '.test_queue_id' do + subject { described_class.test_queue_id } + + context 'when KNAPSACK_PRO_TEST_QUEUE_ID has value' do + before { stub_const("ENV", { 'KNAPSACK_PRO_TEST_QUEUE_ID' => '123:456' }) } + it { should eq '123:456' } + end + + context 'when CI environment has value' do + before do + expect(described_class).to receive(:ci_env_for).with(:test_queue_id).and_return('abc:def') + end + + it { should eq 'abc:def' } + end + + context 'when both KNAPSACK_PRO_TEST_QUEUE_ID and CI environment have value' do + before do + stub_const("ENV", { 'KNAPSACK_PRO_TEST_QUEUE_ID' => env_value }) + expect(described_class).to receive(:ci_env_for).with(:test_queue_id).and_return(ci_value) + end + + context 'when values are different' do + let(:env_value) { '123:456' } + let(:ci_value) { 'abc:def' } + + it { should eq '123:456' } + + it 'logs a warning' do + expect(described_class).to receive(:warn).with( + 'You have set the environment variable KNAPSACK_PRO_TEST_QUEUE_ID to 123:456 which could be automatically determined from the CI environment as abc:def.' + ) + subject + end + end + + context 'when values are the same' do + let(:env_value) { '123:456' } + let(:ci_value) { '123:456' } + + it 'does not log a warning' do + expect(described_class).not_to receive(:warn) + subject + end + end + end + + context "when ENV does not exist" do + it 'raises' do + expect { subject }.to raise_error(/Missing environment variable KNAPSACK_PRO_TEST_QUEUE_ID/) + end + end + end end diff --git a/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb b/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb index a6c0d767..222d18d1 100644 --- a/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb +++ b/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb @@ -1,8 +1,8 @@ require(KnapsackPro.root + '/lib/knapsack_pro/formatters/time_tracker') describe KnapsackPro::Formatters::TimeTrackerFetcher do - describe '.unexecuted_test_files' do - subject { described_class.unexecuted_test_files } + describe '.unexecuted_test_paths' do + subject { described_class.unexecuted_test_paths } context 'when the time tracker formatter not found' do it do @@ -12,15 +12,15 @@ context 'when the time tracker formatter is found' do let(:time_tracker) { instance_double(KnapsackPro::Formatters::TimeTracker) } - let(:unexecuted_test_files) { double(:unexecuted_test_files) } + let(:unexecuted_test_paths) { double(:unexecuted_test_paths) } before do expect(described_class).to receive(:call).and_return(time_tracker) - expect(time_tracker).to receive(:unexecuted_test_files).and_return(unexecuted_test_files) + expect(time_tracker).to receive(:unexecuted_test_paths).and_return(unexecuted_test_paths) end it do - expect(subject).to eq unexecuted_test_files + expect(subject).to eq unexecuted_test_paths end end end diff --git a/spec/knapsack_pro/formatters/time_tracker_spec.rb b/spec/knapsack_pro/formatters/time_tracker_spec.rb index fd59f15b..0c40002d 100644 --- a/spec/knapsack_pro/formatters/time_tracker_spec.rb +++ b/spec/knapsack_pro/formatters/time_tracker_spec.rb @@ -336,7 +336,7 @@ RSpec.configure do |config| config.before(:all) do time_tracker = ::RSpec.configuration.formatters.find { |f| f.class.to_s == 'TestableTimeTracker' } - time_tracker.scheduled_paths = ['#{@dir}/0_spec.rb'] + time_tracker.schedule(["#{@dir}/0_spec.rb"]) end end @@ -359,7 +359,7 @@ RSpec.configure do |config| config.before(:suite) do time_tracker = ::RSpec.configuration.formatters.find { |f| f.class.to_s == 'TestableTimeTracker' } - time_tracker.scheduled_paths = ['#{@dir}/0_spec.rb'] + time_tracker.schedule(["#{@dir}/0_spec.rb"]) end end @@ -391,13 +391,13 @@ end end - describe '#unexecuted_test_files' do + describe '#unexecuted_test_paths' do it do spec = <<~SPEC RSpec.configure do |config| config.before(:all) do time_tracker = ::RSpec.configuration.formatters.find { |f| f.class.to_s == 'TestableTimeTracker' } - time_tracker.scheduled_paths = ['#{@dir}/0_spec.rb', 'foo_spec.rb[1:1]'] + time_tracker.schedule(["#{@dir}/0_spec.rb", "foo_spec.rb[1:1]"]) end end @@ -407,8 +407,8 @@ end SPEC - run_specs(spec, 'unexecuted_test_files') do |spec_paths, unexecuted_test_files| - expect(unexecuted_test_files).to eq(["#{@dir}/0_spec.rb", 'foo_spec.rb[1:1]']) + run_specs(spec, 'unexecuted_test_paths') do |spec_paths, unexecuted_test_paths| + expect(unexecuted_test_paths).to eq(["#{@dir}/0_spec.rb", 'foo_spec.rb[1:1]']) end end end @@ -432,6 +432,45 @@ end end + describe '#failed_test_id_paths' do + it 'returns the most recent failed_test_id_paths' do + spec0 = <<~SPEC + RSpec.configure do |config| + config.before(:all) do + time_tracker = ::RSpec.configuration.formatters.find { |f| f.class.to_s == 'TestableTimeTracker' } + time_tracker.schedule(["#{@dir}/0_spec.rb"]) + end + end + + describe 'KnapsackPro::Formatters::TimeTracker' do + it do + expect(1).to eq 2 + end + end + SPEC + + spec1 = <<~SPEC + RSpec.configure do |config| + config.before(:all) do + time_tracker = ::RSpec.configuration.formatters.find { |f| f.class.to_s == 'TestableTimeTracker' } + time_tracker.schedule(["#{@dir}/1_spec.rb"]) + end + end + + describe 'KnapsackPro::Formatters::TimeTracker' do + it do + expect(1).to eq 2 + end + end + SPEC + + run_specs([spec0, spec1], 'failed_test_id_paths') do |spec_paths, id_paths| + expect(id_paths.size).to eq(1) + expect(id_paths[0]).to eq("#{spec_paths[1]}[1:1]") + end + end + end + def run_specs(specs, method, env: '') paths = Array(specs).map.with_index do |spec, i| path = "#{@dir}/#{i}_spec.rb" diff --git a/spec/knapsack_pro/runners/queue/base_runner_spec.rb b/spec/knapsack_pro/runners/queue/base_runner_spec.rb index 3b52488d..e37120b6 100644 --- a/spec/knapsack_pro/runners/queue/base_runner_spec.rb +++ b/spec/knapsack_pro/runners/queue/base_runner_spec.rb @@ -43,7 +43,7 @@ let(:test_file_paths) { double } before do - expect(allocator).to receive(:test_file_paths).with(can_initialize_queue, executed_test_files).and_return(test_file_paths) + expect(allocator).to receive(:test_file_paths).with(can_initialize_queue, executed_test_files, time_tracker: nil).and_return(test_file_paths) end it { should eq test_file_paths } From a985a582cdd688d0b198d79edb3bb1f87836eed3 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 12 Aug 2025 11:51:47 +0200 Subject: [PATCH 02/29] feat: lost batch --- lib/knapsack_pro/client/api/v2/queues.rb | 3 ++- .../knapsack_pro/client/api/v2/queues_spec.rb | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/knapsack_pro/client/api/v2/queues.rb b/lib/knapsack_pro/client/api/v2/queues.rb index c2f39b27..cbfc82e5 100644 --- a/lib/knapsack_pro/client/api/v2/queues.rb +++ b/lib/knapsack_pro/client/api/v2/queues.rb @@ -19,7 +19,8 @@ def queue(args) node_index: args.fetch(:node_index), user_seat: KnapsackPro::Config::Env.masked_user_seat, test_queue_id: KnapsackPro::Config::Env.test_queue_id, - node_uuid: KnapsackPro::Config::Env.node_uuid + node_uuid: KnapsackPro::Config::Env.node_uuid, + batch_uuid: args.fetch(:batch_uuid) } if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] diff --git a/spec/knapsack_pro/client/api/v2/queues_spec.rb b/spec/knapsack_pro/client/api/v2/queues_spec.rb index eb57eee7..6fa42cf1 100644 --- a/spec/knapsack_pro/client/api/v2/queues_spec.rb +++ b/spec/knapsack_pro/client/api/v2/queues_spec.rb @@ -11,6 +11,7 @@ let(:attempt_connect_to_queue) { [false, true].sample } let(:test_queue_id) { "123:abc" } let(:node_uuid) { SecureRandom.uuid } + let(:batch_uuid) { SecureRandom.uuid } before(:each) do expect(KnapsackPro::Config::Env).to receive(:fixed_queue_split).and_return(fixed_queue_split) @@ -37,7 +38,8 @@ node_index: node_index, user_seat: masked_user_seat, test_queue_id: test_queue_id, - node_uuid: node_uuid + node_uuid: node_uuid, + batch_uuid: batch_uuid } ) @@ -48,7 +50,8 @@ branch: branch, node_total: node_total, node_index: node_index, - test_files: test_files + test_files: test_files, + batch_uuid: batch_uuid ) expect(actual).to eq(expected) @@ -83,7 +86,8 @@ build_author: build_author, commit_authors: commit_authors, test_queue_id: test_queue_id, - node_uuid: node_uuid + node_uuid: node_uuid, + batch_uuid: batch_uuid } ) @@ -94,7 +98,8 @@ branch: branch, node_total: node_total, node_index: node_index, - test_files: test_files + test_files: test_files, + batch_uuid: batch_uuid ) expect(actual).to eq(expected) @@ -121,7 +126,8 @@ user_seat: masked_user_seat, test_queue_id: test_queue_id, node_uuid: node_uuid, - failed_paths: failed_paths + failed_paths: failed_paths, + batch_uuid: batch_uuid } ) @@ -133,7 +139,8 @@ node_total: node_total, node_index: node_index, test_files: test_files, - failed_paths: failed_paths + failed_paths: failed_paths, + batch_uuid: batch_uuid ) expect(actual).to eq(expected) From 7eab5d5e919ce52570e2145a6c2dc9aa8fdeedd8 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 13 Aug 2025 17:00:14 +0200 Subject: [PATCH 03/29] chore: simplify test_queue_id --- lib/knapsack_pro/config/ci/circle.rb | 8 +------- lib/knapsack_pro/config/ci/gitlab_ci.rb | 8 +------- spec/knapsack_pro/config/ci/circle_spec.rb | 4 +--- spec/knapsack_pro/config/ci/gitlab_ci_spec.rb | 4 +--- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/knapsack_pro/config/ci/circle.rb b/lib/knapsack_pro/config/ci/circle.rb index 3ca760ca..538a9f82 100644 --- a/lib/knapsack_pro/config/ci/circle.rb +++ b/lib/knapsack_pro/config/ci/circle.rb @@ -47,13 +47,7 @@ def ci_provider def test_queue_id # CIRCLE_PIPELINE_NUMBER does not exist in Circle, set it with: # `CIRCLE_PIPELINE_NUMBER: << pipeline.number >>` - pipeline_number = ENV['CIRCLE_PIPELINE_NUMBER'] - return nil if pipeline_number.nil? - - job = ENV['CIRCLE_JOB'] - return nil if job.nil? - - "#{pipeline_number}:#{job}" + ENV['CIRCLE_PIPELINE_NUMBER'] end end end diff --git a/lib/knapsack_pro/config/ci/gitlab_ci.rb b/lib/knapsack_pro/config/ci/gitlab_ci.rb index 2fa8f12f..ab6c4af3 100644 --- a/lib/knapsack_pro/config/ci/gitlab_ci.rb +++ b/lib/knapsack_pro/config/ci/gitlab_ci.rb @@ -53,13 +53,7 @@ def ci_provider end def test_queue_id - pipeline_id = ENV['CI_PIPELINE_ID'] - return nil if pipeline_id.nil? - - job = ENV['CI_JOB_NAME'] - return nil if job.nil? - - "#{pipeline_id}:#{job}" + ENV['CI_PIPELINE_ID'] end end end diff --git a/spec/knapsack_pro/config/ci/circle_spec.rb b/spec/knapsack_pro/config/ci/circle_spec.rb index 37fac8c4..a4e9a7fa 100644 --- a/spec/knapsack_pro/config/ci/circle_spec.rb +++ b/spec/knapsack_pro/config/ci/circle_spec.rb @@ -121,9 +121,7 @@ end [ - [{ 'CIRCLE_PIPELINE_NUMBER' => '123', 'CIRCLE_JOB' => 'test' }, '123:test'], - [{ 'CIRCLE_PIPELINE_NUMBER' => '123' }, nil], - [{ 'CIRCLE_JOB' => 'test' }, nil], + [{ 'CIRCLE_PIPELINE_NUMBER' => '123' }, '123'], [{}, nil] ].each do |env, expected| describe '#test_queue_id' do diff --git a/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb b/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb index e6a20d98..9327ecdd 100644 --- a/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb +++ b/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb @@ -136,9 +136,7 @@ end [ - [{ 'CI_PIPELINE_ID' => '123', 'CI_JOB_NAME' => 'test' }, '123:test'], - [{ 'CI_PIPELINE_ID' => '123' }, nil], - [{ 'CI_JOB_NAME' => 'test' }, nil], + [{ 'CI_PIPELINE_ID' => '123' }, '123'], [{}, nil] ].each do |env, expected| describe '#test_queue_id' do From 85963780917182b65f59a5f5f028726f6bf99a4f Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 26 Aug 2025 09:16:36 +0200 Subject: [PATCH 04/29] feat(rof): retry command --- README.md | 2 +- bin/knapsack_pro | 25 +------- bin/rspec | 27 ++++++++ exe/knapsack_pro | 3 + knapsack_pro.gemspec | 43 +++++++------ lib/knapsack_pro/commands.rb | 109 +++++++++++++++++++++++++++++++++ lib/knapsack_pro/config/env.rb | 2 + 7 files changed, 166 insertions(+), 45 deletions(-) create mode 100755 bin/rspec create mode 100755 exe/knapsack_pro create mode 100644 lib/knapsack_pro/commands.rb diff --git a/README.md b/README.md index 28cc38d8..a80295ad 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ bundle update knapsack_pro RSpec: ```bash -bundle exec rspec +bin/rspec ``` ### Publishing diff --git a/bin/knapsack_pro b/bin/knapsack_pro index 6f793cf2..5ac0fe9a 100755 --- a/bin/knapsack_pro +++ b/bin/knapsack_pro @@ -1,25 +1,6 @@ #!/usr/bin/env ruby -require_relative '../lib/knapsack_pro' +require "rubygems" +require "bundler/setup" -runner = ARGV[0] -arguments = ARGV[1] - -MAP = { - 'rspec' => KnapsackPro::Runners::RSpecRunner, - 'queue:rspec' => KnapsackPro::Runners::Queue::RSpecRunner, - 'cucumber' => KnapsackPro::Runners::CucumberRunner, - 'queue:cucumber' => KnapsackPro::Runners::Queue::CucumberRunner, - 'minitest' => KnapsackPro::Runners::MinitestRunner, - 'queue:minitest' => KnapsackPro::Runners::Queue::MinitestRunner, - 'test_unit' => KnapsackPro::Runners::TestUnitRunner, - 'spinach' => KnapsackPro::Runners::SpinachRunner, -} - -runner_class = MAP[runner] - -if runner_class - runner_class.run(arguments) -else - raise 'Undefined runner. Please provide runner name and optional arguments, for instance: knapsack_pro rspec "--color --profile"' -end +load Gem.bin_path("knapsack_pro", "knapsack_pro") diff --git a/bin/rspec b/bin/rspec new file mode 100755 index 00000000..cb53ebe5 --- /dev/null +++ b/bin/rspec @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rspec-core", "rspec") diff --git a/exe/knapsack_pro b/exe/knapsack_pro new file mode 100755 index 00000000..23c62303 --- /dev/null +++ b/exe/knapsack_pro @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +require "knapsack_pro/commands" diff --git a/knapsack_pro.gemspec b/knapsack_pro.gemspec index 997feef9..741624a9 100644 --- a/knapsack_pro.gemspec +++ b/knapsack_pro.gemspec @@ -1,32 +1,31 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'knapsack_pro/version' +require_relative "lib/knapsack_pro/version" Gem::Specification.new do |spec| - spec.name = 'knapsack_pro' + spec.name = "knapsack_pro" spec.version = KnapsackPro::VERSION spec.required_ruby_version = '>= 3.0.0' - spec.authors = ['ArturT'] - spec.email = ['support@knapsackpro.com'] - spec.summary = %q{Knapsack Pro splits tests across parallel CI nodes and ensures each parallel job finish work at a similar time.} - spec.description = %q{Knapsack Pro wraps your current test runner(s) and works with your existing CI infrastructure to parallelize tests optimally. It dynamically splits your tests based on up-to-date test execution data. It's designed from the ground up for CI and supports all of them.} - spec.homepage = 'https://knapsackpro.com' - spec.license = 'MIT' - spec.metadata = { - 'bug_tracker_uri' => 'https://github.com/KnapsackPro/knapsack_pro-ruby/issues', - 'changelog_uri' => 'https://github.com/KnapsackPro/knapsack_pro-ruby/blob/main/CHANGELOG.md', - 'documentation_uri' => 'https://docs.knapsackpro.com/knapsack_pro-ruby/guide/', - 'homepage_uri' => 'https://knapsackpro.com', - 'source_code_uri' => 'https://github.com/KnapsackPro/knapsack_pro-ruby' - } + spec.authors = ["ArturT"] + spec.email = ["support@knapsackpro.com"] + spec.summary = "Knapsack Pro splits tests across parallel CI nodes and ensures each parallel job finish work at a similar time." + spec.description = "Knapsack Pro wraps your current test runner(s) and works with your existing CI infrastructure to parallelize tests optimally. It dynamically splits your tests based on up-to-date test execution data. It's designed from the ground up for CI and supports all of them." + spec.homepage = "https://knapsackpro.com" + spec.license = "MIT" - spec.files = Dir.glob("lib/**/*") + Dir.glob("exe/*") - spec.executables = ['knapsack_pro'] + spec.metadata["bug_tracker_uri"] = "https://github.com/KnapsackPro/knapsack_pro-ruby/issues" + spec.metadata["changelog_uri"] = "https://github.com/KnapsackPro/knapsack_pro-ruby/blob/main/CHANGELOG.md" + spec.metadata["documentation_uri"] = "https://docs.knapsackpro.com/knapsack_pro-ruby/guide/" + spec.metadata["homepage_uri"] = "https://knapsackpro.com" + spec.metadata["source_code_uri"] = "https://github.com/KnapsackPro/knapsack_pro-ruby" + spec.metadata["rubygems_mfa_required"] = "true" + + spec.files = Dir.glob("lib/**/*") + Dir.glob("exe/*") + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ['lib'] + spec.require_paths = ["lib"] - spec.add_dependency 'rake', '>= 0' + spec.add_dependency "rake", ">= 0" + spec.add_dependency "thor", "~> 1.4" spec.add_development_dependency 'bundler', '>= 1.6' spec.add_development_dependency 'cucumber', '>= 0' diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb new file mode 100644 index 00000000..b6807832 --- /dev/null +++ b/lib/knapsack_pro/commands.rb @@ -0,0 +1,109 @@ +require "thor" + +module KnapsackPro + class Commands < Thor + map "queue:rspec" => :queue_rspec + map "queue:cucumber" => :queue_cucumber + map "queue:minitest" => :queue_minitest + + def self.exit_on_failure? + true + end + + desc "rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Regular Mode" + def rspec(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::RSpecRunner.run(arguments) + end + + desc "queue:rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Queue Mode" + def queue_rspec(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::Queue::RSpecRunner.run(arguments) + end + + desc "cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Regular Mode" + def cucumber(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::CucumberRunner.run(arguments) + end + + desc "queue:cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Queue Mode" + def queue_cucumber(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::Queue::CucumberRunner.run(arguments) + end + + desc "minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Regular Mode" + def minitest(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::MinitestRunner.run(arguments) + end + + desc "queue:minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Queue Mode" + def queue_minitest(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::Queue::MinitestRunner.run(arguments) + end + + desc "test_unit ['arguments']", "Parallelize TestUnit with Knapsack Pro in Regular Mode" + def test_unit(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::TestUnitRunner.run(arguments) + end + + desc "spinach ['arguments']", "Parallelize Spinach with Knapsack Pro in Regular Mode" + def spinach(arguments = "") + require "knapsack_pro" + KnapsackPro::Runners::SpinachRunner.run(arguments) + end + + desc "retry [-b] [-- test_runner_args]", "Retry the tests that failed on the previous Knapsack Pro run on BRANCH." + long_desc <<~DESC + \x5knapsack_pro retry + \x5knapsack_pro retry --branch feature -- --format progress + DESC + option :branch, type: :string, aliases: :b, desc: "Default: current branch." + def retry(*runner_args) + test_examples = fetch_test_examples + return (puts "Nothing to run") if test_examples.size.zero? + + puts "Retrying #{test_examples.size} test examples..." + exec Gem.bin_path("rspec-core", "rspec"), *(runner_args + test_examples) + end + + private + + def fetch_test_examples + require "json" + require "net/http" + require "knapsack_pro/config/env" + + branch = options[:branch] || `git branch --show-current`.chomp + puts "Branch: #{branch}" + + headers = { + 'Accept' => 'application/json', + 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") + } + + uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/paths") + uri.query = URI.encode_www_form(branch: branch) + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == 'https') + http.open_timeout = 5 + http.read_timeout = 5 + + response = http.get(uri, headers) + abort response.inspect if (300..).cover?(response.code.to_i) + + parsed = JSON.parse(response.body) + abort parsed.inspect if parsed['errors'] + + parsed.fetch('paths') + end + end +end + +KnapsackPro::Commands.start(ARGV) diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index aefe9ea4..b979d202 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "logger" + module KnapsackPro module Config class Env From 03daeb91d4b9e1f707ea2d1548802c98e7464be1 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 27 Aug 2025 13:23:20 +0200 Subject: [PATCH 05/29] feat: add missing frozen_string_literal --- lib/knapsack_pro/commands.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index b6807832..0ab1251b 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "thor" module KnapsackPro From 7bd6a6eedcdb790084cb9a62ffdb6211200e71aa Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Mon, 24 Nov 2025 18:40:19 +0100 Subject: [PATCH 06/29] bk --- lib/knapsack_pro/config/ci/buildkite.rb | 4 ++++ spec/knapsack_pro/config/ci/buildkite_spec.rb | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/knapsack_pro/config/ci/buildkite.rb b/lib/knapsack_pro/config/ci/buildkite.rb index 745c1960..a5dc9997 100644 --- a/lib/knapsack_pro/config/ci/buildkite.rb +++ b/lib/knapsack_pro/config/ci/buildkite.rb @@ -47,6 +47,10 @@ def fixed_queue_split def ci_provider "Buildkite" end + + def test_queue_id + node_build_id # BUILDKITE_BUILD_ID or BUILDKITE_STEP_ID may work too + end end end end diff --git a/spec/knapsack_pro/config/ci/buildkite_spec.rb b/spec/knapsack_pro/config/ci/buildkite_spec.rb index 51f329b1..174afc4a 100644 --- a/spec/knapsack_pro/config/ci/buildkite_spec.rb +++ b/spec/knapsack_pro/config/ci/buildkite_spec.rb @@ -132,4 +132,17 @@ it { should be nil } end end + + [ + [{ 'BUILDKITE_BUILD_NUMBER' => '123' }, '123'], + [{}, nil] + ].each do |env, expected| + describe '#test_queue_id' do + subject { described_class.new.test_queue_id } + + let(:env) { env } + + it { should eql expected } + end + end end From c08b640488c81d6fe2880e54ba6cd07a2ea8a8dd Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Thu, 8 Jan 2026 11:16:12 +0100 Subject: [PATCH 07/29] feat(rof): rake task to initialize queue --- .circleci/config.yml | 3 +- lib/knapsack_pro/client/api/v2/queues.rb | 45 +++++++++++++++---- lib/knapsack_pro/queue_initializer.rb | 2 +- lib/tasks/queue/rspec.rake | 2 + rails-app-with-knapsack_pro/Gemfile.lock | 3 +- .../bin/knapsack_pro_queue_rspec | 4 +- .../knapsack_pro/client/api/v2/queues_spec.rb | 5 --- 7 files changed, 45 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6f9714ee..505ddc01 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -324,7 +324,8 @@ jobs: working_directory: ~/knapsack_pro-ruby/rails-app-with-knapsack_pro command: | # separate queue initialization - export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue-init" + export KNAPSACK_PRO_TEST_QUEUE_ID="<< pipeline.number >>:$CIRCLE_JOB--queue--init" + export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--<< pipeline.number >>:$CIRCLE_JOB--queue--init" bundle exec rake knapsack_pro:queue:rspec:initialize bundle exec rake knapsack_pro:queue:rspec diff --git a/lib/knapsack_pro/client/api/v2/queues.rb b/lib/knapsack_pro/client/api/v2/queues.rb index cbfc82e5..06bb9e55 100644 --- a/lib/knapsack_pro/client/api/v2/queues.rb +++ b/lib/knapsack_pro/client/api/v2/queues.rb @@ -10,24 +10,23 @@ class Queues < KnapsackPro::Client::API::V1::Base class << self def queue(args) request_hash = { - fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split, - can_initialize_queue: args.fetch(:can_initialize_queue), attempt_connect_to_queue: args.fetch(:attempt_connect_to_queue), - commit_hash: args.fetch(:commit_hash), + batch_uuid: args.fetch(:batch_uuid), branch: args.fetch(:branch), - node_total: args.fetch(:node_total), + can_initialize_queue: args.fetch(:can_initialize_queue), + commit_hash: args.fetch(:commit_hash), node_index: args.fetch(:node_index), - user_seat: KnapsackPro::Config::Env.masked_user_seat, - test_queue_id: KnapsackPro::Config::Env.test_queue_id, + node_total: args.fetch(:node_total), node_uuid: KnapsackPro::Config::Env.node_uuid, - batch_uuid: args.fetch(:batch_uuid) + test_queue_id: KnapsackPro::Config::Env.test_queue_id, + user_seat: KnapsackPro::Config::Env.masked_user_seat } if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] request_hash.merge!( - test_files: args.fetch(:test_files), build_author: KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author, - commit_authors: KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors + commit_authors: KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors, + test_files: args.fetch(:test_files) ) end @@ -43,6 +42,34 @@ def queue(args) request_hash: request_hash ) end + + def initialize(paths) + git_adapter = KnapsackPro::RepositoryAdapters::GitAdapter.new + repository_adapter = KnapsackPro::RepositoryAdapterInitiator.call + + request_hash = { + attempt_connect_to_queue: false, + batch_uuid: SecureRandom.uuid, + branch: KnapsackPro::Crypto::BranchEncryptor.call(repository_adapter.branch), + build_author: git_adapter.build_author, + can_initialize_queue: true, + commit_authors: git_adapter.commit_authors, + commit_hash: repository_adapter.commit_hash, + node_index: KnapsackPro::Config::Env.ci_node_index, + node_total: KnapsackPro::Config::Env.ci_node_total, + node_uuid: SecureRandom.uuid, + skip_pull: true, + test_files: KnapsackPro::Crypto::Encryptor.call(paths), + test_queue_id: KnapsackPro::Config::Env.test_queue_id, + user_seat: KnapsackPro::Config::Env.masked_user_seat, + } + + action_class.new( + endpoint_path: '/v2/queues/queue', + http_method: :post, + request_hash: request_hash + ) + end end end end diff --git a/lib/knapsack_pro/queue_initializer.rb b/lib/knapsack_pro/queue_initializer.rb index 3ff3574b..3817a8a1 100644 --- a/lib/knapsack_pro/queue_initializer.rb +++ b/lib/knapsack_pro/queue_initializer.rb @@ -9,7 +9,7 @@ def call(args) paths = KnapsackPro::Adapters::RSpecAdapter.concat_paths(all_test_files_to_run, slow_id_paths) raise 'No paths to run' if paths.empty? - action = KnapsackPro::Client::API::V1::Queues.initialize(paths) + action = KnapsackPro::Client::API::V2::Queues.initialize(paths) connection = KnapsackPro::Client::Connection.new(action) response = connection.call return unless response.key?('url') # Race to initialize lost to another parallel node diff --git a/lib/tasks/queue/rspec.rake b/lib/tasks/queue/rspec.rake index 4c2303ea..b8893189 100644 --- a/lib/tasks/queue/rspec.rake +++ b/lib/tasks/queue/rspec.rake @@ -10,6 +10,7 @@ namespace :knapsack_pro do task :rspec_go, [:rspec_args] do |_, args| Rake::Task.clear + ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = KnapsackPro::Config::Env.test_queue_id # Needed by queue_allocator_builder (and ignored in this code path) KnapsackPro::Runners::Queue::RSpecRunner.run(args[:rspec_args]) end @@ -20,6 +21,7 @@ namespace :knapsack_pro do ENV.delete('SPEC_OPTS') # Ignore `SPEC_OPTS` to not affect the RSpec execution within this rake task ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec + ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = KnapsackPro::Config::Env.test_queue_id # Needed by build_distributions#last KnapsackPro::RSpec::QueueInitializer.new.call(args[:rspec_args].to_s) end diff --git a/rails-app-with-knapsack_pro/Gemfile.lock b/rails-app-with-knapsack_pro/Gemfile.lock index 8a0ec4e3..ae662afb 100644 --- a/rails-app-with-knapsack_pro/Gemfile.lock +++ b/rails-app-with-knapsack_pro/Gemfile.lock @@ -111,8 +111,9 @@ GIT PATH remote: .. specs: - knapsack_pro (9.2.1) +: knapsack_pro (9.2.1) rake + thor (~> 1.4) GEM remote: https://rubygems.org/ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec index 0f21c919..0bd73674 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,6 +8,6 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_LOG_LEVEL=debug \ bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/spec/knapsack_pro/client/api/v2/queues_spec.rb b/spec/knapsack_pro/client/api/v2/queues_spec.rb index 6fa42cf1..25e7b2d8 100644 --- a/spec/knapsack_pro/client/api/v2/queues_spec.rb +++ b/spec/knapsack_pro/client/api/v2/queues_spec.rb @@ -1,6 +1,5 @@ describe KnapsackPro::Client::API::V2::Queues do describe '.queue' do - let(:fixed_queue_split) { double } let(:commit_hash) { double } let(:branch) { double } let(:node_total) { double } @@ -14,7 +13,6 @@ let(:batch_uuid) { SecureRandom.uuid } before(:each) do - expect(KnapsackPro::Config::Env).to receive(:fixed_queue_split).and_return(fixed_queue_split) expect(KnapsackPro::Config::Env).to receive(:masked_user_seat).and_return(masked_user_seat) expect(KnapsackPro::Config::Env).to receive(:test_queue_id).and_return(test_queue_id) expect(KnapsackPro::Config::Env).to receive(:node_uuid).and_return(node_uuid) @@ -29,7 +27,6 @@ endpoint_path: '/v2/queues/queue', http_method: :post, request_hash: { - fixed_queue_split: fixed_queue_split, can_initialize_queue: true, attempt_connect_to_queue: true, commit_hash: commit_hash, @@ -74,7 +71,6 @@ endpoint_path: '/v2/queues/queue', http_method: :post, request_hash: { - fixed_queue_split: fixed_queue_split, can_initialize_queue: true, attempt_connect_to_queue: false, commit_hash: commit_hash, @@ -116,7 +112,6 @@ endpoint_path: '/v2/queues/queue', http_method: :post, request_hash: { - fixed_queue_split: fixed_queue_split, can_initialize_queue: false, attempt_connect_to_queue: false, commit_hash: commit_hash, From 265ba096b9ff7586308c276f156bafa6189c4131 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Fri, 9 Jan 2026 17:26:21 +0100 Subject: [PATCH 08/29] feat(rof): fall back to triplet when no id --- lib/knapsack_pro/config/env.rb | 19 ++++++-- spec/knapsack_pro/config/env_spec.rb | 65 +++++++++++++++------------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index b979d202..d11a8495 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -263,9 +263,22 @@ def fallback_mode_error_exit_code end def test_queue_id - env_name = 'KNAPSACK_PRO_TEST_QUEUE_ID' - env_for(env_name, :test_queue_id) || - raise("Missing environment variable #{env_name}. Read more at #{KnapsackPro::Urls::KNAPSACK_PRO_TEST_QUEUE_ID}") + knapsack_env_name = 'KNAPSACK_PRO_TEST_QUEUE_ID' + knapsack_env_value = ENV[knapsack_env_name] + + ci_env_value = detected_ci.new.test_queue_id + + if !knapsack_env_value.nil? && !ci_env_value.nil? && knapsack_env_value != ci_env_value.to_s + warn("You have set the environment variable #{knapsack_env_name} to #{knapsack_env_value} which could be automatically determined from the CI environment as #{ci_env_value}.") + end + + id = knapsack_env_value != nil ? knapsack_env_value : ci_env_value + return id unless id.nil? + + triplet = [ci_node_total, branch, commit_hash] + return triplet.join('-') if triplet.all? + + raise("Missing test_queue_id. See: #{KnapsackPro::Urls::KNAPSACK_PRO_TEST_QUEUE_ID}") end def node_uuid diff --git a/spec/knapsack_pro/config/env_spec.rb b/spec/knapsack_pro/config/env_spec.rb index ce855c6f..5e33d6b6 100644 --- a/spec/knapsack_pro/config/env_spec.rb +++ b/spec/knapsack_pro/config/env_spec.rb @@ -1223,53 +1223,58 @@ describe '.test_queue_id' do subject { described_class.test_queue_id } - context 'when KNAPSACK_PRO_TEST_QUEUE_ID has value' do - before { stub_const("ENV", { 'KNAPSACK_PRO_TEST_QUEUE_ID' => '123:456' }) } - it { should eq '123:456' } - end - - context 'when CI environment has value' do - before do - expect(described_class).to receive(:ci_env_for).with(:test_queue_id).and_return('abc:def') - end - - it { should eq 'abc:def' } - end + [ + [{ 'BUILDKITE' => 'true', 'BUILDKITE_BUILD_NUMBER' => 'abc:123' }, 'abc:123'], + [{ 'CIRCLECI' => 'true', 'CIRCLE_PIPELINE_NUMBER' => 'abc:123' }, 'abc:123'], + [{ 'GITHUB_ACTIONS' => 'true', 'GITHUB_RUN_ID' => 'abc:123' }, 'abc:123'], + [{ 'GITLAB_CI' => 'true', 'CI_PIPELINE_ID' => 'abc:123' }, 'abc:123'], + ].each do |env, expected| + context "when CI provides an id" do + before { stub_const("ENV", env) } - context 'when both KNAPSACK_PRO_TEST_QUEUE_ID and CI environment have value' do - before do - stub_const("ENV", { 'KNAPSACK_PRO_TEST_QUEUE_ID' => env_value }) - expect(described_class).to receive(:ci_env_for).with(:test_queue_id).and_return(ci_value) + it do + expect(subject).to eq(expected) + end end - context 'when values are different' do - let(:env_value) { '123:456' } - let(:ci_value) { 'abc:def' } + context "when CI provides an id and KNAPSACK_PRO_TEST_QUEUE_ID is set" do + before { stub_const("ENV", env.merge('KNAPSACK_PRO_TEST_QUEUE_ID' => 'env:456')) } - it { should eq '123:456' } + it "uses KNAPSACK_PRO_TEST_QUEUE_ID" do + expect(subject).to eq('env:456') + end it 'logs a warning' do expect(described_class).to receive(:warn).with( - 'You have set the environment variable KNAPSACK_PRO_TEST_QUEUE_ID to 123:456 which could be automatically determined from the CI environment as abc:def.' + 'You have set the environment variable KNAPSACK_PRO_TEST_QUEUE_ID to env:456 which could be automatically determined from the CI environment as abc:123.' ) subject end end + end - context 'when values are the same' do - let(:env_value) { '123:456' } - let(:ci_value) { '123:456' } + [ + [{ 'CIRCLECI' => 'true', 'CIRCLE_NODE_TOTAL' => 2, 'CIRCLE_BRANCH' => "feature-branch", 'CIRCLE_SHA1' => "ab153653b065dbf22d2caad1bab39d26aa48b883" }, '2-feature-branch-ab153653b065dbf22d2caad1bab39d26aa48b883'], + ].each do |env, expected| + context "when CI does not provide an id" do + before { stub_const("ENV", env) } - it 'does not log a warning' do - expect(described_class).not_to receive(:warn) - subject + it "uses the triplet" do + expect(subject).to eq(expected) end end end - context "when ENV does not exist" do - it 'raises' do - expect { subject }.to raise_error(/Missing environment variable KNAPSACK_PRO_TEST_QUEUE_ID/) + [ + { 'CIRCLECI' => 'true', 'CIRCLE_NODE_TOTAL' => 2, 'CIRCLE_SHA1' => "ab153653b065dbf22d2caad1bab39d26aa48b883" }, + { 'CIRCLECI' => 'true', 'CIRCLE_NODE_TOTAL' => 2, 'CIRCLE_BRANCH' => "feature-branch" } + ].each do |env| + context "when triplet cannot be calculated" do + before { stub_const("ENV", env) } + + it 'raises' do + expect { subject }.to raise_error(/Missing test_queue_id/) + end end end end From 713333151664cf90bc58a2654a01034552d3fc73 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Mon, 12 Jan 2026 11:53:59 +0100 Subject: [PATCH 09/29] test(rails-app): update gems with c extensions to fix build issues --- rails-app-with-knapsack_pro/Gemfile.lock | 36 +----------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/rails-app-with-knapsack_pro/Gemfile.lock b/rails-app-with-knapsack_pro/Gemfile.lock index ae662afb..9e504fa6 100644 --- a/rails-app-with-knapsack_pro/Gemfile.lock +++ b/rails-app-with-knapsack_pro/Gemfile.lock @@ -111,7 +111,7 @@ GIT PATH remote: .. specs: -: knapsack_pro (9.2.1) + knapsack_pro (9.2.1) rake thor (~> 1.4) @@ -219,13 +219,7 @@ GEM erubi (1.13.1) et-orbi (1.4.0) tzinfo - ffi (1.17.3-aarch64-linux-gnu) - ffi (1.17.3-aarch64-linux-musl) - ffi (1.17.3-arm-linux-gnu) - ffi (1.17.3-arm-linux-musl) ffi (1.17.3-x86_64-darwin) - ffi (1.17.3-x86_64-linux-gnu) - ffi (1.17.3-x86_64-linux-musl) fiber-annotation (0.2.0) fiber-local (1.0.0) fugit (1.12.1) @@ -311,20 +305,8 @@ GEM net-protocol net-ssh (7.3.0) nio4r (2.7.5) - nokogiri (1.19.0-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.0-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.19.0-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.0-arm-linux-musl) - racc (~> 1.4) nokogiri (1.19.0-x86_64-darwin) racc (~> 1.4) - nokogiri (1.19.0-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.0-x86_64-linux-musl) - racc (~> 1.4) ostruct (0.6.3) ox (2.14.23) bigdecimal (>= 3.0) @@ -489,13 +471,7 @@ GEM spring (>= 0.9.1) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sqlite3 (2.9.0-aarch64-linux-gnu) - sqlite3 (2.9.0-aarch64-linux-musl) - sqlite3 (2.9.0-arm-linux-gnu) - sqlite3 (2.9.0-arm-linux-musl) sqlite3 (2.9.0-x86_64-darwin) - sqlite3 (2.9.0-x86_64-linux-gnu) - sqlite3 (2.9.0-x86_64-linux-musl) sshkit (1.25.0) base64 logger @@ -529,9 +505,7 @@ GEM test-unit (>= 2.5.2) thor (1.4.0) thruster (0.1.17) - thruster (0.1.17-aarch64-linux) thruster (0.1.17-x86_64-darwin) - thruster (0.1.17-x86_64-linux) timecop (0.9.10) timeout (0.6.0) timers (4.4.0) @@ -569,15 +543,7 @@ GEM zeitwerk (2.7.4) PLATFORMS - aarch64-linux - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-musl x86_64-darwin-21 - x86_64-linux - x86_64-linux-gnu - x86_64-linux-musl DEPENDENCIES async From 601900e5d6601eafca0760c773d0c287899d19bb Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 14 Jan 2026 17:28:15 +0100 Subject: [PATCH 10/29] chore: remove confusing logs --- lib/knapsack_pro/report.rb | 5 ----- spec/integration/runners/queue/rspec_runner_spec.rb | 4 ---- spec/knapsack_pro/report_spec.rb | 5 ----- 3 files changed, 14 deletions(-) diff --git a/lib/knapsack_pro/report.rb b/lib/knapsack_pro/report.rb index aa368f10..d3b9600d 100644 --- a/lib/knapsack_pro/report.rb +++ b/lib/knapsack_pro/report.rb @@ -41,11 +41,6 @@ def self.save_node_queue_to_api(test_files = nil) end end - if test_files.empty? - KnapsackPro.logger.warn("No test files were executed on this CI node.") - KnapsackPro.logger.debug("This CI node likely started work late after the test files were already executed by other CI nodes consuming the queue.") - end - measured_test_files = test_files .map { |t| t['time_execution'] } .select { |time_execution| time_execution != KnapsackPro::Tracker::DEFAULT_TEST_FILE_TIME } diff --git a/spec/integration/runners/queue/rspec_runner_spec.rb b/spec/integration/runners/queue/rspec_runner_spec.rb index a67603dc..da83b3e2 100644 --- a/spec/integration/runners/queue/rspec_runner_spec.rb +++ b/spec/integration/runners/queue/rspec_runner_spec.rb @@ -1579,8 +1579,6 @@ def when_first_matching_example_defined(type:) actual = subject expect(actual.stdout).to include('0 examples, 0 failures') - expect(actual.stdout).to include('WARN -- knapsack_pro: No test files were executed on this CI node.') - expect(actual.stdout).to include('DEBUG -- knapsack_pro: This CI node likely started work late after the test files were already executed by other CI nodes consuming the queue.') expect(actual.exit_code).to eq 0 end @@ -1604,8 +1602,6 @@ def when_first_matching_example_defined(type:) actual = subject expect(actual.stdout).to include('0 examples, 0 failures') - expect(actual.stdout).to include('WARN -- knapsack_pro: No test files were executed on this CI node.') - expect(actual.stdout).to include('DEBUG -- knapsack_pro: This CI node likely started work late after the test files were already executed by other CI nodes consuming the queue.') expect(actual.exit_code).to eq 0 end diff --git a/spec/knapsack_pro/report_spec.rb b/spec/knapsack_pro/report_spec.rb index 68cb789a..5567d468 100644 --- a/spec/knapsack_pro/report_spec.rb +++ b/spec/knapsack_pro/report_spec.rb @@ -127,11 +127,6 @@ end it 'logs warning about reasons why no test files were executed on this CI node' do - logger = instance_double(Logger) - expect(KnapsackPro).to receive(:logger).exactly(2).and_return(logger) - expect(logger).to receive(:warn).with('No test files were executed on this CI node.') - expect(logger).to receive(:debug).with('This CI node likely started work late after the test files were already executed by other CI nodes consuming the queue.') - expect(described_class).to receive(:create_build_subset).with([]) subject From 6ee16f8e03b7e31bb19e4eb50c8c81191034c834 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Mon, 12 Jan 2026 12:26:35 +0100 Subject: [PATCH 11/29] refactor: better naming --- lib/knapsack_pro/formatters/time_tracker.rb | 2 +- lib/knapsack_pro/queue_allocator.rb | 2 +- spec/knapsack_pro/formatters/time_tracker_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/knapsack_pro/formatters/time_tracker.rb b/lib/knapsack_pro/formatters/time_tracker.rb index 22dd4538..18c3daa9 100644 --- a/lib/knapsack_pro/formatters/time_tracker.rb +++ b/lib/knapsack_pro/formatters/time_tracker.rb @@ -28,7 +28,7 @@ def initialize(_output) @current_batch_failed_examples = [] end - def failed_test_id_paths + def current_batch_failed_id_paths @current_batch_failed_examples.map { |example| KnapsackPro::TestFileCleaner.clean(example.id) } end diff --git a/lib/knapsack_pro/queue_allocator.rb b/lib/knapsack_pro/queue_allocator.rb index 45d99b9b..a54f75c2 100644 --- a/lib/knapsack_pro/queue_allocator.rb +++ b/lib/knapsack_pro/queue_allocator.rb @@ -113,7 +113,7 @@ def build_action_v2(can_initialize_queue:, attempt_connect_to_queue:, time_track node_total: ci_node_total, node_index: ci_node_index, test_files: test_files, - failed_paths: time_tracker.failed_test_id_paths, + failed_paths: time_tracker.current_batch_failed_id_paths, batch_uuid: batch_uuid ) end diff --git a/spec/knapsack_pro/formatters/time_tracker_spec.rb b/spec/knapsack_pro/formatters/time_tracker_spec.rb index 0c40002d..b3b0e8e4 100644 --- a/spec/knapsack_pro/formatters/time_tracker_spec.rb +++ b/spec/knapsack_pro/formatters/time_tracker_spec.rb @@ -432,8 +432,8 @@ end end - describe '#failed_test_id_paths' do - it 'returns the most recent failed_test_id_paths' do + describe '#current_batch_failed_id_paths' do + it 'returns the most recent current_batch_failed_id_paths' do spec0 = <<~SPEC RSpec.configure do |config| config.before(:all) do @@ -464,7 +464,7 @@ end SPEC - run_specs([spec0, spec1], 'failed_test_id_paths') do |spec_paths, id_paths| + run_specs([spec0, spec1], 'current_batch_failed_id_paths') do |spec_paths, id_paths| expect(id_paths.size).to eq(1) expect(id_paths[0]).to eq("#{spec_paths[1]}[1:1]") end From 9927007c7dceb702a77539726bd9dcf8e4e987cb Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 16:17:41 +0100 Subject: [PATCH 12/29] perf: avoid double init --- lib/knapsack_pro/client/api/v2/queues.rb | 6 ++++-- spec/knapsack_pro/client/api/v2/queues_spec.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/knapsack_pro/client/api/v2/queues.rb b/lib/knapsack_pro/client/api/v2/queues.rb index 06bb9e55..fcc1c86f 100644 --- a/lib/knapsack_pro/client/api/v2/queues.rb +++ b/lib/knapsack_pro/client/api/v2/queues.rb @@ -23,9 +23,11 @@ def queue(args) } if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] + git_adapter = KnapsackPro::RepositoryAdapters::GitAdapter.new + request_hash.merge!( - build_author: KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author, - commit_authors: KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors, + build_author: git_adapter.build_author, + commit_authors: git_adapter.commit_authors, test_files: args.fetch(:test_files) ) end diff --git a/spec/knapsack_pro/client/api/v2/queues_spec.rb b/spec/knapsack_pro/client/api/v2/queues_spec.rb index 25e7b2d8..a59eebae 100644 --- a/spec/knapsack_pro/client/api/v2/queues_spec.rb +++ b/spec/knapsack_pro/client/api/v2/queues_spec.rb @@ -14,8 +14,8 @@ before(:each) do expect(KnapsackPro::Config::Env).to receive(:masked_user_seat).and_return(masked_user_seat) - expect(KnapsackPro::Config::Env).to receive(:test_queue_id).and_return(test_queue_id) expect(KnapsackPro::Config::Env).to receive(:node_uuid).and_return(node_uuid) + expect(KnapsackPro::Config::Env).to receive(:test_queue_id).and_return(test_queue_id) end context 'when can_initialize_queue=true and attempt_connect_to_queue=true' do From a0229a32da1e4c5ea756668b16883790656d19ec Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 14 Jan 2026 09:50:37 +0100 Subject: [PATCH 13/29] build: update bundler (to remove warns) --- rails-app-with-knapsack_pro/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rails-app-with-knapsack_pro/Gemfile.lock b/rails-app-with-knapsack_pro/Gemfile.lock index 9e504fa6..31c3e764 100644 --- a/rails-app-with-knapsack_pro/Gemfile.lock +++ b/rails-app-with-knapsack_pro/Gemfile.lock @@ -597,4 +597,4 @@ DEPENDENCIES webmock BUNDLED WITH - 2.6.9 + 4.0.3 From 86e42dc331773efb863cb7c7a616eb69c22e94bf Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 14 Jan 2026 10:18:53 +0100 Subject: [PATCH 14/29] chore: update bin scripts --- .../bin/bin_knapsack_pro_queue_rspec | 4 ++-- .../bin/bin_knapsack_pro_rspec | 1 + .../knapsack_pro_queue_rspec_in_background | 2 +- .../knapsack_pro_queue_rspec_missing_constant | 17 +++-------------- .../knapsack_pro_queue_rspec_record_first_run | 10 ++++------ ...o_queue_rspec_record_first_run_for_new_build | 6 ++---- .../bin/knapsack_pro_a_few_commands | 2 +- ...ueue_consumed_at_least_once_with_ci_build_id | 14 ++++++-------- .../bin/knapsack_pro_fixed_queue_split_rspec | 5 ++--- ...fixed_queue_split_rspec_custom_branch_commit | 5 ++--- ...apsack_pro_fixed_queue_split_rspec_encrypted | 5 ++--- ...ueue_split_rspec_fallback_mode_ci_node_retry | 10 ++-------- .../knapsack_pro_queue_rspec_default_formatter | 4 ++-- .../bin/knapsack_pro_queue_rspec_encrypted | 4 ++-- ...o_queue_rspec_frequently_changing_test_files | 6 +++--- .../knapsack_pro_queue_rspec_initialized_once | 8 ++++---- .../bin/knapsack_pro_queue_rspec_json | 4 ++-- .../bin/knapsack_pro_queue_rspec_junit | 4 ++-- ..._queue_rspec_junit_with_rspec_custom_options | 4 ++-- .../bin/knapsack_pro_queue_rspec_log_dir | 4 ++-- .../bin/knapsack_pro_queue_rspec_only_failures | 4 ++-- .../bin/knapsack_pro_queue_rspec_order_defined | 4 ++-- .../bin/knapsack_pro_queue_rspec_order_rand | 4 ++-- ..._pro_queue_rspec_order_rand_with_custom_seed | 4 ++-- .../bin/knapsack_pro_queue_rspec_order_random | 4 ++-- ...o_queue_rspec_order_random_defined_in_config | 4 ++-- .../knapsack_pro_queue_rspec_profile_formatter | 4 ++-- .../knapsack_pro_queue_rspec_record_first_run | 8 +++----- ...psack_pro_queue_rspec_record_first_run_junit | 7 +++---- ...psack_pro_queue_rspec_split_by_test_examples | 4 ++-- ...rspec_split_by_test_examples_above_threshold | 4 ++-- ...by_test_examples_measure_individual_examples | 6 +++--- ...queue_rspec_split_by_test_examples_spec_opts | 7 ++----- ...y_test_examples_test_example_detector_prefix | 4 ++-- ...ue_rspec_split_by_test_examples_unique_build | 4 ++-- .../bin/knapsack_pro_queue_rspec_tags | 4 ++-- .../bin/knapsack_pro_queue_rspec_test_dir | 4 ++-- ...ck_pro_queue_rspec_test_file_exclude_pattern | 4 ++-- .../bin/knapsack_pro_queue_rspec_test_file_list | 4 ++-- ...k_pro_queue_rspec_test_file_list_source_file | 4 ++-- .../knapsack_pro_queue_rspec_unique_build_id | 15 --------------- .../bin/knapsack_pro_queue_rspec_user_seat | 4 ++-- .../bin/knapsack_pro_queue_turnip | 6 ++---- ...knapsack_pro_split_by_test_cases_queue_rspec | 2 +- .../knapsack_pro_queue_rspec_new_build | 10 +++++----- ...napsack_pro_queue_rspec_new_build_with_retry | 14 +++++++------- 46 files changed, 107 insertions(+), 155 deletions(-) delete mode 100755 rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_unique_build_id diff --git a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_queue_rspec b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_queue_rspec index 0e93a2b2..520a0e4e 100755 --- a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_queue_rspec +++ b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_queue_rspec @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=3fa64859337f6e56409d49f865d13fd7 \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec knapsack_pro queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec index 1a310e2c..e438b49b 100755 --- a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec +++ b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec @@ -8,5 +8,6 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$CI_BUILD_ID} \ KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ bundle exec knapsack_pro rspec diff --git a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_in_background b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_in_background index 56e234d7..04bbb1f2 100755 --- a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_in_background +++ b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_in_background @@ -3,7 +3,7 @@ # run it with number at the end to bump commit hash and record unique CI build # bin/edge_cases/knapsack_pro_queue_rspec_in_background 1 -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$(openssl rand -base64 32) +export KNAPSACK_PRO_TEST_QUEUE_ID=$(openssl rand -base64 32) export KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 export KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf export KNAPSACK_PRO_CI_NODE_TOTAL=2 diff --git a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_missing_constant b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_missing_constant index b90f818c..db52394f 100755 --- a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_missing_constant +++ b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_missing_constant @@ -8,22 +8,12 @@ # # We want to test scenario when the test file won't be executed and # to the Knapsack Pro API should be send summary of tests timing with the test file. -# When KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true we expect retried CI build fail. +# We expect retried CI build fail. # We expect the test file to be run and fail. -# If you want to record a new CI build then set -# KNAPSACK_PRO_FIXED_QUEUE_SPLIT=false -# and run this file for both CI nodes. -# bin/edge_cases/knapsack_pro_queue_rspec_missing_constant 0 -# bin/edge_cases/knapsack_pro_queue_rspec_missing_constant 1 -# Then you can set -# KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true -# and run tests to see if the test file: -# spec/controllers/pending_controller_spec.rb -# was executed with error. # We expect CI node to return exit code 1 because test fails. -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -32,6 +22,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_TEST_FILE_PATTERN=spec/controllers/*_spec.rb \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[-f d]" diff --git a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run index 08c3bfab..a7c552ef 100755 --- a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run +++ b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run @@ -13,16 +13,14 @@ # CI node 1 for commit-v2 # bin/edge_cases/knapsack_pro_queue_rspec_record_first_run 1 2 commit-v1 ci-build-1 -RANDOM_CI_BUILD_ID=$(openssl rand -base64 32) -CI_BUILD_ID=${4:-$RANDOM_CI_BUILD_ID} +RANDOM_TEST_QUEUE_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=${4:-$RANDOM_TEST_QUEUE_ID} COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") BRANCH_NAME=fake-branch # you can set a const fake data if you need to test running tests on 2 CI nodes for the same commit/branch #COMMIT_HASH=57dccc53cb2ee921692ad1d3df971674 -#export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true - #export EXTRA_TEST_FILES_DELAY=10 # seconds #export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true #export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/**{,/*/**}/*_spec.rb" @@ -36,7 +34,7 @@ export MOCK_QUEUE_API_RESPONSE=true KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=${3:-$COMMIT_HASH} \ KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ @@ -59,7 +57,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ # Uncomment the following to run 2nd CI node to ensure the CI build is finished in the user dashboard #KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ #KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - #KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + #KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ #KNAPSACK_PRO_COMMIT_HASH=${3:-$COMMIT_HASH} \ #KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ #KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ diff --git a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run_for_new_build b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run_for_new_build index cf53bddf..692d8b6f 100755 --- a/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run_for_new_build +++ b/rails-app-with-knapsack_pro/bin/edge_cases/knapsack_pro_queue_rspec_record_first_run_for_new_build @@ -8,15 +8,13 @@ # This file can be used to test how to optimise the first run of Queue Mode # You must set a unique CI build ID, commit hash or branch. -CI_BUILD_ID=2023-08-28-v5 +TEST_QUEUE_ID=2023-08-28-v5 COMMIT_HASH=abc1234 BRANCH_NAME=redis-test -export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=false - KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=$COMMIT_HASH \ KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_a_few_commands b/rails-app-with-knapsack_pro/bin/knapsack_pro_a_few_commands index 5ba7dedc..462d49e1 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_a_few_commands +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_a_few_commands @@ -19,7 +19,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$CI_BUILD_ID} \ bundle exec rake "knapsack_pro:queue:rspec[-f d]" export KNAPSACK_PRO_EXIT_CODE_2=$? diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_rspec_queue_consumed_at_least_once_with_ci_build_id b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_rspec_queue_consumed_at_least_once_with_ci_build_id index f0bf905f..6f0a0242 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_rspec_queue_consumed_at_least_once_with_ci_build_id +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_rspec_queue_consumed_at_least_once_with_ci_build_id @@ -1,16 +1,15 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) # we use random branch name in order to create a new Build record on API side KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ - KNAPSACK_PRO_BRANCH=branch-$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ + KNAPSACK_PRO_BRANCH=branch-$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=commit-v1 \ KNAPSACK_PRO_CI_NODE_TOTAL=2 \ KNAPSACK_PRO_CI_NODE_INDEX=0 \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ bundle exec rake knapsack_pro:queue:rspec # We expect: @@ -25,15 +24,14 @@ echo echo ======================================== echo -# This should not execute tests because Knapsack Pro API won't allow to initialize another queue for the same CI_BUILD_ID. +# This should not execute tests because Knapsack Pro API won't allow to initialize another queue for the same TEST_QUEUE_ID. KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ - KNAPSACK_PRO_BRANCH=branch-$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ + KNAPSACK_PRO_BRANCH=branch-$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=commit-v1 \ KNAPSACK_PRO_CI_NODE_TOTAL=2 \ KNAPSACK_PRO_CI_NODE_INDEX=1 \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ bundle exec rake knapsack_pro:queue:rspec # We expect: diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec index a6c16d86..c82fdfd0 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=3fa64859337f6e56409d49f865d13fd7 \ @@ -8,6 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_custom_branch_commit b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_custom_branch_commit index 05792122..caf41a7e 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_custom_branch_commit +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_custom_branch_commit @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) # 3rd argument is added as number to branch name # you can bump it to test a new recorded CI build for a new branch @@ -10,8 +10,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=3fa64859337f6e56409d49f865d13fd7 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ KNAPSACK_PRO_BRANCH=test-fixed-queue-split-v${3:-1} \ KNAPSACK_PRO_COMMIT_HASH=test-commit \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${4:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${4:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_encrypted b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_encrypted index 0770667c..362a5ba0 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_encrypted +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_encrypted @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_FILES_ENCRYPTED=true \ @@ -11,6 +11,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_fallback_mode_ci_node_retry b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_fallback_mode_ci_node_retry index 00e83e76..e52f285d 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_fallback_mode_ci_node_retry +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_fixed_queue_split_rspec_fallback_mode_ci_node_retry @@ -3,15 +3,10 @@ # this file is on purpose not listed in knapsack_pro_all.rb # because below tests will fail due to raised exception that we want to verify manually -# you can remove from below code the line: -# KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true -# thanks to that you can test scenario when knapsack_pro tells -# you to set KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true - # you can test disabling fallback mode at all # export KNAPSACK_PRO_FALLBACK_MODE_ENABLED=false -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api-fake.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=3fa64859337f6e56409d49f865d13fd7 \ @@ -19,7 +14,6 @@ KNAPSACK_PRO_ENDPOINT=http://api-fake.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true \ KNAPSACK_PRO_CI_NODE_RETRY_COUNT=1 \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_default_formatter b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_default_formatter index 94396f18..93f41d64 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_default_formatter +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_default_formatter @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_MODIFY_DEFAULT_RSPEC_FORMATTERS=false \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_encrypted b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_encrypted index e887370b..362a5ba0 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_encrypted +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_encrypted @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_FILES_ENCRYPTED=true \ @@ -11,5 +11,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_frequently_changing_test_files b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_frequently_changing_test_files index 199099e7..9726a0be 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_frequently_changing_test_files +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_frequently_changing_test_files @@ -19,7 +19,7 @@ echo # Run all test files in the test suite. # The commands below should record time execution for all test files. -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$(openssl rand -base64 32) +export KNAPSACK_PRO_TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_CI_NODE_INDEX=0 \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation]" @@ -36,7 +36,7 @@ echo # Run only controllers' specs. # Expect Queue API to return test files ordered by time execution recorded in the previous CI build run. -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$(openssl rand -base64 32) +export KNAPSACK_PRO_TEST_QUEUE_ID=$(openssl rand -base64 32) export KNAPSACK_PRO_TEST_FILE_PATTERN="spec/controllers/**{,/*/**}/*_spec.rb" KNAPSACK_PRO_CI_NODE_INDEX=0 \ @@ -55,7 +55,7 @@ echo # In the previous CI build, we recorded time execution for controllers' specs only. # Despite that, we expect the Queue API will return services specs ordered based on ever recorded # services specs' time execution. -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$(openssl rand -base64 32) +export KNAPSACK_PRO_TEST_QUEUE_ID=$(openssl rand -base64 32) export KNAPSACK_PRO_TEST_FILE_PATTERN="spec/services/**{,/*/**}/*_spec.rb" KNAPSACK_PRO_CI_NODE_INDEX=0 \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_initialized_once b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_initialized_once index 44a19481..10b488c9 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_initialized_once +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_initialized_once @@ -1,12 +1,12 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ KNAPSACK_PRO_PROJECT_DIR=. \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ bundle exec rake knapsack_pro:queue:rspec @@ -16,12 +16,12 @@ echo echo ======================================== echo -# This should not execute tests because Knapsack Pro API won't allow to initialize another queue for the same CI_BUILD_ID. +# This should not execute tests because Knapsack Pro API won't allow to initialize another queue for the same TEST_QUEUE_ID. KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ KNAPSACK_PRO_PROJECT_DIR=. \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_json b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_json index 504eecb1..e9ddef84 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_json +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_json @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) mkdir -p tmp/test-reports/rspec/queue_mode/ @@ -12,5 +12,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation --format json --out tmp/test-reports/rspec/queue_mode/rspec_$KNAPSACK_PRO_CI_NODE_INDEX.json]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit index e66adc06..b6c59559 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit @@ -5,12 +5,12 @@ mkdir -p tmp/test-reports/rspec/queue_mode/ # must be exported to read value in below knapsack_pro command export KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation --format RspecJunitFormatter --out tmp/test-reports/rspec/queue_mode/rspec_$KNAPSACK_PRO_CI_NODE_INDEX.xml]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit_with_rspec_custom_options b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit_with_rspec_custom_options index 67972beb..18c262b1 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit_with_rspec_custom_options +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_junit_with_rspec_custom_options @@ -5,7 +5,7 @@ mkdir -p tmp/test-reports/rspec/queue_mode/ # must be exported to read value in below knapsack_pro command export KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) export RSPEC_CUSTOM_OPTIONS_ENABLED=true @@ -14,5 +14,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--options .rspec_custom.options --format RspecJunitFormatter --out tmp/test-reports/rspec/queue_mode/rspec_$KNAPSACK_PRO_CI_NODE_INDEX.xml]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_log_dir b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_log_dir index 46cb620a..d7f6c11e 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_log_dir +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_log_dir @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_LOG_DIR=log \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[-f d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_only_failures b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_only_failures index ac813889..c65f3c8c 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_only_failures +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_only_failures @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,7 +8,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec # run only failed tests to retry them diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_defined b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_defined index 1c3e9fb7..fb000fef 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_defined +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_defined @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--order defined]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand index 2c44f544..837c96ea 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--order rand]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand_with_custom_seed b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand_with_custom_seed index f4cf8b63..cbaff55a 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand_with_custom_seed +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_rand_with_custom_seed @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--order rand:123]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random index a0eac6f6..5cb83b85 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--order random]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random_defined_in_config b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random_defined_in_config index 8abec1a6..acb8ca4e 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random_defined_in_config +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_order_random_defined_in_config @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ RSPEC_ORDER_RANDOM_DEFINED_IN_CONFIG=true \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake knapsack_pro:queue:rspec diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_profile_formatter b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_profile_formatter index 3a9d6634..2235a23e 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_profile_formatter +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_profile_formatter @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--profile]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run index 4a13ce8b..5f6741b9 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run @@ -13,23 +13,21 @@ # CI node 1 for commit-v2 # bin/knapsack_pro_queue_rspec_record_first_run 1 2 commit-v1 ci-build-1 -RANDOM_CI_BUILD_ID=$(openssl rand -base64 32) -CI_BUILD_ID=${4:-$RANDOM_CI_BUILD_ID} +RANDOM_TEST_QUEUE_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=${4:-$RANDOM_TEST_QUEUE_ID} COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") BRANCH_NAME=fake-branch # you can set a const fake data if you need to test running tests on 2 CI nodes for the same commit/branch #COMMIT_HASH=57dccc53cb2ee921692ad1d3df971674 -#export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true - #export EXTRA_TEST_FILES_DELAY=10 # seconds #export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true #export KNAPSACK_PRO_LOG_LEVEL=debug KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=${3:-$COMMIT_HASH} \ KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run_junit b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run_junit index 9f059534..6e654a4e 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run_junit +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_record_first_run_junit @@ -13,19 +13,18 @@ mkdir -p tmp/test-reports/rspec/queue_mode/ RANDOM_COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") COMMIT_HASH=${3:-$RANDOM_COMMIT_HASH} -RANDOM_CI_BUILD_ID=$(openssl rand -base64 32) -CI_BUILD_ID=${4:-$RANDOM_CI_BUILD_ID} +RANDOM_TEST_QUEUE_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=${4:-$RANDOM_TEST_QUEUE_ID} BRANCH_NAME=fake-junit-branch export EXTRA_TEST_FILES_DELAY=10 # seconds export KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/**{,/*/**}/*_spec.rb" -#export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=$COMMIT_HASH \ KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples index 71ab2fcd..6f95f5b1 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples @@ -6,7 +6,7 @@ #export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/**{,/*/**}/*_spec.rb" export EXTRA_TEST_FILES_DELAY=10 # seconds -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -14,6 +14,6 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true \ bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_above_threshold b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_above_threshold index 06d19f0d..42a17969 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_above_threshold +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_above_threshold @@ -1,7 +1,7 @@ #!/bin/bash export EXTRA_TEST_FILES_DELAY=10 # seconds -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,7 +9,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_LOG_LEVEL=debug \ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true \ KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD=1 \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_measure_individual_examples b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_measure_individual_examples index ed80b2b9..9b240741 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_measure_individual_examples +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_measure_individual_examples @@ -6,8 +6,8 @@ # Run tests on a single CI node: # bin/knapsack_pro_queue_rspec_split_by_test_examples_measure_individual_examples 0 1 -RANDOM_CI_BUILD_ID=$(openssl rand -base64 32) -CI_BUILD_ID=${4:-$RANDOM_CI_BUILD_ID} +RANDOM_TEST_QUEUE_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=${4:-$RANDOM_TEST_QUEUE_ID} COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") BRANCH_NAME=fake-branch @@ -17,7 +17,7 @@ export KNAPSACK_PRO_TEST_FILE_LIST=spec/features/homepage_spec.rb[1:1],spec/coll KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=fec3c641a3c4d2e720fe1b6d9dd780bc \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=$CI_BUILD_ID \ + KNAPSACK_PRO_TEST_QUEUE_ID=$TEST_QUEUE_ID \ KNAPSACK_PRO_COMMIT_HASH=${3:-$COMMIT_HASH} \ KNAPSACK_PRO_BRANCH=$BRANCH_NAME \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_spec_opts b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_spec_opts index 9469221c..deb92836 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_spec_opts +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_spec_opts @@ -1,12 +1,9 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) #export KNAPSACK_PRO_LOG_LEVEL=warn -# ensure a new queue is generated so that the split by examples is triggered (dry-run report is generated) -export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=false - # uncomment to run all tests split by examples #export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/**{,/*/**}/*_spec.rb" export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/controllers/**{,/*/**}/*_spec.rb" @@ -23,6 +20,6 @@ RAILS_ENV=test \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_test_example_detector_prefix b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_test_example_detector_prefix index e3fa932f..150b027f 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_test_example_detector_prefix +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_test_example_detector_prefix @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) #export KNAPSACK_PRO_LOG_LEVEL=warn @@ -14,5 +14,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true \ KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX="CUSTOM_VARIABLE_FOR_RSPEC_TEST_EXAMPLE_DETECTOR='custom-value'" \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_unique_build b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_unique_build index 9fe03b0f..f983bf11 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_unique_build +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_split_by_test_examples_unique_build @@ -10,7 +10,7 @@ #export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/**{,/*/**}/*_spec.rb" export EXTRA_TEST_FILES_DELAY=10 # seconds -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -18,6 +18,6 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_BRANCH=test-fixed-queue-split-v${3:-1} \ KNAPSACK_PRO_COMMIT_HASH=test-commit \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=ci-build-id-${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=ci-build-id-${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true \ bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_tags b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_tags index ada544ec..c8c28658 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_tags +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_tags @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=7f558f2ec21f9fffeb6ccb2e998dc3e5 \ @@ -8,5 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation --tag tag_a]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_dir b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_dir index a885f8ce..1672cc18 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_dir +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_dir @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -10,5 +10,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_FILE_PATTERN="{spec,engines/*/spec}/**/*_spec.rb" \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_exclude_pattern b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_exclude_pattern index 2ccaeb23..25ad2c3d 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_exclude_pattern +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_exclude_pattern @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN="spec/*_spec.rb" \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format documentation]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list index b3155072..28864a1a 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_TEST_FILE_LIST=spec/bar_spec.rb,spec/time_helpers_spec.rb:10,spec/time_helpers_spec.rb:38 \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[-f d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list_source_file b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list_source_file index 7d345758..a3fdb78d 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list_source_file +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_test_file_list_source_file @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_TEST_FILE_LIST_SOURCE_FILE=spec/fixtures/test_file_list_source_file.txt \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[-f d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_unique_build_id b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_unique_build_id deleted file mode 100755 index 852d5a89..00000000 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_unique_build_id +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# Run tests for the same CI build ID -# bin/knapsack_pro_queue_rspec_unique_build_id 0 2 build-id-2023-04-02-v1 -# bin/knapsack_pro_queue_rspec_unique_build_id 1 2 build-id-2023-04-02-v1 - -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$3 - -KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ - KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ - KNAPSACK_PRO_REPOSITORY_ADAPTER=git \ - KNAPSACK_PRO_PROJECT_DIR=. \ - KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ - KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_user_seat b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_user_seat index 7fb2c470..241d7e26 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_user_seat +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_rspec_user_seat @@ -1,6 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -9,5 +9,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ KNAPSACK_PRO_USER_SEAT="Jane Doe" \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ bundle exec rake "knapsack_pro:queue:rspec[--format d]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_turnip b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_turnip index c6dc7b9e..89032840 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_turnip +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_queue_turnip @@ -1,8 +1,6 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) - -export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=false +TEST_QUEUE_ID=$(openssl rand -base64 32) KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a28ce51204d7c7dbd25c3352fea222cf \ @@ -10,7 +8,7 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ + KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$TEST_QUEUE_ID} \ KNAPSACK_PRO_TEST_DIR=turnip \ KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature" \ bundle exec rake "knapsack_pro:queue:rspec[-r turnip/rspec]" diff --git a/rails-app-with-knapsack_pro/bin/knapsack_pro_split_by_test_cases_queue_rspec b/rails-app-with-knapsack_pro/bin/knapsack_pro_split_by_test_cases_queue_rspec index 0a11efe0..84db0e24 100755 --- a/rails-app-with-knapsack_pro/bin/knapsack_pro_split_by_test_cases_queue_rspec +++ b/rails-app-with-knapsack_pro/bin/knapsack_pro_split_by_test_cases_queue_rspec @@ -3,7 +3,7 @@ # run it with number at the end to bump commit hash and record unique CI build # bin/knapsack_pro_split_by_test_cases_queue_rspec v1 -export KNAPSACK_PRO_CI_NODE_BUILD_ID=$(openssl rand -base64 32) +export KNAPSACK_PRO_TEST_QUEUE_ID=$(openssl rand -base64 32) export KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 export KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=a998199d1f294a750c184f4f635851b9 export KNAPSACK_PRO_CI_NODE_TOTAL=2 diff --git a/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build b/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build index a943c930..87f212ed 100755 --- a/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build +++ b/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build @@ -1,9 +1,9 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") -bin/knapsack_pro_queue_rspec_record_first_run 0 4 $COMMIT_HASH $CI_BUILD_ID & -bin/knapsack_pro_queue_rspec_record_first_run 1 4 $COMMIT_HASH $CI_BUILD_ID -bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $CI_BUILD_ID & -bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $CI_BUILD_ID +bin/knapsack_pro_queue_rspec_record_first_run 0 4 $COMMIT_HASH $TEST_QUEUE_ID & +bin/knapsack_pro_queue_rspec_record_first_run 1 4 $COMMIT_HASH $TEST_QUEUE_ID +bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $TEST_QUEUE_ID & +bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $TEST_QUEUE_ID diff --git a/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build_with_retry b/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build_with_retry index 00d1dcb9..bb91d9f0 100755 --- a/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build_with_retry +++ b/rails-app-with-knapsack_pro/bin/record_many_nodes/knapsack_pro_queue_rspec_new_build_with_retry @@ -1,18 +1,18 @@ #!/bin/bash -CI_BUILD_ID=$(openssl rand -base64 32) +TEST_QUEUE_ID=$(openssl rand -base64 32) COMMIT_HASH=$(ruby -e "require 'securerandom'; puts SecureRandom.hex") -bin/knapsack_pro_queue_rspec_record_first_run 0 4 $COMMIT_HASH $CI_BUILD_ID & +bin/knapsack_pro_queue_rspec_record_first_run 0 4 $COMMIT_HASH $TEST_QUEUE_ID & sleep 1 -bin/knapsack_pro_queue_rspec_record_first_run 1 4 $COMMIT_HASH $CI_BUILD_ID & +bin/knapsack_pro_queue_rspec_record_first_run 1 4 $COMMIT_HASH $TEST_QUEUE_ID & sleep 2 -bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $CI_BUILD_ID & +bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $TEST_QUEUE_ID & sleep 1 # retry node 3 -bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $CI_BUILD_ID -bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $CI_BUILD_ID +bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $TEST_QUEUE_ID +bin/knapsack_pro_queue_rspec_record_first_run 3 4 $COMMIT_HASH $TEST_QUEUE_ID # retry node 2 -bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $CI_BUILD_ID +bin/knapsack_pro_queue_rspec_record_first_run 2 4 $COMMIT_HASH $TEST_QUEUE_ID From 34d018ce4b6114b46e8e42badce9c73510926c17 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 14 Jan 2026 15:03:25 +0100 Subject: [PATCH 15/29] chore: paths -> test_paths --- lib/knapsack_pro/commands.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index 0ab1251b..7f91ea37 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -89,7 +89,7 @@ def fetch_test_examples 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") } - uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/paths") + uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") uri.query = URI.encode_www_form(branch: branch) http = Net::HTTP.new(uri.host, uri.port) From 0ad3799e818e5b450be1d9ec7c7404dd722aa730 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 16:11:11 +0100 Subject: [PATCH 16/29] feat: tweak retry command --- exe/knapsack_pro | 2 + lib/knapsack_pro/commands.rb | 41 +--------------- .../commands/retry_failed_tests.rb | 47 +++++++++++++++++++ lib/knapsack_pro/config/env.rb | 2 - spec/knapsack_pro/commands_spec.rb | 35 ++++++++++++++ 5 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 lib/knapsack_pro/commands/retry_failed_tests.rb create mode 100644 spec/knapsack_pro/commands_spec.rb diff --git a/exe/knapsack_pro b/exe/knapsack_pro index 23c62303..24976d1c 100755 --- a/exe/knapsack_pro +++ b/exe/knapsack_pro @@ -1,3 +1,5 @@ #!/usr/bin/env ruby +require "knapsack_pro" require "knapsack_pro/commands" +KnapsackPro::Commands.start(ARGV) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index 7f91ea37..e993f1eb 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -67,45 +67,8 @@ def spinach(arguments = "") DESC option :branch, type: :string, aliases: :b, desc: "Default: current branch." def retry(*runner_args) - test_examples = fetch_test_examples - return (puts "Nothing to run") if test_examples.size.zero? - - puts "Retrying #{test_examples.size} test examples..." - exec Gem.bin_path("rspec-core", "rspec"), *(runner_args + test_examples) - end - - private - - def fetch_test_examples - require "json" - require "net/http" - require "knapsack_pro/config/env" - - branch = options[:branch] || `git branch --show-current`.chomp - puts "Branch: #{branch}" - - headers = { - 'Accept' => 'application/json', - 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") - } - - uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") - uri.query = URI.encode_www_form(branch: branch) - - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = (uri.scheme == 'https') - http.open_timeout = 5 - http.read_timeout = 5 - - response = http.get(uri, headers) - abort response.inspect if (300..).cover?(response.code.to_i) - - parsed = JSON.parse(response.body) - abort parsed.inspect if parsed['errors'] - - parsed.fetch('paths') + require_relative "./commands/retry_failed_tests" + RetryFailedTests.new(branch: options[:branch]).call(runner_args) end end end - -KnapsackPro::Commands.start(ARGV) diff --git a/lib/knapsack_pro/commands/retry_failed_tests.rb b/lib/knapsack_pro/commands/retry_failed_tests.rb new file mode 100644 index 00000000..87aefc84 --- /dev/null +++ b/lib/knapsack_pro/commands/retry_failed_tests.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require "json" +require "net/http" + +class RetryFailedTests + def initialize(branch:) + @branch = branch || `git branch --show-current`.chomp + end + + def call(runner_args) + $stderr.puts "Branch: #{branch}" + + failed_paths = fetch_failed_paths + return ($stderr.puts "Nothing to run") if failed_paths.size.zero? + + $stderr.puts "Retrying #{failed_paths.size} tests..." + exec Gem.bin_path("rspec-core", "rspec"), *(runner_args + failed_paths) + end + + private + + attr_accessor :branch + + def fetch_failed_paths + headers = { + 'Accept' => 'application/json', + 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") + } + + uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") + uri.query = URI.encode_www_form(branch: branch) + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == 'https') + http.open_timeout = 5 + http.read_timeout = 5 + + response = http.get(uri.request_uri, headers) + abort response.inspect if (300..).cover?(response.code.to_i) + + parsed = JSON.parse(response.body) + abort parsed.inspect if parsed['errors'] + + parsed.fetch('failed_paths') + end +end diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index d11a8495..8f8d1292 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "logger" - module KnapsackPro module Config class Env diff --git a/spec/knapsack_pro/commands_spec.rb b/spec/knapsack_pro/commands_spec.rb new file mode 100644 index 00000000..a9767d2e --- /dev/null +++ b/spec/knapsack_pro/commands_spec.rb @@ -0,0 +1,35 @@ +require "open3" +require "knapsack_pro/commands" +require "knapsack_pro/commands/retry_failed_tests" + +describe "commands" do + describe "retry" do + around(:each) do |example| + original = $stderr + $stderr = StringIO.new + example.run + $stdout = original + end + + it do + body = JSON.dump(failed_paths: ["spec/a_spec.rb[1:2:3]"]) + response = instance_double(Net::HTTPResponse, code: "200", body: body) + expect_any_instance_of(Net::HTTP).to receive(:get) do |_klass, path, headers| + expect(path).to eq("/v2/test_paths?branch=feature") + expect(headers).to include("KNAPSACK-PRO-TEST-SUITE-TOKEN" => "abc:123") + response + end + + expect_any_instance_of(Kernel).to receive(:exec) do |_klass, bin, *args| + expect(bin).to include("rspec") + expect(args).to eq(["--formatter", "progress", "spec/a_spec.rb[1:2:3]"]) + end + + env = { "KNAPSACK_PRO_TEST_SUITE_TOKEN" => "abc:123" } + stub_const("ENV", env) + + cmd = ["retry", "--branch", "feature", "--", "--formatter", "progress"] + KnapsackPro::Commands.start(cmd) + end + end +end From 84af173d9821bffd34249e302126751d48f7f189 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 16:11:21 +0100 Subject: [PATCH 17/29] chore: remove unused code --- lib/knapsack_pro/client/api/v1/queues.rb | 27 ------------------------ 1 file changed, 27 deletions(-) diff --git a/lib/knapsack_pro/client/api/v1/queues.rb b/lib/knapsack_pro/client/api/v1/queues.rb index 088e6107..9fa666eb 100644 --- a/lib/knapsack_pro/client/api/v1/queues.rb +++ b/lib/knapsack_pro/client/api/v1/queues.rb @@ -36,33 +36,6 @@ def queue(args) request_hash: request_hash ) end - - def initialize(paths) - git_adapter = KnapsackPro::RepositoryAdapters::GitAdapter.new - repository_adapter = KnapsackPro::RepositoryAdapterInitiator.call - - request_hash = { - attempt_connect_to_queue: false, - branch: KnapsackPro::Crypto::BranchEncryptor.call(repository_adapter.branch), - build_author: git_adapter.build_author, - can_initialize_queue: true, - commit_authors: git_adapter.commit_authors, - commit_hash: repository_adapter.commit_hash, - fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split, - node_build_id: KnapsackPro::Config::Env.ci_node_build_id, - node_index: KnapsackPro::Config::Env.ci_node_index, - node_total: KnapsackPro::Config::Env.ci_node_total, - skip_pull: true, - test_files: KnapsackPro::Crypto::Encryptor.call(paths), - user_seat: KnapsackPro::Config::Env.masked_user_seat, - } - - action_class.new( - endpoint_path: '/v1/queues/queue', - http_method: :post, - request_hash: request_hash - ) - end end end end From 04d0f1a456a69a83ec5970ba77d71adc5fc80476 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 16:11:45 +0100 Subject: [PATCH 18/29] chore: remove code comment --- lib/knapsack_pro/config/ci/buildkite.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/knapsack_pro/config/ci/buildkite.rb b/lib/knapsack_pro/config/ci/buildkite.rb index a5dc9997..d9181e6b 100644 --- a/lib/knapsack_pro/config/ci/buildkite.rb +++ b/lib/knapsack_pro/config/ci/buildkite.rb @@ -49,7 +49,7 @@ def ci_provider end def test_queue_id - node_build_id # BUILDKITE_BUILD_ID or BUILDKITE_STEP_ID may work too + node_build_id end end end From b01076fa4b7fbeb336dea34bb1660aa314345b7e Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 15:32:06 +0100 Subject: [PATCH 19/29] test: remove noise from logs --- .rspec | 2 +- .../api/build_distributions_subset_spec.rb | 12 ++++++++++++ spec/integration/api/build_subsets_create_spec.rb | 12 ++++++++++++ spec/knapsack_pro/adapters/base_adapter_spec.rb | 12 ++++++++++++ spec/knapsack_pro/adapters/rspec_adapter_spec.rb | 12 ++++++++++++ spec/knapsack_pro/build_distribution_fetcher_spec.rb | 12 ++++++++++++ spec/knapsack_pro/commands_spec.rb | 2 +- spec/knapsack_pro/config/env_spec.rb | 6 ++++++ .../runners/queue/minitest_runner_spec.rb | 12 ++++++++++++ .../rspec_test_example_detector_spec.rb | 12 ++++++++++++ 10 files changed, 92 insertions(+), 2 deletions(-) diff --git a/.rspec b/.rspec index bc9e32df..c173a4d1 100644 --- a/.rspec +++ b/.rspec @@ -1,5 +1,5 @@ --color #--warnings --require spec_helper ---format documentation +--format progress #--profile diff --git a/spec/integration/api/build_distributions_subset_spec.rb b/spec/integration/api/build_distributions_subset_spec.rb index 5c4f3be4..02131475 100644 --- a/spec/integration/api/build_distributions_subset_spec.rb +++ b/spec/integration/api/build_distributions_subset_spec.rb @@ -25,6 +25,18 @@ let(:endpoint) { valid_endpoint } let(:test_suite_token) { valid_test_suite_token } + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + before do stub_const('ENV', { 'KNAPSACK_PRO_ENDPOINT' => endpoint, diff --git a/spec/integration/api/build_subsets_create_spec.rb b/spec/integration/api/build_subsets_create_spec.rb index 8dc515ce..bdf99813 100644 --- a/spec/integration/api/build_subsets_create_spec.rb +++ b/spec/integration/api/build_subsets_create_spec.rb @@ -26,6 +26,18 @@ let(:endpoint) { valid_endpoint } let(:test_suite_token) { valid_test_suite_token } + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + before do stub_const('ENV', { 'KNAPSACK_PRO_ENDPOINT' => endpoint, diff --git a/spec/knapsack_pro/adapters/base_adapter_spec.rb b/spec/knapsack_pro/adapters/base_adapter_spec.rb index 103e341e..be4a03fc 100644 --- a/spec/knapsack_pro/adapters/base_adapter_spec.rb +++ b/spec/knapsack_pro/adapters/base_adapter_spec.rb @@ -1,4 +1,16 @@ describe KnapsackPro::Adapters::BaseAdapter do + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + it do expect(described_class::TEST_DIR_PATTERN).to eq 'test/**{,/*/**}/*_test.rb' end diff --git a/spec/knapsack_pro/adapters/rspec_adapter_spec.rb b/spec/knapsack_pro/adapters/rspec_adapter_spec.rb index dfea6c1f..25d75190 100644 --- a/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +++ b/spec/knapsack_pro/adapters/rspec_adapter_spec.rb @@ -1,6 +1,18 @@ require_relative '../../../lib/knapsack_pro/formatters/time_tracker' describe KnapsackPro::Adapters::RSpecAdapter do + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + it 'backwards compatibility with knapsack gem old rspec adapter name' do expect(KnapsackPro::Adapters::RspecAdapter.new).to be_kind_of(described_class) end diff --git a/spec/knapsack_pro/build_distribution_fetcher_spec.rb b/spec/knapsack_pro/build_distribution_fetcher_spec.rb index f0963262..1174507e 100644 --- a/spec/knapsack_pro/build_distribution_fetcher_spec.rb +++ b/spec/knapsack_pro/build_distribution_fetcher_spec.rb @@ -1,4 +1,16 @@ describe KnapsackPro::BuildDistributionFetcher do + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + describe '.call' do subject { described_class.new.call } diff --git a/spec/knapsack_pro/commands_spec.rb b/spec/knapsack_pro/commands_spec.rb index a9767d2e..c07ec121 100644 --- a/spec/knapsack_pro/commands_spec.rb +++ b/spec/knapsack_pro/commands_spec.rb @@ -8,7 +8,7 @@ original = $stderr $stderr = StringIO.new example.run - $stdout = original + $stderr = original end it do diff --git a/spec/knapsack_pro/config/env_spec.rb b/spec/knapsack_pro/config/env_spec.rb index 5e33d6b6..fabddada 100644 --- a/spec/knapsack_pro/config/env_spec.rb +++ b/spec/knapsack_pro/config/env_spec.rb @@ -1,4 +1,10 @@ describe KnapsackPro::Config::Env do + around(:each) do |example| + $stderr = StringIO.new + example.run + $stderr = STDERR + end + before { stub_const("ENV", {}) } before(:each) do diff --git a/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb b/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb index 3637ce1c..b3082d8d 100644 --- a/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +++ b/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb @@ -1,4 +1,16 @@ describe KnapsackPro::Runners::Queue::MinitestRunner do + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + describe '.run' do let(:test_suite_token_minitest) { 'fake-token' } let(:queue_id) { 'fake-queue-id' } diff --git a/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb b/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb index 7fae49e1..de4d68ec 100644 --- a/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +++ b/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb @@ -3,6 +3,18 @@ let(:report_path) { '.knapsack_pro/test_case_detectors/rspec/rspec_dry_run_json_report_node_0.json' } let(:rspec_test_example_detector) { described_class.new } + around(:each) do |example| + KnapsackPro.reset_logger! + $stdout = StringIO.new + $stderr = StringIO.new + KnapsackPro.stdout = $stdout + example.run + KnapsackPro.stdout = STDOUT + $stdout = STDOUT + $stderr = STDERR + KnapsackPro.reset_logger! + end + describe '#dry_run_to_file' do subject { rspec_test_example_detector.dry_run_to_file(rspec_args) } From 62bdbb4a6f30022e641cc6fb83463e3a1616100c Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 15:46:10 +0100 Subject: [PATCH 20/29] fix: do not oblige users to pass a string as args --- lib/knapsack_pro/commands.rb | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index e993f1eb..3af17a3d 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -12,52 +12,52 @@ def self.exit_on_failure? true end - desc "rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Regular Mode" - def rspec(arguments = "") + desc "rspec [arguments]", "Parallelize RSpec with Knapsack Pro in Regular Mode" + def rspec(*arguments) require "knapsack_pro" - KnapsackPro::Runners::RSpecRunner.run(arguments) + KnapsackPro::Runners::RSpecRunner.run(arguments.join(" ")) end - desc "queue:rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Queue Mode" - def queue_rspec(arguments = "") + desc "queue:rspec [arguments]", "Parallelize RSpec with Knapsack Pro in Queue Mode" + def queue_rspec(*arguments) require "knapsack_pro" - KnapsackPro::Runners::Queue::RSpecRunner.run(arguments) + KnapsackPro::Runners::Queue::RSpecRunner.run(arguments.join(" ")) end - desc "cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Regular Mode" - def cucumber(arguments = "") + desc "cucumber [arguments]", "Parallelize Cucumber with Knapsack Pro in Regular Mode" + def cucumber(*arguments) require "knapsack_pro" - KnapsackPro::Runners::CucumberRunner.run(arguments) + KnapsackPro::Runners::CucumberRunner.run(arguments.join(" ")) end - desc "queue:cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Queue Mode" - def queue_cucumber(arguments = "") + desc "queue:cucumber [arguments]", "Parallelize Cucumber with Knapsack Pro in Queue Mode" + def queue_cucumber(*arguments) require "knapsack_pro" - KnapsackPro::Runners::Queue::CucumberRunner.run(arguments) + KnapsackPro::Runners::Queue::CucumberRunner.run(arguments.join(" ")) end - desc "minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Regular Mode" - def minitest(arguments = "") + desc "minitest [arguments]", "Parallelize Minitest with Knapsack Pro in Regular Mode" + def minitest(*arguments) require "knapsack_pro" - KnapsackPro::Runners::MinitestRunner.run(arguments) + KnapsackPro::Runners::MinitestRunner.run(arguments.join(" ")) end - desc "queue:minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Queue Mode" - def queue_minitest(arguments = "") + desc "queue:minitest [arguments]", "Parallelize Minitest with Knapsack Pro in Queue Mode" + def queue_minitest(*arguments) require "knapsack_pro" - KnapsackPro::Runners::Queue::MinitestRunner.run(arguments) + KnapsackPro::Runners::Queue::MinitestRunner.run(arguments.join(" ")) end - desc "test_unit ['arguments']", "Parallelize TestUnit with Knapsack Pro in Regular Mode" - def test_unit(arguments = "") + desc "test_unit [arguments]", "Parallelize TestUnit with Knapsack Pro in Regular Mode" + def test_unit(*arguments) require "knapsack_pro" - KnapsackPro::Runners::TestUnitRunner.run(arguments) + KnapsackPro::Runners::TestUnitRunner.run(arguments.join(" ")) end - desc "spinach ['arguments']", "Parallelize Spinach with Knapsack Pro in Regular Mode" - def spinach(arguments = "") + desc "spinach [arguments]", "Parallelize Spinach with Knapsack Pro in Regular Mode" + def spinach(*arguments) require "knapsack_pro" - KnapsackPro::Runners::SpinachRunner.run(arguments) + KnapsackPro::Runners::SpinachRunner.run(arguments.join(" ")) end desc "retry [-b] [-- test_runner_args]", "Retry the tests that failed on the previous Knapsack Pro run on BRANCH." From 1a0d93cb2a847127f2050233dd4e7db73931f8ba Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 15:46:16 +0100 Subject: [PATCH 21/29] feat: support encrypted branch in retry command --- lib/knapsack_pro/commands/retry_failed_tests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/knapsack_pro/commands/retry_failed_tests.rb b/lib/knapsack_pro/commands/retry_failed_tests.rb index 87aefc84..6293e5af 100644 --- a/lib/knapsack_pro/commands/retry_failed_tests.rb +++ b/lib/knapsack_pro/commands/retry_failed_tests.rb @@ -29,7 +29,7 @@ def fetch_failed_paths } uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") - uri.query = URI.encode_www_form(branch: branch) + uri.query = URI.encode_www_form(branch: KnapsackPro::Crypto::BranchEncryptor.call(branch)) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == 'https') From 6bb69e2418d0df0b477471501a73abf6e0a7c2a1 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 16:41:45 +0100 Subject: [PATCH 22/29] fix: avoid name collisions --- lib/knapsack_pro/commands.rb | 2 +- .../commands/retry_failed_tests.rb | 60 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index 3af17a3d..054382bf 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -68,7 +68,7 @@ def spinach(*arguments) option :branch, type: :string, aliases: :b, desc: "Default: current branch." def retry(*runner_args) require_relative "./commands/retry_failed_tests" - RetryFailedTests.new(branch: options[:branch]).call(runner_args) + KnapsackPro::RetryFailedTests.new(branch: options[:branch]).call(runner_args) end end end diff --git a/lib/knapsack_pro/commands/retry_failed_tests.rb b/lib/knapsack_pro/commands/retry_failed_tests.rb index 6293e5af..9d957be1 100644 --- a/lib/knapsack_pro/commands/retry_failed_tests.rb +++ b/lib/knapsack_pro/commands/retry_failed_tests.rb @@ -3,45 +3,47 @@ require "json" require "net/http" -class RetryFailedTests - def initialize(branch:) - @branch = branch || `git branch --show-current`.chomp - end +module KnapsackPro + class RetryFailedTests + def initialize(branch:) + @branch = branch || `git branch --show-current`.chomp + end - def call(runner_args) - $stderr.puts "Branch: #{branch}" + def call(runner_args) + $stderr.puts "Branch: #{branch}" - failed_paths = fetch_failed_paths - return ($stderr.puts "Nothing to run") if failed_paths.size.zero? + failed_paths = fetch_failed_paths + return ($stderr.puts "Nothing to run") if failed_paths.size.zero? - $stderr.puts "Retrying #{failed_paths.size} tests..." - exec Gem.bin_path("rspec-core", "rspec"), *(runner_args + failed_paths) - end + $stderr.puts "Retrying #{failed_paths.size} tests..." + exec Gem.bin_path("rspec-core", "rspec"), *(runner_args + failed_paths) + end - private + private - attr_accessor :branch + attr_accessor :branch - def fetch_failed_paths - headers = { - 'Accept' => 'application/json', - 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") - } + def fetch_failed_paths + headers = { + 'Accept' => 'application/json', + 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => ENV.fetch("KNAPSACK_PRO_TEST_SUITE_TOKEN") + } - uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") - uri.query = URI.encode_www_form(branch: KnapsackPro::Crypto::BranchEncryptor.call(branch)) + uri = URI.parse("#{KnapsackPro::Config::Env.endpoint}/v2/test_paths") + uri.query = URI.encode_www_form(branch: KnapsackPro::Crypto::BranchEncryptor.call(branch)) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = (uri.scheme == 'https') - http.open_timeout = 5 - http.read_timeout = 5 + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == 'https') + http.open_timeout = 5 + http.read_timeout = 5 - response = http.get(uri.request_uri, headers) - abort response.inspect if (300..).cover?(response.code.to_i) + response = http.get(uri.request_uri, headers) + abort response.inspect if (300..).cover?(response.code.to_i) - parsed = JSON.parse(response.body) - abort parsed.inspect if parsed['errors'] + parsed = JSON.parse(response.body) + abort parsed.inspect if parsed['errors'] - parsed.fetch('failed_paths') + parsed.fetch('failed_paths') + end end end From 668da13a8022f54aa415ccb5dd01854e5df06055 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Tue, 20 Jan 2026 22:10:55 +0100 Subject: [PATCH 23/29] fix: rspec queue command --- lib/knapsack_pro/commands.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index 054382bf..fe99c4c1 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -21,6 +21,7 @@ def rspec(*arguments) desc "queue:rspec [arguments]", "Parallelize RSpec with Knapsack Pro in Queue Mode" def queue_rspec(*arguments) require "knapsack_pro" + ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = KnapsackPro::Config::Env.test_queue_id # Needed by queue_allocator_builder (and ignored in this code path) KnapsackPro::Runners::Queue::RSpecRunner.run(arguments.join(" ")) end From d59da10a2b66c10c279915406c3be7d420f2ff3b Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 21 Jan 2026 11:14:43 +0100 Subject: [PATCH 24/29] feat: send fixed queue split in v2 --- lib/knapsack_pro/client/api/v2/queues.rb | 2 + lib/knapsack_pro/config/env.rb | 4 + .../knapsack_pro/client/api/v2/queues_spec.rb | 138 +++++++----------- 3 files changed, 58 insertions(+), 86 deletions(-) diff --git a/lib/knapsack_pro/client/api/v2/queues.rb b/lib/knapsack_pro/client/api/v2/queues.rb index fcc1c86f..bdce678f 100644 --- a/lib/knapsack_pro/client/api/v2/queues.rb +++ b/lib/knapsack_pro/client/api/v2/queues.rb @@ -15,6 +15,7 @@ def queue(args) branch: args.fetch(:branch), can_initialize_queue: args.fetch(:can_initialize_queue), commit_hash: args.fetch(:commit_hash), + fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split_?, node_index: args.fetch(:node_index), node_total: args.fetch(:node_total), node_uuid: KnapsackPro::Config::Env.node_uuid, @@ -57,6 +58,7 @@ def initialize(paths) can_initialize_queue: true, commit_authors: git_adapter.commit_authors, commit_hash: repository_adapter.commit_hash, + fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split_?, node_index: KnapsackPro::Config::Env.ci_node_index, node_total: KnapsackPro::Config::Env.ci_node_total, node_uuid: SecureRandom.uuid, diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index 8f8d1292..f64db54c 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -164,6 +164,10 @@ def fixed_queue_split end end + def fixed_queue_split_? + @fixed_queue_split_ ||= env_for('KNAPSACK_PRO_FIXED_QUEUE_SPLIT', :fixed_queue_split).to_s == "true" + end + def fixed_queue_split? fixed_queue_split.to_s == 'true' end diff --git a/spec/knapsack_pro/client/api/v2/queues_spec.rb b/spec/knapsack_pro/client/api/v2/queues_spec.rb index a59eebae..9042aec0 100644 --- a/spec/knapsack_pro/client/api/v2/queues_spec.rb +++ b/spec/knapsack_pro/client/api/v2/queues_spec.rb @@ -1,18 +1,19 @@ describe KnapsackPro::Client::API::V2::Queues do describe '.queue' do - let(:commit_hash) { double } + let(:attempt_connect_to_queue) { [false, true].sample } + let(:batch_uuid) { SecureRandom.uuid } let(:branch) { double } - let(:node_total) { double } - let(:node_index) { double } - let(:test_files) { double } - let(:masked_user_seat) { double } let(:can_initialize_queue) { [false, true].sample } - let(:attempt_connect_to_queue) { [false, true].sample } - let(:test_queue_id) { "123:abc" } + let(:commit_hash) { double } + let(:fixed_queue_split_?) { [false, true].sample } + let(:masked_user_seat) { double } + let(:node_index) { double } + let(:node_total) { double } let(:node_uuid) { SecureRandom.uuid } - let(:batch_uuid) { SecureRandom.uuid } + let(:test_queue_id) { "123:abc" } before(:each) do + expect(KnapsackPro::Config::Env).to receive(:fixed_queue_split_?).and_return(fixed_queue_split_?) expect(KnapsackPro::Config::Env).to receive(:masked_user_seat).and_return(masked_user_seat) expect(KnapsackPro::Config::Env).to receive(:node_uuid).and_return(node_uuid) expect(KnapsackPro::Config::Env).to receive(:test_queue_id).and_return(test_queue_id) @@ -23,122 +24,87 @@ let(:attempt_connect_to_queue) { true } it do - expected = KnapsackPro::Client::API::Action.new( - endpoint_path: '/v2/queues/queue', - http_method: :post, - request_hash: { - can_initialize_queue: true, - attempt_connect_to_queue: true, - commit_hash: commit_hash, - branch: branch, - node_total: node_total, - node_index: node_index, - user_seat: masked_user_seat, - test_queue_id: test_queue_id, - node_uuid: node_uuid, - batch_uuid: batch_uuid - } - ) - actual = described_class.queue( - can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: attempt_connect_to_queue, - commit_hash: commit_hash, + batch_uuid: batch_uuid, branch: branch, - node_total: node_total, + can_initialize_queue: can_initialize_queue, + commit_hash: commit_hash, node_index: node_index, - test_files: test_files, - batch_uuid: batch_uuid + node_total: node_total ) - expect(actual).to eq(expected) + expected_request_hash = { + attempt_connect_to_queue: attempt_connect_to_queue, + batch_uuid: batch_uuid, + branch: branch, + can_initialize_queue: can_initialize_queue, + commit_hash: commit_hash, + fixed_queue_split: fixed_queue_split_?, + node_index: node_index, + node_total: node_total, + node_uuid: node_uuid, + test_queue_id: test_queue_id, + user_seat: masked_user_seat + } + expect(actual.endpoint_path).to eq("/v2/queues/queue") + expect(actual.http_method).to eq(:post) + expect(actual.request_hash).to include(expected_request_hash) end end context 'when can_initialize_queue=true and attempt_connect_to_queue=false' do - let(:can_initialize_queue) { true } let(:attempt_connect_to_queue) { false } let(:build_author) { '3v0*4 ' } + let(:can_initialize_queue) { true } let(:commit_authors) { [{ commits: 2, author: build_author }] } + let(:test_files) { ["spec/a_spec.rb"] } before(:each) do allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:build_author).and_return(build_author) allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:commit_authors).and_return(commit_authors) end - it do - expected = KnapsackPro::Client::API::Action.new( - endpoint_path: '/v2/queues/queue', - http_method: :post, - request_hash: { - can_initialize_queue: true, - attempt_connect_to_queue: false, - commit_hash: commit_hash, - branch: branch, - node_total: node_total, - node_index: node_index, - user_seat: masked_user_seat, - test_files: test_files, - build_author: build_author, - commit_authors: commit_authors, - test_queue_id: test_queue_id, - node_uuid: node_uuid, - batch_uuid: batch_uuid - } - ) - + it "includes build_authors, commit_authors, test_files" do actual = described_class.queue( - can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: attempt_connect_to_queue, - commit_hash: commit_hash, + batch_uuid: batch_uuid, branch: branch, - node_total: node_total, + can_initialize_queue: can_initialize_queue, + commit_hash: commit_hash, node_index: node_index, - test_files: test_files, - batch_uuid: batch_uuid + node_total: node_total, + test_files: test_files ) - expect(actual).to eq(expected) + expect(actual.request_hash).to include( + build_author: build_author, + commit_authors: commit_authors, + test_files: test_files + ) end end context 'when can_initialize_queue=false and attempt_connect_to_queue=false' do - let(:can_initialize_queue) { false } let(:attempt_connect_to_queue) { false } + let(:can_initialize_queue) { false } let(:failed_paths) { ['spec/a_spec.rb[1:1]'] } + let(:test_files) { ["spec/a_spec.rb"] } - it do - expected = KnapsackPro::Client::API::Action.new( - endpoint_path: '/v2/queues/queue', - http_method: :post, - request_hash: { - can_initialize_queue: false, - attempt_connect_to_queue: false, - commit_hash: commit_hash, - branch: branch, - node_total: node_total, - node_index: node_index, - user_seat: masked_user_seat, - test_queue_id: test_queue_id, - node_uuid: node_uuid, - failed_paths: failed_paths, - batch_uuid: batch_uuid - } - ) - + it "includes failed_paths" do actual = described_class.queue( - can_initialize_queue: can_initialize_queue, attempt_connect_to_queue: attempt_connect_to_queue, - commit_hash: commit_hash, + batch_uuid: batch_uuid, branch: branch, - node_total: node_total, - node_index: node_index, - test_files: test_files, + can_initialize_queue: can_initialize_queue, + commit_hash: commit_hash, failed_paths: failed_paths, - batch_uuid: batch_uuid + node_index: node_index, + node_total: node_total, + test_files: test_files ) - expect(actual).to eq(expected) + expect(actual.request_hash).to include(failed_paths: failed_paths) end end end From de1ab88226e392709737e7119da6361a492440ef Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 21 Jan 2026 11:43:14 +0100 Subject: [PATCH 25/29] refactor: simplify params --- lib/knapsack_pro/commands.rb | 2 +- lib/knapsack_pro/commands/retry_failed_tests.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index fe99c4c1..f4240928 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -69,7 +69,7 @@ def spinach(*arguments) option :branch, type: :string, aliases: :b, desc: "Default: current branch." def retry(*runner_args) require_relative "./commands/retry_failed_tests" - KnapsackPro::RetryFailedTests.new(branch: options[:branch]).call(runner_args) + KnapsackPro::RetryFailedTests.new(options[:branch]).call(runner_args) end end end diff --git a/lib/knapsack_pro/commands/retry_failed_tests.rb b/lib/knapsack_pro/commands/retry_failed_tests.rb index 9d957be1..8bfa18d9 100644 --- a/lib/knapsack_pro/commands/retry_failed_tests.rb +++ b/lib/knapsack_pro/commands/retry_failed_tests.rb @@ -5,7 +5,7 @@ module KnapsackPro class RetryFailedTests - def initialize(branch:) + def initialize(branch) @branch = branch || `git branch --show-current`.chomp end From 7e8734be4793409dfbcf97d474e00c1c4ba6346f Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 21 Jan 2026 11:47:12 +0100 Subject: [PATCH 26/29] chore: retry only rspec for now [skip ci] --- lib/knapsack_pro/commands.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index f4240928..098ab74f 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -61,7 +61,7 @@ def spinach(*arguments) KnapsackPro::Runners::SpinachRunner.run(arguments.join(" ")) end - desc "retry [-b] [-- test_runner_args]", "Retry the tests that failed on the previous Knapsack Pro run on BRANCH." + desc "retry [-b] [-- test_runner_args]", "Retry RSpec the tests that failed on the previous Knapsack Pro run on BRANCH." long_desc <<~DESC \x5knapsack_pro retry \x5knapsack_pro retry --branch feature -- --format progress From b033fce3838ab9a240a53e80099d19d2c2b64319 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Wed, 21 Jan 2026 13:09:10 +0100 Subject: [PATCH 27/29] fix: commands expect string (keep compat) [skip ci] --- lib/knapsack_pro/commands.rb | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/knapsack_pro/commands.rb b/lib/knapsack_pro/commands.rb index 098ab74f..a95b01ef 100644 --- a/lib/knapsack_pro/commands.rb +++ b/lib/knapsack_pro/commands.rb @@ -12,53 +12,53 @@ def self.exit_on_failure? true end - desc "rspec [arguments]", "Parallelize RSpec with Knapsack Pro in Regular Mode" - def rspec(*arguments) + desc "rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Regular Mode" + def rspec(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::RSpecRunner.run(arguments.join(" ")) + KnapsackPro::Runners::RSpecRunner.run(arguments) end - desc "queue:rspec [arguments]", "Parallelize RSpec with Knapsack Pro in Queue Mode" - def queue_rspec(*arguments) + desc "queue:rspec ['arguments']", "Parallelize RSpec with Knapsack Pro in Queue Mode" + def queue_rspec(arguments = "") require "knapsack_pro" ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = KnapsackPro::Config::Env.test_queue_id # Needed by queue_allocator_builder (and ignored in this code path) - KnapsackPro::Runners::Queue::RSpecRunner.run(arguments.join(" ")) + KnapsackPro::Runners::Queue::RSpecRunner.run(arguments) end - desc "cucumber [arguments]", "Parallelize Cucumber with Knapsack Pro in Regular Mode" - def cucumber(*arguments) + desc "cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Regular Mode" + def cucumber(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::CucumberRunner.run(arguments.join(" ")) + KnapsackPro::Runners::CucumberRunner.run(arguments) end - desc "queue:cucumber [arguments]", "Parallelize Cucumber with Knapsack Pro in Queue Mode" - def queue_cucumber(*arguments) + desc "queue:cucumber ['arguments']", "Parallelize Cucumber with Knapsack Pro in Queue Mode" + def queue_cucumber(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::Queue::CucumberRunner.run(arguments.join(" ")) + KnapsackPro::Runners::Queue::CucumberRunner.run(arguments) end - desc "minitest [arguments]", "Parallelize Minitest with Knapsack Pro in Regular Mode" - def minitest(*arguments) + desc "minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Regular Mode" + def minitest(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::MinitestRunner.run(arguments.join(" ")) + KnapsackPro::Runners::MinitestRunner.run(arguments) end - desc "queue:minitest [arguments]", "Parallelize Minitest with Knapsack Pro in Queue Mode" - def queue_minitest(*arguments) + desc "queue:minitest ['arguments']", "Parallelize Minitest with Knapsack Pro in Queue Mode" + def queue_minitest(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::Queue::MinitestRunner.run(arguments.join(" ")) + KnapsackPro::Runners::Queue::MinitestRunner.run(arguments) end - desc "test_unit [arguments]", "Parallelize TestUnit with Knapsack Pro in Regular Mode" - def test_unit(*arguments) + desc "test_unit ['arguments']", "Parallelize TestUnit with Knapsack Pro in Regular Mode" + def test_unit(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::TestUnitRunner.run(arguments.join(" ")) + KnapsackPro::Runners::TestUnitRunner.run(arguments) end - desc "spinach [arguments]", "Parallelize Spinach with Knapsack Pro in Regular Mode" - def spinach(*arguments) + desc "spinach ['arguments']", "Parallelize Spinach with Knapsack Pro in Regular Mode" + def spinach(arguments = "") require "knapsack_pro" - KnapsackPro::Runners::SpinachRunner.run(arguments.join(" ")) + KnapsackPro::Runners::SpinachRunner.run(arguments) end desc "retry [-b] [-- test_runner_args]", "Retry RSpec the tests that failed on the previous Knapsack Pro run on BRANCH." From 6e725051935e21966390d3f86a7709c11686bb2a Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Fri, 23 Jan 2026 11:35:39 +0100 Subject: [PATCH 28/29] test: remove unneeded ENV --- rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec | 1 - 1 file changed, 1 deletion(-) diff --git a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec index e438b49b..1a310e2c 100755 --- a/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec +++ b/rails-app-with-knapsack_pro/bin/bin_knapsack_pro_rspec @@ -8,6 +8,5 @@ KNAPSACK_PRO_ENDPOINT=http://api.knapsackpro.localhost:3000 \ KNAPSACK_PRO_PROJECT_DIR=. \ KNAPSACK_PRO_CI_NODE_TOTAL=${2:-2} \ KNAPSACK_PRO_CI_NODE_INDEX=${1:-0} \ - KNAPSACK_PRO_TEST_QUEUE_ID=${3:-$CI_BUILD_ID} \ KNAPSACK_PRO_CI_NODE_BUILD_ID=${3:-$CI_BUILD_ID} \ bundle exec knapsack_pro rspec From 6f2844fe3a8f67676e5a8e6c4772ec1f1dfd4106 Mon Sep 17 00:00:00 2001 From: 3v0k4 Date: Fri, 23 Jan 2026 14:29:35 +0100 Subject: [PATCH 29/29] feat: log a message when no tests were executed in queue mode --- lib/knapsack_pro/report.rb | 4 ++++ spec/integration/runners/queue/rspec_runner_spec.rb | 2 ++ 2 files changed, 6 insertions(+) diff --git a/lib/knapsack_pro/report.rb b/lib/knapsack_pro/report.rb index d3b9600d..25938340 100644 --- a/lib/knapsack_pro/report.rb +++ b/lib/knapsack_pro/report.rb @@ -41,6 +41,10 @@ def self.save_node_queue_to_api(test_files = nil) end end + if test_files.empty? + KnapsackPro.logger.info("No tests were executed because the test queue is empty.") + end + measured_test_files = test_files .map { |t| t['time_execution'] } .select { |time_execution| time_execution != KnapsackPro::Tracker::DEFAULT_TEST_FILE_TIME } diff --git a/spec/integration/runners/queue/rspec_runner_spec.rb b/spec/integration/runners/queue/rspec_runner_spec.rb index da83b3e2..b09a3368 100644 --- a/spec/integration/runners/queue/rspec_runner_spec.rb +++ b/spec/integration/runners/queue/rspec_runner_spec.rb @@ -1579,6 +1579,7 @@ def when_first_matching_example_defined(type:) actual = subject expect(actual.stdout).to include('0 examples, 0 failures') + expect(actual.stdout).to include('INFO -- knapsack_pro: No tests were executed because the test queue is empty.') expect(actual.exit_code).to eq 0 end @@ -1602,6 +1603,7 @@ def when_first_matching_example_defined(type:) actual = subject expect(actual.stdout).to include('0 examples, 0 failures') + expect(actual.stdout).to include('INFO -- knapsack_pro: No tests were executed because the test queue is empty.') expect(actual.exit_code).to eq 0 end