Is there a way to do incremental linting with RuboCop? - ruby

I have a Ruby code base which has been maintained for many years. When I use RuboCop to check the code-style, it will give me thousands of offenses. Is there a way use RuboCop to check only the new added code or new modified code, and only report offenses for that code?

There are a couple of ways in which Rubocop can help you.
If you run
rubocop --auto-gen-config
Rubocop will generate two configuration files for you: a mostly empty .rubocop.yml, which only contains one key:
inherit_from: .rubocop_todo.yml
And a .rubocop_todo.yml which disables every offense found in your codebase on a per-file basis:
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2020-09-11 06:20:56 UTC using RuboCop version 0.90.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
# Cop supports --auto-correct.
Layout/SpaceAfterMethodName:
Exclude:
- 'test.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods.
Lint/UnusedMethodArgument:
Exclude:
- 'test.rb'
This file is used for two things:
If your organization's style guide differs from the default Rubocop config, you can cut&paste the offense from the TODO into the "real" config file and disable it permanently and globally.
You can use the TODO file as an actual TODO list, and remove the exclusions one-by-one and fix the offenses one-by-one whenever you have time to do them.
Note, however, that exclusions are file-based, not line-based, so you can only disable cops globally or per-file. When you make changes to an existing file, your newly added code will also have those cops disabled, so it is a good idea to enable linting of the file first and fix all existing offenses.
Also note that you will probably have to use the --exclude-limit COUNT option, because if there are more than COUNT files with the same offense, Rubocop will just disable it globally. The default is 15, so you should set it to a value that is higher than the total number of files in your project.
Another helpful parameter is
rubocop --safe-auto-correct --disable-uncorrectable
Which will safely auto correct all safely auto correctable offenses, and add comments to disable cops for non-correctable offenses.
However, I would argue that this is not actually Rubocop's job in the first place. Your reporting system should have a way of recording a "baseline", and only report deviations from that baseline.

I found that pronto-rubocop may do the job

Related

clang-format in VSCodium breaking when using some rules

I'm trying to define custom format rules, and for some reason clang-format reverts to the default rules, despite my file having no discernable mistakes.
More precisely, I'm trying to define use detailed rules for AlignConsecutiveDeclarations. This .clang-format file works :
AlignConsecutiveDeclarations: true
UseTab: "Always"
IndentWidth: 4
TabWidth: 4
And this one, which should give the exact same result, breaks and reverts to default format :
AlignConsecutiveDeclarations:
Enabled: true
UseTab: "Always"
IndentWidth: 4
TabWidth: 4
Am I doing something wrong ? Or is the extension broken ? My file seems completely valid to me, but I very well could be wrong. Also please note this is a deliberately reduced example, even when specifying more options, the rule still breaks the entire file.
I'm using VSCodium 1.75.0 on macOS 13.2.1, with the clangd extension version 0.1.23 ; as far as I have checked those are the latest versions of everything.
Looking at clangd's output in the console, this is what it says about the affected rule :
/Users/crysambrosia/Developer/Project/.clang-format:2:2: error: unknown enumerated scalar
Enabled: true
This changes to whatever the first variable is, no matter which one it is.
This option is available in clang-format 15. You seem to use the older clang-format. It's unclear from your question what clang-format do you uses. VSCode, macOS, clangd all their versions are unrelated to clang-format. Compare https://releases.llvm.org/14.0.0/tools/clang/docs/ClangFormatStyleOptions.html and https://releases.llvm.org/15.0.0/tools/clang/docs/ClangFormatStyleOptions.html in two browser tabs. You will see the difference.

Find what settings influence a given Pylint message

