Skip to content

All cops should have documentation

Summary

All cops should have documentation so that developers can understand the rationale behind them, how to fix them, and when they can be ignored. Historically, we have linked to new cop proposal issues for this, but this does not age well and does not present information in a consistent way.

Proposal

I think we can annotate cops similar to what we do for sidekiq workers, then auto-generate documentation based on these annotations. For example, CodeReuse/ActiveRecord can be annotated like so:

# frozen_string_literal: true

module Rubocop
  module Cop
    module CodeReuse
      class ActiveRecord < OurBaseClassWhichImplementsAnnotations
        purpose 'This cop denies the use of ActiveRecord methods outside of models.'
        rationale 'Models should [encapsulate of data-layer logic](https://docs.gitlab.com/ee/development/reusing_abstractions.html#models).'
        bad_examples 'Project.where(archived: true)'
        good_examples 'Project.archived'
        when_to_disable <<~MARKDOWN
          This cop can be disabled if the caller is not an ActiveRecord model,
          or if the code is used in a highly specific context that is unlikely
          to be re-used. For example, the `.joins()` and `.where()` statements
          for a query with a lateral join is unlikely to be re-used elsewhere in the codebase.

          ```ruby
          ::Ci::Runner.joins("JOIN LATERAL (#{lateral_query.to_sql}) builds_with_limit ON true")
            .id_in(runner_ids)
            .select(:id, Arel.star.count.as('count'))
            .group(:id)
            .index_by(&:id)
          ```
        MARKDOWN

        [... cop source]
      end
    end
  end
end

We can then use ERB to auto-generate documentation for each cop, and link to these docs in the cop's message:

## `<%= cop_name =>`

<%= purpose =>

### Rationale

<%= rationale =>

### Examples

Good

```ruby
<%= good_examples =>
```

Bad

```ruby
<%= bad_examples =>
```

### When to disable

<%= when_to_disable =>

Continuation of: !227 (comment 2082367394)