Skip to content

Instantly share code, notes, and snippets.

@jasonkarns
Last active April 21, 2025 21:04
Show Gist options
  • Save jasonkarns/a0884cb7a5ff25c26e2cd2d339d57d66 to your computer and use it in GitHub Desktop.
Save jasonkarns/a0884cb7a5ff25c26e2cd2d339d57d66 to your computer and use it in GitHub Desktop.
Partition RSpec files across runners in a stable way to support deterministic sharding.
jobs:
build:
docker: [image: cimg/ruby:3.4.3]
parallelism: 4
steps:
- checkout
- run: script/test spec:ci[$((${CIRCLE_NODE_INDEX}+1))/${CIRCLE_NODE_TOTAL}]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
group: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout
- uses: ruby/setup-ruby
- run: script/test spec:ci[${{ matrix.group }}/${{ strategy.job-total }}]
if defined?(RSpec)
SPECS = FileList[ENV.fetch "SPEC", RSpec::Core::RakeTask::DEFAULT_PATTERN].uniq
namespace :spec do
desc "Run default ci specs - no flaky specs [job='N/total' (default: 1/1)]"
RSpec::Core::RakeTask.new(:ci, [:job]) do |t, args|
args.with_defaults(job: "1/1")
group, total = args[:job].split("/").map(&:to_i)
# partition such that the grouping is stable regardless of file count
# hash the filename taking the first 64 bits as an int, modulo the number of groups
# offset by 1 b/c job number is 1-index (so that '5/5' makes sense)
ENV["SPEC"] = SPECS.select { |s| Digest::SHA2.digest(s).unpack1("Q") % total == group - 1 }.join(" ")
t.rspec_opts = %w[
--tag ~flaky
--force-color
--format doc
--profile 2
--warnings
]
end
desc "Run only flaky specs (need made deterministic or deleted)"
RSpec::Core::RakeTask.new(:flaky) do |t|
t.rspec_opts = %w[
--tag flaky
--force-color
--format doc
]
end
end
end
@jasonkarns
Copy link
Author

jasonkarns commented Apr 21, 2025

Invocation of the rake task looks like:

rake spec:ci[1/4]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment