Skip to content

Modernize dependencies and fix Ruby 4.0 CI#90

Merged
dduugg merged 18 commits intomainfrom
modernize-ruby-and-fix-ci
Mar 10, 2026
Merged

Modernize dependencies and fix Ruby 4.0 CI#90
dduugg merged 18 commits intomainfrom
modernize-ruby-and-fix-ci

Conversation

@dduugg
Copy link
Contributor

@dduugg dduugg commented Mar 5, 2026

Summary

CI was failing because `minitest-5.16.3` requires `ruby < 4.0`, but the shared CI workflow now tests against Ruby 4.0.1. This follows the same process used in rubyatscale/packwerk-extensions#62.

Dependency updates:

  • Update all outdated gems via `bundle update`: activesupport 7→8.1, rubocop 1.36→1.85, rubocop-sorbet 0.8→0.12, rubocop-ast 1.21→1.49, minitest 5.16→6.0, sorbet/tapioca, and many more
  • Bump `required_ruby_version` in gemspec from `>= 2.7` to `>= 3.2` to match lowest CI Ruby version
  • Remove bundler version constraint (`~> 2.2.16`) in gemspec — incompatible with bundler 4.0.7

Bug fixes required by updated gems:

  • Fix `TypedPublicApis` spec: removed `let(:config) { RuboCop::Config.new }` override that replaced the `:config` shared context's properly-constructed config with a bare `RuboCop::Config.new`, which inherits `Enabled: false` from `config/default.yml`. In rubocop 1.85.1, `Registry#enabled?` strictly checks `== true` so the cop never ran.
  • Fix `DocumentedPublicApis` cop: rubocop-ast 1.49.0 extended `non_public_modifier?` to also match `:private_class_method`. This caused `private_class_method def self.bar` to be treated as non-public, silently suppressing offenses for methods in `app/public`. Removed the `non_public?` guard — the cop is already restricted to `app/public` files where everything should be documented regardless of Ruby visibility.

Sorbet/Tapioca:

  • Bump tapioca to 0.17.10 (requires spoom >= 1.7.9, which requires rbs >= 4.0.0.dev.4)
  • Regenerate all tapioca RBI files for updated gem versions
  • Add `sorbet/tapioca/config.yml` excluding `bundler`, `didyoumean`, and `msgpack` from tapioca gem RBI generation — these already have shims in sorbet's built-in RBI library
  • Verified `srb tc` passes with no type errors

Linting:

  • Add `rubocop-gusto` as a development dependency and plugin in `.rubocop.yml` (replaces `require: rubocop-sorbet`; rubocop-gusto transitively includes rubocop-sorbet)
  • Add `inherit_mode`, `inherit_gem` config to `.rubocop.yml`
  • Remove disabled Layout cops (`LineLength`, `MultilineMethodCallIndentation`, `FirstArgumentIndentation`, `ArgumentAlignment`) from `.rubocop.yml` and autocorrect resulting violations
  • Autocorrect rubocop offenses throughout; regenerate `.rubocop_todo.yml` for remaining violations

Rake task:

  • Refactor `tasks/cop_documentation.rake`: replace `define_method` calls (flagged by `Gusto/NoMetaprogramming`) with a `CopDocumentation` module using `self.` methods; extend `Rake::DSL` so `sh` is available without passing the task context as a parameter

Housekeeping:

  • Remove `.DS_Store` from git tracking (`.DS_Store` is a per-user concern and belongs in each developer's global gitignore, not the project's `.gitignore`)
  • Remove `spec/rubocop/packs_spec.rb` — the file contained only a `before` hook with no examples; `rubocop-rspec` correctly identified it as an empty example group
  • Regenerate binstubs with current bundler (`bundle binstubs rubocop tapioca --force`)

Fixes https://github.com/rubyatscale/rubocop-packs/actions/runs/22733673075/job/65929220506

🤖 Generated with Claude Code

- Update gems to fix Ruby 4.0 incompatibility (minitest 5.16.3 required < 4.0)
- Bump required_ruby_version in gemspec from >= 2.7 to >= 3.2
- Remove bundler version constraint in gemspec
- Autocorrect 36 rubocop offenses; generate .rubocop_todo.yml for remaining 9
- Fix TypedPublicApis spec: remove config override that disabled the cop
  (rubocop 1.85.1 strictly respects Enabled: false, unlike 1.36.0)
- Fix DocumentedPublicApis cop: remove non_public? check that incorrectly
  suppressed offenses for `private_class_method def self.bar` after
  rubocop-ast 1.49.0 added :private_class_method to non_public_modifier?