When Pylint warns me about something, how can I know what settings it's applying? And what section of .pylintrc this setting goes in?
For example:
Used builtin function 'map'. Using a list comprehension can be clearer. (bad-builtin) is because bad-functions in [BASIC] contains map.
Missing function docstring (missing-docstring) is conditional on docstring-min-length in [BASIC].
invalid-name obeys several [BASIC] settings: variable-rgx, method-rgx, module-rgx, etc.
I expected to find this information in the Pylint documentation but it generally doesn't provide this information. For example, there's no link from the documentation of missing-docstring or invalid-names to the applicable options. With bad-builtin, the information is easy to find, but only because it's from a specific extension. The Pylint message wiki has explanations about what the message means, but not what brought it up. The comments in pylint --generate-rcfile don't relate the settings to warning codenames either (nothing there explains that e.g. bad-functions influences the bad-builtin message).
The reason I'm asking this is that in many cases, Pylint's conventions don't match my project's needs and conventions, and I want to tune it rather than ignore specific instances or ignore messages wholesale (so I'm not looking for disable=!). So how do I find what to tune?
How do I find what to tune?
So it seems like you're asking about how you can determine the combination of factors that lead to a pylint message being raised. Using the bad-builtin example, a warning message that is not listed at all in the .pylintrc, a helpful verbose message would be:
bad-builtin: Used builtin function 'map'. Using a list comprehension can be clearer.
---> (Hypothetical) VERBOSE OUTPUT:
bad-builtin was raised because the bad-functions setting in your .pylintrc under the [BASIC] section contains the function map. If you want to "tune" this behavior look here.
Short answer: I am not sure this exists.
When you run pylint my_file.py the first thing it should tell you is the configuration file it is using. From there, you want to find the .pylintrc in use or else you want to create it. Otherwise it will be using the default configuration. If pylint does not tell you what config you are using you can figure out your current pylintrc configuration by running something like:
pylint --generate-rcfile &> output.txt
When you inspect output.txt it should look like this example pylintrc. It is organized into different categories. You can get more info on this without generating an rcfile by running pylint --long-help. The sections include:
[MASTER]
[MESSAGES CONTROL]
[REPORTS]
[BASIC]
[ELIF]
[TYPECHECK]
[FORMAT]
[MISCELLANEOUS]
[VARIABLES]
[LOGGING]
[SIMILARITIES]
[SPELLING]
[IMPORTS]
[DESIGN]
[CLASSES]
[EXCEPTIONS]
I am not sure what you mean by, "The Pylint message wiki has explanations about what the message means, but not what brought it up." When I run pylint on a file or in a code base it tells me exactly where the offending line is.
Then I usually either:
Fix the warning
Disable the warning
Modify the .pylintrc to meet my needs
If you want to tune a specific message type but you are not sure how to do so, then I think you are right that is something that could be better documented. The question: Is XYZ warning message 'tunable'? Or is the only option to fix OR disable? This page lists the pylint features but I do not see anything about bad built-in, for example, let alone the options that are available to apply to a message type.
UPDATE: I am not sure what version of pylint you are on, but it looks like the bad-builtin was specifically addressed in pylint version 1.6. I was going to say we should look at what is going on in the actual source code to generate this message, but I think that requires figuring out what version of pylint you are on first, then digging into the code, then figuring out how to tune it? I agree that the docs can be more clear on how to tune specific warnings:
The bad-builtin check was moved into an extension.
The check was complaining about used builtin functions which were
supposed to not be used. For instance, map and filter were falling
into this category, since better alternatives can be used, such as
list comprehensions. But the check was annoying, since using map or
filter can have its use cases and as such, we decided to move it to an
extension check instead. It can now be enabled through
--load-plugins=pylint.extensions.bad_builtin.

Which module to use to edit files - Ansible

I want to edit the configuration file of telegraf(system metrics collecting agent).
Telegraf comes in with a default config file which can be edited. There are many input and output plugins defined in there, which are commented out and can be added by removing the comments and also be customized.
I want to edit only some of the plugins defined there, not all of them. For example, consider this is the file,
[global]
interval='10s'
[outputs.influxdb]
host=['http://localhost:8086']
#[outputs.elasticsearch]
# host=['http://localhost:9200']
[inputs.netstat]
interface='eth0'
Now, I want to edit the 3 blocks, global, outputs.influxdb and inputs.netstat. I don't want to edit outputs.elasticsearch but also want that the block outputs.elasticsearch should remain in the file.
When Using Ansible, I firstly used Template module, but if I use that, then the commented data would be lost.
Then I used the ini_file module, instead of editing the already present block, it adds a new block even if it is already present, and results in something like this,
[outputs.influxdb]
host=[http://localhost:8086]
[outputs.influxdb]
host=[http://xx.xx.xx.xx:8086]
Which module is ideal for my scenario ?
There are several options, depending on your purpose.
The lineinfile - module is the best option, if you just want to add, replace or remove one line.
The replace - module is best, if you want to add, replace or delete several lines.
The blockinfile - module can add several lines, surrounded by markers.
If you only want to change two or three lines, you could use as many calls of lineinfile. To change a whole config file, I would recommend, like the commenters suggest, use the template - module.
Ok, if you really really want to avoid using templates, you could try to use replace and a regex like this:
- hosts: local
tasks:
- replace:
path: testfile
regexp: '^\[{{ item.category }}\]\s(.*)host(.*)$'
replace: '[{{ item.category }}]\n host=[{{ item.host }}]'
with_items:
- { category: 'outputs.influxdb', host: 'http://cake.com:8080' }
This, in its current form, would not necessarily handle more than one option under each category, but the regex can be modified to handle multiple lines.
As required, it will not touch the # commented lines. However, if you decide to enable some of the previously inactive sections, you might end up with a slightly messier configuration file that would include the instructions both commented and uncommented (shouldn't impact functionality, only 'looks'). You will also need to account for options that look like the example below (interleaved commented/uncommented values) and create regexes specially for those use-cases:
[section]
option1=['value']
# option2=['value']
option3=['value']
It highly depends on your use-case, but my recommendation remains that templates are to be used instead, as they are a more robust approach, with less chances of things going wrong.

How do I comment a line in /etc/sudoers file using Chef Recipe?

I want to comment "Defaults requiretty" line present in /etc/sudoers file using Chef. If it is already commented, the ruby code should skip commenting it. I'm using CentOS 6.7 operating system. So far I have done this in my recipe:
files = Dir.glob("/home/cent/etc/*")
files.each do |file_name|
text = File.read(sudoers)
replace = text.gsub!(/Defaults requiretty/, "#Defaults requiretty")
File.open(sudoers, "w") { |file| file.puts replace }
end
The correct solution is to use a template resource to control the file content, rather than performing differential updates against a distro-provided file. This ensures overall convergent behavior and makes it easier to mentally model the state of the system.
To expand on the other answers and comments. One of the principles of Chef is that cookbooks and recipes should idempotent and convergent. They specify the state you want your nodes to be in, they check what needs to be done to bring it into that state, and apply only those changes.
This logically makes sense, minimizes unnecessary changes and how Chef is structured to run under-the-hood.
Running the Ruby code in your example, will not add extra '#' symbols, but it will update your file everytime it is run. This is misleading and could have an impact if some application checks your file's update time to see if a config change has occurred.
The template resource suggested by #coderanger will only update the file if required. Also, a template is more likely clearer than some Ruby Code. This approach is how must other (good) Chef code works
We've got the answer!
ruby_block "replace_line" do
block do
file = Chef::Util::FileEdit.new("/etc/sudoers")
file.search_file_replace_line(/Defaults requiretty/, "#Defaults requiretty")
file.write_file
end
end

Custom syntax highlighting in Geany

I am trying to create custom syntax highlighting for Kivy '.kv' files in the Geany editor. Although the specific filetype seems irrelavant to the issue I'm having, as any efforts I make at getting syntax highlighting to work for a custom filetype results in a completely non-highlighted file. I believe I have done my homework on this, and nothing seems to work.
I have added the following to ~/.config/geany/filetype_extensions.conf
Kivy=*.kv;
I also have a custom type definition file named 'filetypes.Kivy.conf' in ~/.config/geany/filedefs/. I have tried basing this file off several of the stock type definition files in /usr/share/geany/ and the file never gets any syntax highlighting applied in Geany. Right now, just for experimentation's sake, my 'filetypes.Kivy.conf' file looks like this:
# For complete documentation of this file, please see Geany's main documentation
[settings]
# default extension used when saving files
extension=kv
# single comments, like # in this file
comment_single=#
[keywords]
# all items must be in one line
primary=size canvas
secondary=pos size
[indentation]
width=4
# 0 is spaces, 1 is tabs, 2 is tab & spaces
type=0
This is very loosly based on the stock XML definition file, but like I said I've tried many other stock files. In many cases I only changed the 'extension=' value to kv and still no highlighting was applied, even though going to Document>Set Filetype in Geany and choosing virtually any random filetype (besides my custom entry) would yeild some sort of highlighting within my .kv file. This is even the case when using the unmodified contents of a stock definition which otherwise works fine on my .kv file when specifically selected in Geany!
Also, the Kivy filetype is listed and selected by default in Document>Set Filetype within Geany, so I must be doing something right here!
I realize this similar question has been asked, but the solutions seem irrelavent to my case, as I've tried every related topic on this and many other sites. My Geany version is 1.22 and I'm running Arch Linux. This is driving me nuts - any suggestions?
Thank you!
Set lexer_filetype= property in the [settings] section of your filetype file. Working highlighting requires that there is a lexer that could be used for highlighting the .kv-files.
For more info see http://www.geany.org/manual/#lexer-filetype
There are three important things to obey:
the configuration file should be placed in "~/.config/geany/filedefs"
the configuration file must have the extension ".conf" - otherwise it won't show up at all (the files in "/usr/share/geany/filesdefs", where I copied my base file from, do not have a ".conf" extension!)
you must set the "lexer_filetype" to an existing (presumably builtin) configuration; e.g. "lexer_filetype=Python"

Resources