Skip to content

Modernize dependencies and fix Ruby 4.0 CI#90

Open
dduugg wants to merge 17 commits intomainfrom
modernize-ruby-and-fix-ci
Open

Modernize dependencies and fix Ruby 4.0 CI#90
dduugg wants to merge 17 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

2 participants