- Remove .DS_Store from repo and add to .gitignore

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@dduugg dduugg requested a review from a team as a code owner March 5, 2026 20:24
@github-project-automation github-project-automation bot moved this to Triage in Modularity Mar 5, 2026
dduugg and others added 15 commits March 5, 2026 12:33
Update tapioca to 0.17.10 (requires spoom >= 1.7.9 and rbs >= 4.0.0.dev.4)
and regenerate all tapioca RBI files to match updated gem versions.

Also verified `srb tc` passes with no type errors.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…icApis

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replace `require: rubocop-sorbet` with `plugins: rubocop-gusto` in
.rubocop.yml (rubocop-gusto transitively includes rubocop-sorbet).
Autocorrect 78 new offenses; regenerate .rubocop_todo.yml for the rest.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Explanation moved to a PR comment instead.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… defs

Move all helper methods out of the Rake task block and define them at
the file's top level using regular `def`. This resolves Gusto/NoMetaprogramming
and Lint/CopDirectiveSyntax offenses, removes both from .rubocop_todo.yml.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Avoids polluting the root namespace by wrapping all helper methods
in a CopDocumentation module with self. methods, called explicitly
from the Rake task blocks.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add sorbet/tapioca/config.yml excluding bundler, didyoumean, and msgpack,
which already have shims in https://github.com/sorbet/sorbet/tree/master/rbi/gems.
rake is not excluded despite having a sorbet shim because the tapioca-generated
rake RBI defines Rake::DSL and Rake::FileUtilsExt that other gems (thor) depend on.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
extend Rake::DSL so sh is available as a module-level method,
removing the need to pass the task context as a parameter.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
.DS_Store should be handled by each user's global gitignore, not
tracked in the project's .gitignore.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The rubocop autocorrector split these across lines but left the
indentation inconsistent. Since Layout/LineLength is disabled there
is no reason to split them in the first place.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replaces hand-edited binstubs with clean output from
`bundle binstubs rubocop tapioca --force`.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Remove Layout/LineLength, Layout/MultilineMethodCallIndentation,
Layout/FirstArgumentIndentation, and Layout/ArgumentAlignment from
.rubocop.yml. Autocorrect the 6 resulting violations.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Ensures Exclude/Include lists in .rubocop_todo.yml are merged with
those in .rubocop.yml rather than overriding them.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
def check(node)
# This cop only applies for ruby files in `app/public`
return if !processed_source.file_path.include?('app/public')
return if non_public?(node) && !require_for_non_public_methods?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parent class Style::DocumentationMethod has this guard to skip Ruby-private/protected methods when RequireForNonPublicMethods is not configured — it makes sense globally, where you may not want to enforce documentation on every private method across an entire codebase.

This cop is already restricted to app/public files, so the guard is semantically wrong here: a method like private_class_method def self.bar is Ruby-private but pack-public — it's part of the pack's public API surface and should always be documented.

The line was harmless until rubocop-ast 1.49.0 extended non_public_modifier? to also match :private_class_method (previously only :private and :protected matched). After that change, non_public?(node) returned true for private_class_method def self.bar, causing the guard to silently suppress offenses for methods in app/public.

The file contained only a before hook with no examples.
rubocop-rspec flagged it as an empty example group and autocorrect
had already stripped the body, leaving only the typed sigil.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@dduugg
Copy link
Contributor Author

dduugg commented Mar 5, 2026

spec/rubocop/cop/packs/typed_public_apis_spec.rb — removal of let(:config) { RuboCop::Config.new }

This override replaced the config provided by RuboCop's :config shared context with a bare RuboCop::Config.new. The shared context sets Enabled: true for the cop under test, but RuboCop::Config.new inherits Enabled: false from config/default.yml (where all cops in this gem default to disabled so they must be explicitly opted into).

In rubocop 1.36.0 this was harmless — the cop ran regardless. In rubocop 1.85.1, Registry#enabled? strictly checks cfg.fetch('Enabled') == true and excludes the cop from the run entirely. The result was that the test expecting an offense passed vacuously (no cop ran, no offense reported, expect_no_offenses trivially satisfied) while the test expecting an offense silently failed.

Removing the override lets the :config shared context supply a properly-constructed config with Enabled: true.

@dduugg dduugg enabled auto-merge (squash) March 6, 2026 15:51
@dduugg dduugg merged commit 211fa96 into main Mar 10, 2026
5 of 7 checks passed
@dduugg dduugg deleted the modernize-ruby-and-fix-ci branch March 10, 2026 18:38
@github-project-automation github-project-automation bot moved this from Triage to Done in Modularity Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants