With Hound, there is already an easy way to include automatic code style comments into Github projects. We recently introduced something comparable into our (self-hosted) Gitlab CI pipeline. The heavy work is done be the excellent Pronto, a pluggable code style linter which uses battle-tested linter under the hood like Rubocop, Eslint, phpcs and many more.
Creating Docker image with embedded code style tools
As we are using Docker for running our pipeline, we created a new Docker image that we deploy to the runner nodes. That image just has all the tools included that we need for testing, as well as the various linter default config files that we are using across all projects.
First, create private token in your (or the account that you want to use for commenting) Gitlab profile under Profile/Settings -> Access Tokens.
FROM ruby:2.4
MAINTAINER Your Name <info@your.domain.com>
# env variables for 'gitlab' executable for test
ENV GITLAB_API_PRIVATE_TOKEN YourSecretGitlabToken-209xas
ENV GITLAB_API_ENDPOINT https://git.yourcompanyserver.com/api/v3
# cmake is required by pronto
RUN apt-get update -y && \
apt-get install -y cmake
RUN gem install pronto \
# just list all the linters you are planning to use
pronto-brakeman pronto-slim pronto-scss pronto-rubocop \
--no-ri --no-rdoc
RUN echo "Testing Gitlab API access.." && \
gitlab projects "{ per_page: 1000, page: 1 }" --only=id,path_with_namespace
ENV PRONTO_GITLAB_API_PRIVATE_TOKEN $GITLAB_API_PRIVATE_TOKEN
ENV PRONTO_GITLAB_API_ENDPOINT $GITLAB_API_ENDPOINT
# copy over various default linter files
COPY rubocop.yml /root/.rubocop.yml
COPY scss-lint.yml /root/.scss-lint.yml
Here, rubocop as well as scss-lint are using default style files under the current user’s home directory. Any project might override these by placing a project specific file into the project folder. Feel free to add more pronto-runner besides the one for Rubocop, Slim, Scss or Brakeman.
Now, build the container:
docker build -t yourcompany/code-style:v1 .
Roll out the docker image to the runner nodes or rerun the script above on each runner node, depends on your setup.
Add the pronto task to your .gitlab-ci.yml
Add or modify your .gitlab-ci.yml in the project and commit it.
# project .gitlab-ci.yml
states:
- test
pronto:
image: yourcompany/code-style:v1
stage: test
script: |
export PRONTO_GITLAB_SLUG="$CI_PROJECT_ID"
pronto run -f gitlab
Done! Push & deploy and your commit log should fill up with commit messages.
Appendix 1: Rubocop hints
Start by installing a recent Rubocop version with gem install rubocop
. Run rubocop app -D
and have a look at the output. You probably want to disable or cool down a lot of “Cops”, so by running with -D
the Cop name is listed alongside every check.
rubocop -f w
shows you the files with the most style/linter problemsrubocop -f o
shows you the list of all Copsrubocop -D --only Style/SpaceInsideParens,Style/AlignHash,Style/HashSyntax,Style/SpaceInsideBlockBraces -a
Autocorrect the given list of Cops - One of the best features of Rubocop is to automatically. Run with caution and commit often to be able to go back, if you didn’t like the result.
Here an example Rubocop.yml you might take as a starting point:
AllCops:
TargetRubyVersion: 2.4
Exclude:
- 'bin/*'
- 'scripts/**/*'
- 'db/**/*'
Rails:
Enabled: true
Style/GuardClause:
MinBodyLength: 1
Style/AndOr:
EnforcedStyle: conditionals
Style/PercentLiteralDelimiters:
PreferredDelimiters: {}
Style/Alias:
Enabled: false
Style/Documentation:
Enabled: false
Style/PercentLiteralDelimiters:
Enabled: false
Lint/UnusedMethodArgument:
Enabled: false
Rails/HasAndBelongsToMany:
Enabled: false
Metrics/ModuleLength:
Enabled: false
Style/StringLiterals:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/BlockLength:
ExcludedMethods: ['task', 'namespace', 'get', 'post', 'describe', 'context', 'specify', 'it', 'route_param', 'draw']
Appendix 2: Integrating into vim
Fortunately, with Syntastic plugin very easy, but you need to explicitly include it like:
let g:syntastic_ruby_checkers = ['mri', 'rubocop']
This will run both the (default) Ruby built-in lint and Rubocop afterwards.