Skip to content

About

Gusto's custom Rubocop as Open Source Software

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

166 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RuboCop::Gusto

Gem Version Build GitHub Release

Gusto's custom RuboCop cops and shared configuration, distributed as a gem and integrated via the lint_roller plugin interface.

Installation

Add this line to your application's Gemfile:

gem 'rubocop-gusto', require: false

And then execute:

$ bundle

Usage

rubocop-gusto ships with a CLI that sets up your project's .rubocop.yml:

bundle exec rubocop-gusto init

This adds rubocop-gusto to your .rubocop.yml plugins: list and includes any relevant configuration (e.g. Rails-specific rules when Rails is detected, Sidekiq-specific rules when the Sidekiq gem is present).

If this is an existing project, it is recommended to run the autocorrector (bundle exec rubocop -a) and then to regenerate the .rubocop_todo.yml (bundle exec rubocop --auto-gen-config), so issues can be dealt with piecemeal.

GraphQL configuration

The Gusto/Graphql cops lint the graphql-ruby schema DSL. They live in config/graphql.yml, which also configures the GraphQL cops from rubocop-graphql — several of them cops Gusto contributed upstream rather than keep here. Neither is in config/default.yml, so projects without a GraphQL schema are not linted for those patterns.

Running bundle exec rubocop-gusto init does all of it when graphql is in your Gemfile or Gemfile.lock: adds rubocop-graphql to your Gemfile and plugins: list, and adds config/graphql.yml to your inherit_gem list. rubocop-graphql is deliberately not a dependency of this gem, for the same reason rubocop-rails is not — so rubocop-gusto stays usable from a plain gem.

GraphQL/DisallowedTypes is where a project names the types it has decided not to expose. It is inert until configured, and the reason is per type, so it needs no Details::

GraphQL/DisallowedTypes:
  Types:
    Float: 'Use MyApp::GraphQL::Scalars::Decimal, which serializes as a string.'
    MyApp::Scalars::LegacyDate: 'Use GraphQL::Types::ISO8601Date.'

By default the Gusto/Graphql department is scoped to **/graphql/**/*. Gusto/Graphql/ResolverIgnoresObject reads NodeAccessors, which lists methods your GraphQL base classes provide that read the node without naming object; leave it empty and the cop reports those resolvers as offenses.

Several of these cops replace a project-specific convention with a generic message. Put the convention your project actually follows in the cop's Details:, and set AllCops: ExtraDetails: true so it is appended to the offense message:

AllCops:
  ExtraDetails: true

Gusto/Graphql/PaginateArrays:
  Details: 'Use `paginated_list(<Type>)`, or `non_paginated_list(<Type>)` for a bounded list.'

Sidekiq configuration

Sidekiq-specific cops live in config/sidekiq.yml and are not included in config/default.yml, so projects without Sidekiq are not linted for those patterns. Running bundle exec rubocop-gusto init adds config/sidekiq.yml to your inherit_gem list automatically when Sidekiq is listed in your Gemfile or Gemfile.lock.

For an existing project that already uses Sidekiq, add the Sidekiq config to your .rubocop.yml:

inherit_gem:
  rubocop-gusto:
    - config/default.yml
    - config/sidekiq.yml

If your project also uses Rails, include config/rails.yml as well (order does not matter). Re-run bundle exec rubocop-gusto init to merge this in automatically.

Logging configuration

The Gusto/Logging cops report likely sensitive data in Rails.logger, Sidekiq.logger, and bare logger calls, including chained .tagged(...) loggers and message blocks. Each cop has its own severity, exclusions, todo entries, and inline disables:

  • PiiAccessor checks configured PII methods such as user.email.
  • RawParams checks unfiltered params, including serialization and require without narrowing.

All ship at Severity: info, which does not fail RuboCop at its default failure threshold. Spec and test files are excluded. Promote each cop independently after reviewing its hits; for example, set Gusto/Logging/PiiAccessor: Severity: warning in your project configuration. Configure PiiMethods on Gusto/Logging to customize the shared sensitive-method list.

These are syntax-based heuristics: selecting a params key is allowed, not proof that it is safe; plain local variables and values assembled outside the log call may escape detection.

Available cops

Custom cops live under the following namespaces:

Publishing New Versions

Releases are fully automated via release-please.

How it works:

  1. Merge PRs to main using Conventional Commits in the PR title (enforced by CI).
  2. release-please automatically creates and maintains a "Release PR" that bumps the version and updates the changelog.
  3. When you merge the Release PR, a GitHub Release and git tag are created, and the gem is published to RubyGems.

Conventional commit types and version bumps:

PR title prefix Version bump Example
feat: Minor (10.8.0 -> 10.9.0) feat: add Gusto/NewCop cop
fix: Patch (10.8.0 -> 10.8.1) fix: correct false positive in DefaultScope
feat!: or BREAKING CHANGE footer Major (10.8.0 -> 11.0.0) feat!: drop Ruby 3.1 support
chore:, docs:, ci:, etc. No release chore: update dev dependencies

Contributing

Submit new rules, updated configuration, and other checks to be used organization wide by submitting a Pull Request!

PR titles must use Conventional Commits format (enforced by CI) — see the version bump table above for which prefixes trigger releases.

Adding a new cop

  1. Create lib/rubocop/cop/gusto/<cop_name>.rb, see how to create a new cop and how to choose a name
  2. Add an entry to config/default.yml, then sort it:
    bundle exec rubocop-gusto sort config/default.yml
  3. Add a spec in spec/rubocop/cop/gusto/<cop_name>_spec.rb
  4. Run tests and lint:
    bundle exec rspec
    bundle exec rubocop

Versioning policy

rubocop-gusto generally follows semver, with the exception that the only thing that is considered a breaking change is a change in the public API to use rubocop-gusto.

Users can generally expect to need to regenerate their rubocop todo when they make a minor version bump to rubocop-gusto.

Git pre-commit hooks

git config core.hooksPath script/githooks

About

Gusto's custom Rubocop as Open Source Software

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages