summaryrefslogtreecommitdiff
path: root/tooling
diff options
context:
space:
mode:
Diffstat (limited to 'tooling')
-rwxr-xr-xtooling/bin/find_tests (renamed from tooling/bin/find_foss_tests)11
-rwxr-xr-xtooling/bin/parallel_rspec19
-rw-r--r--tooling/lib/tooling/parallel_rspec_runner.rb90
-rw-r--r--tooling/lib/tooling/test_map_generator.rb2
-rw-r--r--tooling/overcommit/Gemfile2
-rw-r--r--tooling/overcommit/Gemfile.lock4
6 files changed, 121 insertions, 7 deletions
diff --git a/tooling/bin/find_foss_tests b/tooling/bin/find_tests
index 9cd8a616ad0..2c0e7ae2c53 100755
--- a/tooling/bin/find_foss_tests
+++ b/tooling/bin/find_tests
@@ -19,7 +19,12 @@ mr_iid = ENV.fetch('CI_MERGE_REQUEST_IID')
mr_changes = Gitlab.merge_request_changes(mr_project_path, mr_iid)
changed_files = mr_changes.changes.map { |change| change['new_path'] }
-mapping = TestFileFinder::Mapping.load('tests.yml')
-test_files = TestFileFinder::FileFinder.new(paths: changed_files, mapping: mapping).test_files
+tff = TestFileFinder::FileFinder.new(paths: changed_files).tap do |file_finder|
+ file_finder.use TestFileFinder::MappingStrategies::PatternMatching.load('tests.yml')
-File.write(output_file, test_files.uniq.join(' '))
+ if ENV['RSPEC_TESTS_MAPPING_ENABLED']
+ file_finder.use TestFileFinder::MappingStrategies::DirectMatching.load_json(ENV['RSPEC_TESTS_MAPPING_PATH'])
+ end
+end
+
+File.write(output_file, tff.test_files.uniq.join(' '))
diff --git a/tooling/bin/parallel_rspec b/tooling/bin/parallel_rspec
new file mode 100755
index 00000000000..a706df69a1e
--- /dev/null
+++ b/tooling/bin/parallel_rspec
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'optparse'
+require_relative '../lib/tooling/parallel_rspec_runner'
+
+options = {}
+
+OptionParser.new do |opts|
+ opts.on("--rspec_args rspec_args", String, "Optional rspec arguments") do |value|
+ options[:rspec_args] = value
+ end
+
+ opts.on("--filter filter_tests_file", String, "Optional filename containing tests to be filtered") do |value|
+ options[:filter_tests_file] = value
+ end
+end.parse!
+
+Tooling::ParallelRSpecRunner.run(options)
diff --git a/tooling/lib/tooling/parallel_rspec_runner.rb b/tooling/lib/tooling/parallel_rspec_runner.rb
new file mode 100644
index 00000000000..b482160d3c0
--- /dev/null
+++ b/tooling/lib/tooling/parallel_rspec_runner.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require 'knapsack'
+
+# A custom parallel rspec runner based on Knapsack runner
+# which takes in additional option for a file containing
+# list of test files.
+#
+# When executing RSpec in CI, the list of tests allocated by Knapsack
+# will be compared with the test files listed in the file.
+#
+# Only the test files allocated by Knapsack and listed in the file
+# would be executed in the CI node.
+#
+# Reference:
+# https://github.com/ArturT/knapsack/blob/v1.20.0/lib/knapsack/runners/rspec_runner.rb
+module Tooling
+ class ParallelRSpecRunner
+ def self.run(rspec_args: nil, filter_tests_file: nil)
+ new(rspec_args: rspec_args, filter_tests_file: filter_tests_file).run
+ end
+
+ def initialize(allocator: knapsack_allocator, filter_tests_file: nil, rspec_args: nil)
+ @allocator = allocator
+ @filter_tests_file = filter_tests_file
+ @rspec_args = rspec_args&.split(' ') || []
+ end
+
+ def run
+ Knapsack.logger.info
+ Knapsack.logger.info 'Knapsack node specs:'
+ Knapsack.logger.info node_tests
+ Knapsack.logger.info
+ Knapsack.logger.info 'Filter specs:'
+ Knapsack.logger.info filter_tests
+ Knapsack.logger.info
+ Knapsack.logger.info 'Running specs:'
+ Knapsack.logger.info tests_to_run
+ Knapsack.logger.info
+
+ if tests_to_run.empty?
+ Knapsack.logger.info 'No tests to run on this node, exiting.'
+ return
+ end
+
+ exec(*rspec_command)
+ end
+
+ private
+
+ attr_reader :allocator, :filter_tests_file, :rspec_args
+
+ def rspec_command
+ %w[bundle exec rspec].tap do |cmd|
+ cmd.push(*rspec_args)
+ cmd.push('--default-path', allocator.test_dir)
+ cmd.push('--')
+ cmd.push(*tests_to_run)
+ end
+ end
+
+ def tests_to_run
+ if filter_tests.empty?
+ Knapsack.logger.info 'Running all node tests without filter'
+ return node_tests
+ end
+
+ @tests_to_run ||= node_tests & filter_tests
+ end
+
+ def node_tests
+ allocator.node_tests
+ end
+
+ def filter_tests
+ @filter_tests ||=
+ filter_tests_file ? tests_from_file(filter_tests_file) : []
+ end
+
+ def tests_from_file(filter_tests_file)
+ return [] unless File.exist?(filter_tests_file)
+
+ File.read(filter_tests_file).split(' ')
+ end
+
+ def knapsack_allocator
+ Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator
+ end
+ end
+end
diff --git a/tooling/lib/tooling/test_map_generator.rb b/tooling/lib/tooling/test_map_generator.rb
index bd0415f6e67..20e4ed8e405 100644
--- a/tooling/lib/tooling/test_map_generator.rb
+++ b/tooling/lib/tooling/test_map_generator.rb
@@ -17,7 +17,7 @@ module Tooling
example_groups.each do |example_id, files|
files.each do |file|
spec_file = strip_example_uid(example_id)
- @mapping[file] << spec_file
+ @mapping[file] << spec_file.delete_prefix('./')
end
end
end
diff --git a/tooling/overcommit/Gemfile b/tooling/overcommit/Gemfile
index 08f08018ffb..52e8dcaa497 100644
--- a/tooling/overcommit/Gemfile
+++ b/tooling/overcommit/Gemfile
@@ -4,6 +4,6 @@
source 'https://rubygems.org'
gem 'overcommit'
-gem 'gitlab-styles', '~> 5.1.0', require: false
+gem 'gitlab-styles', '~> 5.3.0', require: false
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.34.0', require: false
diff --git a/tooling/overcommit/Gemfile.lock b/tooling/overcommit/Gemfile.lock
index 5bada88e1dc..b46229ac9f8 100644
--- a/tooling/overcommit/Gemfile.lock
+++ b/tooling/overcommit/Gemfile.lock
@@ -11,7 +11,7 @@ GEM
childprocess (3.0.0)
concurrent-ruby (1.1.7)
ffi (1.12.2)
- gitlab-styles (5.1.0)
+ gitlab-styles (5.3.0)
rubocop (~> 0.89.1)
rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.8.1)
@@ -88,7 +88,7 @@ PLATFORMS
ruby
DEPENDENCIES
- gitlab-styles (~> 5.1.0)
+ gitlab-styles (~> 5.3.0)
haml_lint (~> 0.34.0)
overcommit
scss_lint (~> 0.56.0)