From f6390c3326b016e1a52057573839a5608ba317ea Mon Sep 17 00:00:00 2001
From: Matt Jankowski <matt@jankowski.online>
Date: Thu, 27 Jun 2024 03:42:57 -0400
Subject: [PATCH] Use flatware to parallelize CI specs (#30284)

---
 .github/workflows/test-ruby.yml |  8 +++++---
 Gemfile                         |  3 +++
 Gemfile.lock                    | 10 ++++++++++
 bin/flatware                    | 27 +++++++++++++++++++++++++++
 spec/flatware_helper.rb         | 12 ++++++++++++
 5 files changed, 57 insertions(+), 3 deletions(-)
 create mode 100755 bin/flatware
 create mode 100644 spec/flatware_helper.rb

diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml
index dd71fd253b..ef898968d0 100644
--- a/.github/workflows/test-ruby.yml
+++ b/.github/workflows/test-ruby.yml
@@ -132,15 +132,17 @@ jobs:
           additional-system-dependencies: ffmpeg libpam-dev
 
       - name: Load database schema
-        run: './bin/rails db:create db:schema:load db:seed'
+        run: |
+          bin/rails db:setup
+          bin/flatware fan bin/rails db:test:prepare
 
-      - run: bin/rspec
+      - run: bin/flatware rspec -r ./spec/flatware_helper.rb
 
       - name: Upload coverage reports to Codecov
         if: matrix.ruby-version == '.ruby-version'
         uses: codecov/codecov-action@v4
         with:
-          files: coverage/lcov/mastodon.lcov
+          files: coverage/lcov/*.lcov
         env:
           CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
 
diff --git a/Gemfile b/Gemfile
index aa3ca8f792..be3f9e6f98 100644
--- a/Gemfile
+++ b/Gemfile
@@ -121,6 +121,9 @@ group :opentelemetry do
 end
 
 group :test do
+  # Enable usage of all available CPUs/cores during spec runs
+  gem 'flatware-rspec'
+
   # Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab
   gem 'rspec-github', '~> 2.4', require: false
 
diff --git a/Gemfile.lock b/Gemfile.lock
index 3b1b4b1121..dd112d0189 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -264,6 +264,11 @@ GEM
     ffi-compiler (1.3.2)
       ffi (>= 1.15.5)
       rake
+    flatware (2.3.2)
+      thor (< 2.0)
+    flatware-rspec (2.3.2)
+      flatware (= 2.3.2)
+      rspec (>= 3.6)
     fog-core (2.4.0)
       builder
       excon (~> 0.71)
@@ -700,6 +705,10 @@ GEM
       chunky_png (~> 1.0)
       rqrcode_core (~> 1.0)
     rqrcode_core (1.2.0)
+    rspec (3.13.0)
+      rspec-core (~> 3.13.0)
+      rspec-expectations (~> 3.13.0)
+      rspec-mocks (~> 3.13.0)
     rspec-core (3.13.0)
       rspec-support (~> 3.13.0)
     rspec-expectations (3.13.1)
@@ -932,6 +941,7 @@ DEPENDENCIES
   faker (~> 3.2)
   fast_blank (~> 1.0)
   fastimage
+  flatware-rspec
   fog-core (<= 2.4.0)
   fog-openstack (~> 1.0)
   fuubar (~> 2.5)
diff --git a/bin/flatware b/bin/flatware
new file mode 100755
index 0000000000..337ce9277e
--- /dev/null
+++ b/bin/flatware
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'flatware' 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("flatware", "flatware")
diff --git a/spec/flatware_helper.rb b/spec/flatware_helper.rb
new file mode 100644
index 0000000000..57a7c1f56a
--- /dev/null
+++ b/spec/flatware_helper.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+if defined?(Flatware)
+  Flatware.configure do |config|
+    config.after_fork do |test_env_number|
+      unless ENV.fetch('DISABLE_SIMPLECOV', nil) == 'true'
+        require 'simplecov'
+        SimpleCov.at_fork.call(test_env_number) # Combines parallel coverage results
+      end
+    end
+  end
+end