Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Static code analysis via Rubocop #857

Conversation

klappradla
Copy link
Member

Related to the discussion in #845, this adds static code analysis via Rubocop as an additional step in the CI pipeline (a super fast step though, no worries).

Please see the commit history and the .rubocop.yml file in this PR for the details on which cops are enabled and which I already ran.
Rubocop has a large list of per-default enabled cops. Since the number of cops we want to have enabled is rather small, I instead of manually disabling the ones we don't want, disabled all and just added some specific ones. The file is rather large, since I also included the description and link to the styleguide for each cop. I thought it could be more helpful for newcomers or people coming to the list from the contribution guide.

From @carpodaster's initial list of cops, I for now skipped everything related to specs since it would require another gem (I can do this once we agreed on the setup for the app code) and did not enable the one for line length and the frozen string literal comment, since this would basically touch every file in the repo 🙈 (I'd then also do this in a separate PR).

Aside that, I also enabled some very basic cops related to things like trailing whitespaces, indentation, etc. (see the file and the commit history for details).

I also update the Readme and Contribution guide to include all this ☝️

Add instructions for running code analyzers and some general cleanup.
@emcoding
Copy link
Member

Wow Max, that is an amazing job! Thank you!! 🎁
My future self is already immensely grateful. 😛

I feel you added some great cops (re: Ruby/Rails conventions), and also some that are probably up for debate; for instance one that I don't see as an important thing, and even one that I don't like at all 🙊 :trollface:
I don't name them, because my concern is: how are we going to prevent lengthy discussions about the extra cops? Especially because that was one of the concerns when we talked about introducing
Rubocop in the first place.
So, is it okay if I just review the code, and refrain from adding opinions on the cops itself? Or did you actually hope to get second opinions? Because then we should think of something to address that.

Either way, I am really stoked about getting Rubocop. Dev Happiness Score: 💯

@klappradla
Copy link
Member Author

Well, I neither have any expectations, nor do I share your concerns @F3PiX. So feel free to comment as you wish ✌️

Copy link
Member

@emcoding emcoding left a comment

Choose a reason for hiding this comment

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

Again, big thanks Max!
I added some suggestions, mostly for some details in descriptions.
And I added a lean 'votes' system for the cops you introduced, either a 😍 for cops I really love, or a 😢 for things I'd rather leave out.

Naming/ClassAndModuleCamelCase:
Description: "Use CamelCase for classes and modules."
StyleGuide: "#camelcase-classes"
Enabled: true
Copy link
Member

Choose a reason for hiding this comment

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

😍

Description: "Constants should use SCREAMING_SNAKE_CASE."
StyleGuide: "#screaming-snake-case"
Enabled: true

Copy link
Member

Choose a reason for hiding this comment

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

😍

Description: "Checks for trailing comma in argument lists."
StyleGuide: "#no-trailing-params-comma"
Enabled: true

Copy link
Member

Choose a reason for hiding this comment

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

😢

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, I don't understand your concern about this cop. What's the benefit of

def foo(bar,)
  # do stuff
end

over

def foo(bar)
  # do stuff
end

???

You can run rubocop -a and it will automatically remove these commas for you.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe I misunderstood. I thought it were about the kind of comma's at the end of this line https://github.com/rails-girls-summer-of-code/rgsoc-teams/pull/857/files#diff-ea406fc966c043b0342994808d837c01L65
Of course I don't weep about the example you give above 😂

@@ -57,7 +57,7 @@ def set_team

def set_role
@role = if params[:id]
@team.roles.find(params[:id])
@team.roles.find(params[:id])
else
Copy link
Member

Choose a reason for hiding this comment

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

Is this alignment a cop rule or a typo? (also in next 2 files)

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

@klappradla klappradla Sep 17, 2017

Choose a reason for hiding this comment

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

The 2 spaces indentation is based on the if... The "normal" way of formatting this would be:

@role = if params[:id]
          @team.bla
        else
          # other
        end

But I did not want to enforce this via another cop, so it looks kinda weird here. I can manually change it to the above.

@@ -60,7 +60,7 @@ def set_team

def set_sources
@sources = if @team
@team.sources
@team.sources
else
Copy link
Member

Choose a reason for hiding this comment

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

☝️ = see above

.rubocop.yml Outdated
Enabled: true

Layout/CaseIndentation:
Description: "Indentation of when in a case/when/[else/]end."
Copy link
Member

Choose a reason for hiding this comment

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

Maybe include in the description, something like: align when/else/end/ with case. ?
To make it easier to understand what we are suppose to do about it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I in 99% of cases just directly copied over the description from Rubocop's internal default rule set. Not sure if it makes sense to tweak them and do a lot of changes to them. For most cases the thing that helps explaining / understanding these rules best are examples - and they can be found in the Rubocop docs or the styleguide (also referenced for each rule).

So my idea was to keep the task of explaining things to the part the knows it best - naming the docs / styleguide - and not try to explain it in detail here.

But yeah, I still can do it if you think there's a huge benefit in having it.

Copy link
Member

Choose a reason for hiding this comment

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

Sure, let's leave it at the documentation! 👍

.rubocop.yml Outdated
Enabled: false

Style/HashSyntax:
Description: "Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax"
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a beginner friendly { :a => 1, :b => 2 } after 1.8 syntax in the description?

Enabled: true
Include:
- "**/Gemfile"
- "**/gems.rb"
Copy link
Member

Choose a reason for hiding this comment

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

