ci: speed up lint checks - #330
Conversation
There was a problem hiding this comment.
Pull request overview
This PR optimizes the Ruby CI “lint” portion by parallelizing previously-serialized checks, removing nested RuboCop parallelism in the Rake task, and enabling caching (Bundler + RuboCop) to reduce repeat work across runs.
Changes:
- Split RuboCop vs. typechecking (Sorbet/Steep) into separate parallel GitHub Actions jobs while keeping the stable
ci-requiredaggregate check. - Replace the prior
find | xargs rubocop ...fan-out with a nativeRuboCop::RakeTaskusing RuboCop’s own--parallel. - Enable
ruby/setup-ruby’s supportedbundler-cacheacross Ruby jobs and persist RuboCop cache between runs.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| Rakefile | Switches RuboCop linting to RuboCop::RakeTask with --parallel; sizes Steep workers to available CPUs and emits GitHub-formatted output in CI. |
| .github/workflows/ci-checks.yml | Splits lint/typecheck into parallel jobs; enables Bundler caching everywhere; adds a persisted RuboCop cache; updates the required aggregate job dependencies accordingly. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Rakefile:139
- The PR description says Steep workers are sized to the runner’s available CPUs, but this task hard-codes
--jobs=8. On smaller runners this can oversubscribe CPU and slow down typechecking; on larger runners it underutilizes available cores. Consider deriving the job count fromEtc.nprocessors(already required at the top of the Rakefile).
steep = %w[steep check]
# Steep defaults to two workers in CI; eight is the tested balance for this project's runner.
steep += %w[--jobs=8 --format=github] if ENV.key?("CI")
sh(*steep)
HAYDEN-OAI
left a comment
There was a problem hiding this comment.
Reviewed commit 7469348. The RuboCop target set is unchanged (2,587 files), Sorbet and Steep remain independently covered by the required CI gate, and Bundler/RuboCop cache invalidation, least-privilege permissions, pinned actions, fork behavior, and cold/warm execution all look sound.
HAYDEN-OAI
left a comment
There was a problem hiding this comment.
Re-reviewed the full PR and subsequent changes at fb11844. RuboCop still covers the same 2,587 files; all removed lint-wrapper callers were updated; Sorbet and Steep remain independently required; and the configurable eight-worker Steep command, cache invalidation, pinned actions, least-privilege/fork behavior, and exact-head CI results all check out.
Summary
xargsRuboCop fan-out with one native parallel RuboCop invocationruby/setup-rubyBundler cache for every Ruby jobscripts/lintpass-through wrapper and use the canonical Rake taskci / ci-requiredaggregate checkWhy
On PR #326, the lint job took 6m24s end to end. Its explicit
bundle installtook 31s, and the combined RuboCop/Sorbet/Steep step took 5m45s. The three tools competed for one runner, while thexargsRuboCop batches each enabled RuboCop's own parallel execution.This change isolates the tools on separate runners, removes nested RuboCop process pools and a redundant shell wrapper, and caches both gems and RuboCop results.
CI results
Measured from GitHub Actions timestamps, comparing PR #326's run with this PR:
Steep is now the remaining critical path. The four-worker run took 4m51s; two eight-worker runs took 4m35s and 3m33s. The range reflects normal hosted-runner variance, so the PR reports the observations rather than attributing all of the difference to worker count.
Validation
bundle exec rake lint:rubocopbundle exec rake typecheck:sorbetCI=1 STEEP_JOBS=8 bundle exec rake typecheck:steep./scripts/test— 468 runs, 1,514 assertionsbundle exec rake build:gemactionlint .github/workflows/ci-checks.ymlshellcheck scripts/detect-breaking-changesLocal RuboCop benchmark
Same checkout, Ruby 3.3.12, RuboCop 1.81.7, 16 CPUs, separate empty/restored cache directories:
xargsbatches