Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Cops for brew audit #1873

Merged
merged 4 commits into from
Feb 12, 2017
Merged

Conversation

GauthamGoli
Copy link
Contributor

@GauthamGoli GauthamGoli commented Jan 18, 2017

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew tests with your changes locally?

This PR implements Custom Cops for a simple rule in brew audit command as discussed in #569

revision in a bottle do block should be renamed to rebuild and Rubocop should autocorrect it to rebuild

More rules can be added/migrated as cops, and RuboCop can be leveraged to check for style violations instead of regular expressions as being done currently when brew audit is ran.

Using --strict would check for CustomCop/style violations.
The newly added --fix option would automatically correct the source code if any CustomCop/style violations are found.

@GauthamGoli
Copy link
Contributor Author

Why did the build fail? brew tests on my local machine shows 0 errors.

@MikeMcQuaid
Copy link
Member

brew man needs run and brew style failed: https://travis-ci.org/Homebrew/brew/builds/192996433

@GauthamGoli
Copy link
Contributor Author

@MikeMcQuaid Now only brew tests --generic is failing in CI. Strangely , it doesn't fail and shows 0 errors when I run the same command locally.

@alyssais
Copy link
Contributor

@GauthamGoli don't worry about it. There's a test suite bug that causes that test to intermittently fail. #1879 fixes it.

@MikeMcQuaid
Copy link
Member

It's merged so rerunning these tests.

@GauthamGoli
Copy link
Contributor Author

@MikeMcQuaid What should I do for codecov check failures?

@MikeMcQuaid
Copy link
Member

@GauthamGoli You can ignore them for now 👍

method, _args, body = *node
_keyword, method_name = *method

return unless method_name.equal?(:bottle) && revision?(body)
Copy link
Member

Choose a reason for hiding this comment

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

Make this multiple returns.

lambda do |corrector|
# Check for revision
_method, _args, body = *node
if revision?(body)
Copy link
Member

Choose a reason for hiding this comment

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

next unless revision?(body)

def revision?(body)
body.children.each do |method_call_node|
_receiver, method_name, _args = *method_call_node
if method_name == :revision
Copy link
Member

Choose a reason for hiding this comment

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

return true if method_name == :revision

new_source = ""
node.source.each_line do |line|
if line =~ /\A\s*revision/
line = line.sub("revision", "rebuild")
Copy link
Member

Choose a reason for hiding this comment

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

line.sub!("revision", "rebuild")

def replace_revision(corrector, node)
new_source = ""
node.source.each_line do |line|
if line =~ /\A\s*revision/
Copy link
Member

Choose a reason for hiding this comment

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

Maybe next unless line =~ /\A\s*revision/?

Copy link
Contributor Author

@GauthamGoli GauthamGoli Jan 23, 2017

Choose a reason for hiding this comment

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

next cannot be used I think because on line 42 , the current line is being appended to new_source

Copy link
Member

Choose a reason for hiding this comment

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

Yeh, sorry, 👍

new_source << line
line.sub!("revision", "rebuild")
end
new_source << line
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like something weird's happened to your indentation here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah! Mix up of spaces and tabs due to opening in different editors. Fixing it.

@MikeMcQuaid
Copy link
Member

Tested locally. The user experience here is amazingly good.

@reitermarkus @jawshooah you may want to consider this approach instead of a separate gem; if they have editor Rubocop integration with this one they'll just start seeing these warnings immediately with zero configuration.

@alyssais
Copy link
Contributor

@MikeMcQuaid you just inspired me to set up Rubocop in my editor. This is amazing!

Nice work @GauthamGoli! 👏

@alyssais
Copy link
Contributor

alyssais commented Jan 23, 2017

One thing: when I test this with a bottle block, my editor highlights bottle rather than rebuild, which doesn't seem quite right. Is that just a problem with my editor's RuboCop integration, or is it fixable?

method, _args, body = *node
_keyword, method_name = *method

return unless method_name.equal?(:bottle)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should prefer #== over #equal?.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Pushed the updated code.

@GauthamGoli
Copy link
Contributor Author

@alyssais Are you using Emacs?

end

def revision?(body)
body.children.each do |method_call_node|
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be body.children.any? instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Pushed the updated code.

@alyssais
Copy link
Contributor

@GauthamGoli I'm using Sublime Text 3 with SublimeLinter-rubocop.

@GauthamGoli
Copy link
Contributor Author

@alyssais Able to reproduce this. I think its because, I used on_block method in the custom cop to detect usage of revision inside a bottle do block. As of now, I don't know how to make it highlight revision as the documentation of rubocop on writing custom cops is not so clear for me.

@alyssais
Copy link
Contributor

@GauthamGoli fair enough. Let's forget about it for now, then, it's not a big deal. :)

@GauthamGoli
Copy link
Contributor Author