👍 Love that we cover this already 👯

Copy link
Member

Choose a reason for hiding this comment

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

I had to google what gems.rb is all about. Good stuff, looking forward to it!


Bundler/DuplicatedGem:
Description: "Checks for duplicate gem entries in Gemfile."
Enabled: true
Copy link
Member

Choose a reason for hiding this comment

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

😍

Copy link
Member

Choose a reason for hiding this comment

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

Oh, that's a good one, yes

AllCops:
TargetRubyVersion: 2.4
DisabledByDefault: true

Copy link
Member

Choose a reason for hiding this comment

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

Are there any files or directories that we should exclude? I know the db/schema.rb is sometimes excluded, but I don't know why TBH.

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right, normally one would exclude e.g. the db and bin directories, just because the code there is not really regarded as "app code" and linting it often times does not make too much sense.

In our case, since we disable all cops, this is not really a problem for now. We don't have any cops that could be problematic for the schema file, migrations or the bin directory.

Copy link
Member

Choose a reason for hiding this comment

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

Aha 💡 . Thanks 🙇

@emcoding
Copy link
Member

How about we set up CodeClimate ? That was my initial idea for Rubocop. It is free for Open Source.

Copy link
Member

@carpodaster carpodaster left a comment

Choose a reason for hiding this comment

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

That's a job extremely well done – ¡Muchas gracias, señor! 💚 💜 ❤️

I added a few comments, but I'm also totally down to merge this as is.

Enabled: true
Include:
- "**/Gemfile"
- "**/gems.rb"
Copy link
Member

Choose a reason for hiding this comment

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

I had to google what gems.rb is all about. Good stuff, looking forward to it!

CONTRIBUTING.md Outdated
@@ -94,7 +92,8 @@ If you've cloned the app a while ago, you want to make sure that your cloned `ma

### Write Code

We aim to follow the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) but we don't enforce it (i.e. there is no [RuboCop](https://github.com/bbatsov/rubocop)). The most important thing is probably just proper indentation: two whitespaces.
We aim to follow the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) and have [RuboCop](https://github.com/bbatsov/rubocop) set up to make sure we stay consistent with some basic rules (see our [rubocop.yml](https://github.com/rails-girls-summer-of-code/rgsoc-teams/blob/master/.rubocop.yml) file for details).
But don't be afraid, the most important thing is probably just proper indentation: two whitespaces ✌️
Copy link
Member

Choose a reason for hiding this comment

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

👍 to @F3PiX's suggestion

@@ -11,6 +11,7 @@ def update
end

private

def attendance_params
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this extra level of indentation be caught by RC?

Copy link
Member Author

@klappradla klappradla Sep 17, 2017

Choose a reason for hiding this comment

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

Yes, but it's a different cop we don't yet have. But if we already have the one for a blank line before access modifiers and its indentation, it just makes sense to also add the one for proper (in my opinion 😉) indentation after it as well.

I'll add it ✌️


# TODO
Metrics/LineLength:
Description: "Limit lines to 80 characters."
Copy link
Member

Choose a reason for hiding this comment

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

I know it's flagged as TODO and disabled, but should we up the limit to 100-something?

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe 120? Not sure what really makes sense... Currently we have 215 that's why it's a bit of an effort and I did not want to run it right away.


Bundler/DuplicatedGem:
Description: "Checks for duplicate gem entries in Gemfile."
Enabled: true
Copy link
Member

Choose a reason for hiding this comment

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

Oh, that's a good one, yes

.travis.yml Outdated
@@ -17,6 +17,7 @@ before_script:
- npm install -g jshint
script:
- bundle exec rake spec
- bundle exec rubocop
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should use CodeClimate to run the cops; IMHO it gives better feedback on Github PRs: you get two CI results. Travis may run the specs just fine, it may "just" be coding style that needs improvement.

I have never set up CodeClimate with custom rules, though. If we cannot reuse our rubocop.yml, it's not worth pursuing this.

Copy link
Member

Choose a reason for hiding this comment

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

I think it works like this: we add a codeclimate.yml where we enable rubocop (and a js linter), and then cc uses our rubocop.yml for the rules.

Copy link
Member

Choose a reason for hiding this comment

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

If it is that easy, I'd prefer CC over running it on Travis

Copy link
Member Author

Choose a reason for hiding this comment

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

Just for the sake of completeness: I just came across build stages for Travis. Would also solve the problem I think.

Copy link
Member

Choose a reason for hiding this comment

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

I'll make a separate issue to discuss/decide on the CodeClimate way. Get it out of the way of merging this. 🎉

@@ -43,7 +43,7 @@ def current_team

def current_drafts
@current_drafts ||= if current_team
current_team.application_drafts.in_current_season
current_team.application_drafts.in_current_season
Copy link
Member

Choose a reason for hiding this comment

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

I think it is, but I cannot name it. I really like this way of indentation. Vim's Ruby syntax auto-formats blocks like this in exactly the same way.

Switch pipeline order: lint before tests

close 845
@klappradla klappradla force-pushed the feature/845-discussion-static-code-analysis-via-rubocop-codeclimate branch from 7ae7d7b to 09aa0e9 Compare September 18, 2017 20:39
@klappradla klappradla merged commit db178cf into master Sep 18, 2017
@klappradla klappradla deleted the feature/845-discussion-static-code-analysis-via-rubocop-codeclimate branch September 18, 2017 20:43
@emcoding
Copy link
Member

🎉 🎉 🎉

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants