Skip to content

Commit 162076d

Browse files
committed
Moved code from Tasks to Tasks::Helpers
1 parent 4d5531c commit 162076d

File tree

4 files changed

+219
-55
lines changed

4 files changed

+219
-55
lines changed

lib/parallel_tests/tasks.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# frozen_string_literal: true
2-
require 'rake'
32
require 'shellwords'
4-
require_relative '../tasks/helpers.rb'
3+
require_relative 'tasks/helpers.rb'
54

65
namespace :parallel do
76
desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
87
task :setup, :count do |_, args|
98
command = [$0, "db:setup", "RAILS_ENV=#{ParallelTests::Tasks::Helpers.rails_env}"]
10-
ParallelTests::Tasks::Helpers.run_in_parallel(ParallelTests::Tasks::Helpers.suppress_schema_load_output(command), args)
9+
ParallelTests::Tasks::Helpers.
10+
run_in_parallel(ParallelTests::Tasks::Helpers.suppress_schema_load_output(command), args)
1111
end
1212

1313
ParallelTests::Tasks::Helpers.for_each_database do |name|

lib/parallel_tests/tasks/helpers.rb

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# frozen_string_literal: true
2+
require 'rake'
3+
4+
module ParallelTests
5+
module Tasks
6+
module Helpers
7+
class << self
8+
def rails_env
9+
'test'
10+
end
11+
12+
def load_lib
13+
$LOAD_PATH << File.expand_path('../..', __dir__)
14+
require "parallel_tests"
15+
end
16+
17+
def purge_before_load
18+
if ActiveRecord.version > Gem::Version.new('4.2.0')
19+
Rake::Task.task_defined?('db:purge') ? 'db:purge' : 'app:db:purge'
20+
end
21+
end
22+
23+
def run_in_parallel(cmd, options = {})
24+
load_lib
25+
26+
# Using the relative path to find the binary allow to run a specific version of it
27+
executable = File.expand_path('../../../bin/parallel_test', __dir__)
28+
command = ParallelTests.with_ruby_binary(executable)
29+
command += ['--exec', Shellwords.join(cmd)]
30+
command += ['-n', options[:count]] unless options[:count].to_s.empty?
31+
command << '--non-parallel' if options[:non_parallel]
32+
33+
abort unless system(*command)
34+
end
35+
36+
# this is a crazy-complex solution for a very simple problem:
37+
# removing certain lines from the output without changing the exit-status
38+
# normally I'd not do this, but it has been lots of fun and a great learning experience :)
39+
#
40+
# - sed does not support | without -r
41+
# - grep changes 0 exitstatus to 1 if nothing matches
42+
# - sed changes 1 exitstatus to 0
43+
# - pipefail makes pipe fail with exitstatus of first failed command
44+
# - pipefail is not supported in (zsh)
45+
# - defining a new rake task like silence_schema would force users to load parallel_tests in test env
46+
# - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
47+
def suppress_output(command, ignore_regex)
48+
activate_pipefail = "set -o pipefail"
49+
remove_ignored_lines = %{(grep -v #{Shellwords.escape(ignore_regex)} || true)}
50+
51+
# remove nil values (ex: #purge_before_load returns nil)
52+
command.compact!
53+
54+
if system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null")
55+
shell_command = "#{activate_pipefail} && (#{Shellwords.shelljoin(command)}) | #{remove_ignored_lines}"
56+
['/bin/bash', '-c', shell_command]
57+
else
58+
command
59+
end
60+
end
61+
62+
def suppress_schema_load_output(command)
63+
suppress_output(command, "^ ->\\|^-- ")
64+
end
65+
66+
def check_for_pending_migrations
67+
["db:abort_if_pending_migrations", "app:db:abort_if_pending_migrations"].each do |abort_migrations|
68+
if Rake::Task.task_defined?(abort_migrations)
69+
Rake::Task[abort_migrations].invoke
70+
break
71+
end
72+
end
73+
end
74+
75+
# parallel:spec[:count, :pattern, :options, :pass_through]
76+
def parse_args(args)
77+
# order as given by user
78+
args = [args[:count], args[:pattern], args[:options], args[:pass_through]]
79+
80+
# count given or empty ?
81+
# parallel:spec[2,models,options]
82+
# parallel:spec[,models,options]
83+
count = args.shift if args.first.to_s =~ /^\d*$/
84+
num_processes = (count.to_s.empty? ? nil : Integer(count))
85+
pattern = args.shift
86+
options = args.shift
87+
pass_through = args.shift
88+
89+
[num_processes, pattern, options, pass_through]
90+
end
91+
92+
def schema_format_based_on_rails_version
93+
if active_record_7_or_greater?
94+
ActiveRecord.schema_format
95+
else
96+
ActiveRecord::Base.schema_format
97+
end
98+
end
99+
100+
def schema_type_based_on_rails_version
101+
if active_record_61_or_greater? || schema_format_based_on_rails_version == :ruby
102+
"schema"
103+
else
104+
"structure"
105+
end
106+
end
107+
108+
def build_run_command(type, args)
109+
count, pattern, options, pass_through = parse_args(args)
110+
test_framework = {
111+
'spec' => 'rspec',
112+
'test' => 'test',
113+
'features' => 'cucumber',
114+
'features-spinach' => 'spinach'
115+
}.fetch(type)
116+
117+
type = 'features' if test_framework == 'spinach'
118+
119+
# Using the relative path to find the binary allow to run a specific version of it
120+
executable = File.expand_path('../../../bin/parallel_test', __dir__)
121+
executable = ParallelTests.with_ruby_binary(executable)
122+
123+
command = [*executable, type, '--type', test_framework]
124+
command += ['-n', count.to_s] if count
125+
command += ['--pattern', pattern] if pattern
126+
command += ['--test-options', options] if options
127+
command += Shellwords.shellsplit pass_through if pass_through
128+
command
129+
end
130+
131+
def configured_databases
132+
return [] unless defined?(ActiveRecord) && active_record_61_or_greater?
133+
134+
@@configured_databases ||= ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
135+
end
136+
137+
def for_each_database(&block)
138+
# Use nil to represent all databases
139+
block&.call(nil)
140+
141+
# skip if not rails or old rails version
142+
return if !defined?(ActiveRecord::Tasks::DatabaseTasks) || !ActiveRecord::Tasks::DatabaseTasks.respond_to?(:for_each)
143+
144+
ActiveRecord::Tasks::DatabaseTasks.for_each(configured_databases) do |name|
145+
block&.call(name)
146+
end
147+
end
148+
149+
private
150+
151+
def active_record_7_or_greater?
152+
ActiveRecord.version >= Gem::Version.new('7.0')
153+
end
154+
155+
def active_record_61_or_greater?
156+
ActiveRecord.version >= Gem::Version.new('6.1.0')
157+
end
158+
end
159+
end
160+
end
161+
end

0 commit comments

Comments
 (0)