@alyssais I found a fix for this. Will update the code and push it in sometime!

@GauthamGoli GauthamGoli force-pushed the audit_custom_cops branch 2 times, most recently from bf74c61 to 4321b6b Compare January 25, 2017 05:08
@GauthamGoli
Copy link
Contributor Author

@alyssais Now the linter should highlight revision
@MikeMcQuaid @dunn The code has been simplified. Please review it.

def check_revision?(body)
body.children.each do |method_call_node|
_receiver, method_name, _args = *method_call_node
if method_name == :revision
Copy link
Member

Choose a reason for hiding this comment

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

Could do next unless method_name == :revision to avoid indentation and end

@MikeMcQuaid
Copy link
Member

@MikeMcQuaid @dunn The code has been simplified. Please review it.

Looks much better/simpler, thanks!

docs/brew.1.html Outdated
run before submitting a new formula.</p>

<p>If no <var>formulae</var> are provided, all of them are checked.</p>

<p>If <code>--strict</code> is passed, additional checks are run, including RuboCop
style checks.</p>
style checks and custom cop checks.</p>
Copy link
Member

Choose a reason for hiding this comment

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

This is a bit redundant, since custom checks are still RuboCop style checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right. Fixed it.

@@ -6,6 +6,12 @@ AllCops:
- '**/Casks/**/*'
- '**/vendor/**/*'

require:
- ./Homebrew/rubocops/bottle_block_cop.rb
Copy link
Member

Choose a reason for hiding this comment

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

Let's maybe require a since Homebrew/rubocops.rb which in turn includes all our custom cops (just this one for now but we'll add more).

Copy link
Member

Choose a reason for hiding this comment

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

Also could just do on a single line like require: ./Homebrew/rubocops.rb perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I was thinking of creating another another .yml file(which will have all custom cops) andrequire it inside .rubocop.yml as the custom cops grow in number. Your idea of require on rubocops.rb is seems much better, but then we'd have to place all the cops in a single huge rubocops.rb rather than having individual files. If thats not a problem, I'll go ahead and change it.

Copy link
Member

Choose a reason for hiding this comment

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

but then we'd have to place all the cops in a single huge rubocops.rb

Not really, we just require all of the individual cops inside rubocops/ with this file, so we don't have to do that inside the YAML file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, cool. On my way to make the above changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Facing an error when implementing the above: in `<module:Cop>':superclass must be a Class (Module given) (TypeError) , trying to find a work around.

Copy link
Contributor

Choose a reason for hiding this comment

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

@GauthamGoli feel free to post your code if you need a hand working it out! :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alyssais I created Library/Homebrew/rubocops.rb, and it has a single line Dir[File.dirname(__FILE__) + "/rubocops/*.rb"].each {|file| require file }

Line 10 in Library/.rubocop.yml is now - ./Homebrew/rubocops.rb

Now just run brew audit --strict <someformula> to see the error.
Further debugging shows the error is thrown at line 72 in /Homebrew/cmd/style.rb
and I think the issue is being unable to require bottle_block_cop.rb

Copy link
Contributor

Choose a reason for hiding this comment

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

@GauthamGoli it's failing because of this error:

Error: obsolete parameter IndentWhenRelativeTo (for Style/CaseIndentation) found in /Users/alyssa/code/brew/Library/.rubocop.yml
`IndentWhenRelativeTo` has been renamed to `EnforcedStyle`
obsolete parameter AlignWith (for Lint/EndAlignment) found in /Users/alyssa/code/brew/Library/.rubocop.yml
`AlignWith` has been renamed to `EnforcedStyleAlignWith`

Copy link
Member

Choose a reason for hiding this comment

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

Let's just hard-code all the requires for now; dynamic requiring is a bit overkill for now.

@@ -0,0 +1,36 @@
module RuboCop
module Cop
module CustomCops
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to call this module Homebrew?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

module Homebrew has been used in Library/Homebrew/cmd/ and Library/Hombrew/dev-cmd/ , so I thought calling it as Homebrew might cause some sort of confusion/clash ( I am not sure) and named it as CustomCops

Copy link
Member

Choose a reason for hiding this comment

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

@GauthamGoli, this isn't really a problem as it's in another namespace. The only thing to look out for would be to reference the top-level module Homebrew with ::Homebrew inside Rubocop::Cop, but I think we don't even need it in this context.

Copy link
Member

Choose a reason for hiding this comment

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

this isn't really a problem as it's in another namespace

Agreed here.

@MikeMcQuaid MikeMcQuaid merged commit 674e5f1 into Homebrew:master Feb 12, 2017
@MikeMcQuaid
Copy link
Member

Great work here @GauthamGoli 👏!

@Homebrew Homebrew locked and limited conversation to collaborators May 3, 2018
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.

5 participants