diff options
Diffstat (limited to 'tooling')
-rwxr-xr-x | tooling/bin/find_tests (renamed from tooling/bin/find_foss_tests) | 11 | ||||
-rwxr-xr-x | tooling/bin/parallel_rspec | 19 | ||||
-rw-r--r-- | tooling/lib/tooling/parallel_rspec_runner.rb | 90 | ||||
-rw-r--r-- | tooling/lib/tooling/test_map_generator.rb | 2 | ||||
-rw-r--r-- | tooling/overcommit/Gemfile | 2 | ||||
-rw-r--r-- | tooling/overcommit/Gemfile.lock | 4 |
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) |