Integrate Pronto with Gitlab CI for Rails App
Table of contents
At Truemark, we are constantly looking to improve the code quality in our projects. And one way to do that is through the regular code review process. Code review process can quickly get exhausting if team members have to spend majority of their time on maintaining best practices.
Enters automated code review; which reviews source code for compliance with a predefined set of rules and best practices.
In Rails projects, to define rules and best practices, we use RuboCop and for code reviews we will be using Pronto integrated with Gitlab CI.
Pronto is a gem which uses RuboCop configuration file to perform analysis on changes made in the given feature branch and adds comment to merge requests based on the best practices configured. Pronto can be integrated with popular version control system managers like Gitlab. Github and Bitbucket.
It also works on local machine and is perfect if you want to find out quickly if a branch introduces changes that conform to your style guide (rules configuration file), are DRY and doesn’t introduce security holes.
Short answer, for automating the code review process so your team doesn’t have to manually comment and make sure that every team member is following the best practices.
Every developer has their own belief on the best practices and styles, for e.g. some want to use single quotes whereas others prefer double quotes. Some love using semicolons, other just think it’s unnecessary. This can brew conflict in the team, when teammates are reviewing merge requests, hence we let Pronto do this.
Best practices and style guide can first be setup by the team and Pronto makes sure that every member is adhering to those rules.
- RuboCop has been configured in the app, i.e. .rubocop.yml exists in the project
Add following to development, test group
group :development, :test do gem 'pronto' gem 'pronto-rubocop', require: false gem 'pronto-flay', require: false end
From command line, run
Add specific version for the installed Gems
After bundle install, go to your Gemfile and search the gem version installed and update the Gemfile with that version
group :development, :test do gem 'pronto', '~> 0.11.0' gem 'pronto-rubocop', '~> 0.11.1', require: false gem 'pronto-flay', '~> 0.11.0', require: false end
Create .gitlab-ci.yml in the root project and add the following:
image: ruby:3.0.0 # this should be the ruby version that your rails app is using, ours was using 3.0.0 before_script: - apt-get update && apt-get install -y cmake # Install cmake needed for pronto - bundle install # install all packages in the Gemfile - git fetch origin # fetch all branches, was throwing Rugged::ReferenceError, you can remove this and try if it works for you stages: - lint # we are only formatting/linting the changes pronto: stage: lint # runs pronto on the lint stage only: - merge_requests # run pronto only on merge requests (also runs when new changes are pushed to the merge request) script: - PRONTO_GITLAB_API_PRIVATE_TOKEN=$PRONTO_ACCESS_TOKEN bundle exec pronto run -f gitlab_mr -c origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME # Run pronto on branch of current merge request
$PRONTO_ACCESS_TOKENshould be configured in gitlab which is explained in steps below.
$CI_MERGE_REQUEST_TARGET_BRANCH_NAMEis the predefined Gitlab CI variable which returns the branch name of the current merge request. You can read more about the predefined Gitlab CI variables here.
- In Gitlab, after login, go to personal access token
- Enter a name and optional expiry date for the token.
- In scopes, choose only api, it is enough for our purpose as it gives all access to the project via Gitlab API.
- Click on Create token
- Copy the token and keep it somewhere safe, we will need this in next step.
Reference: Official documentation
To use the Personal Access Token (
$PRONTO_ACCESS_TOKEN) in our Gitlab CI, we should set it up as custom variable in settings inside CI/CD.
NOTE: Only project members with maintainer permissions can add or update project CI/CD variables, so make sure you have the correct access.
- Go to your project
- From the left menu, in Settings; choose the CI/CD
- Expand Variables Section
- Click on Add Variable
- In Key, add
PRONTO_ACCESS_TOKENas that is what we have configured in our .gitlab-ci.yml file. You can use any key name, just make sure to update it inside .gilab-ci.yml.
- In Value, add the token generated in the previous step
- In Flags section, uncheck Protect variable, checking this option will export the variable (
PRONTO_ACCESS_TOKEN) only for protected branches like master/main. But we need this variable inside all merge request branches.
- Check Mask variable so our token value is not visible in the CI job logs.
- Click on Add variable
Reference: Official documentation
- Run against master
- Run against other branches
pronto run -c branch-name
- Commit the changes made in the branch and push the code to Gitlab
- You should see Gitlab CI running automatically now and it should pass
- If Pronto finds any issues after analyzing the codes changed in the merge request, it will post those issues as comments in that merge request.
NOTE: Sometimes it throws Reference::RuggedError due to missing git branch, retry running the job in that case and it should work the second time.
If you are curious and want to see what is happening in the background, you can check the Gitlab CI Job log.
- From the left menu inside the project, hover over CI/CD and click on Jobs
- To view the log, click on job id in the Job column which starts with #, for e.g. #1290157388
Due to installation of all gems (
bundle install) in the project, it can take up to 3 minutes for the job to be completed even when there are not many changes.
Caching helps in making the CI run really fast. At Truemark, before CI was implemented every job would take ~7 minutes and after the CI was implemented it’s now taking ~1 minute.
Let’s look at the configuration changes we need to do in “.gitlab-ci.yml” file for the caching.
image: ruby:3.0.0 # add this cache: paths: - vendor/ before_script: # add this - bundle config set path 'vendor' # replace "bundle install" with 👇 - bundle install -j $(nproc) --path=vendor # other content will be the same
With above configuration, we are telling Gitlab Ci to cache “vendor” folder where all our gems will be stored. Then when running “bundle install”, we will ask the CI to install gems to vendor folder from where CI will reuse gems that haven’t changed in version. This will help in reducing the time CI takes to install gems.
Your final “.gitlab-ci.yml” could look similar to this:
image: ruby:3.0.0 # this should be the ruby version that your rails app is using, ours was using 3.0.0 cache: paths: - vendor/ before_script: - apt-get update && apt-get install -y cmake # Install cmake needed for pronto - bundle config set path 'vendor' - bundle install -j $(nproc) --path=vendor - git fetch origin # fetch all branches, was throwing Rugged::ReferenceError, you can remove this and try if it works for you stages: - lint # we are only formatting/linting the changes pronto: stage: lint # runs pronto on the lint stage only: - merge_requests # run pronto only on merge requests (also runs when new changes are pushed to the merge request) script: - PRONTO_GITLAB_API_PRIVATE_TOKEN=$PRONTO_ACCESS_TOKEN bundle exec pronto run -f gitlab_mr -c origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME # Run pronto on branch of current merge request
The main reason for writing this article was because I couldn’t find decent article explaining exactly what we should do to integrate Pronto in Gitlab. Integration guide for Pronto in official documentation was not clear enough to guide us what exactly to do for integrating Pronto with Gitlab CI.
We were able to find some blogs, and majority of them were using Docker or were Github integrations, it took a while for the team to figure this solution out. Now this blog should save your team’s time when you are using Pronto with Gitlab Ci in your projects. Good luck!
Thank you for reading. See you in the next blog.