Lets us follow a standard and a consistent way for integrating changes into the source code

Photo by Glenn Carstens-Peters on Unsplash

Problem

Code quality is always an important topic in software development because it dramatically influences the maintenance efforts needed to keep supporting the projects. That is why most of the software application projects are using the Pull Request & Code Review concepts to ensure a specific quality level. With code reviews engineers will review the changes introduced by their peers and try to verify the quality of the code being integrated, usually, they check for some of these items

Code style and conventions adopted by the team.

For interpreted languages such as ruby or python, they could verify the syntax of the source code.

Extra or unnecessary statements such as debugging comments, print statements, and debugging test code.

Missing Unit tests.

The implementation of the change and the algorithms used.

In my opinion, performing the code review process for each pull request to verify and check for all the points above (maybe more depends on the project nature) have a couple of drawbacks:

The process is time-consuming, engineers will spend a lot of time verifying that the PRs are compliant with the project standards.

Even with reviewing each of the PRs, it is not guaranteed that we will be able to follow the standards of the code style for each of the PRs. Engineers are human beings and they could miss somethings 😆.

Fortunately, some of these checks and verifications can be done automatically and performed without human interaction before even creating the PRs. In this post, I will present a tool that can be used to automate the verification of some of the items discussed above.

Git Hooks and Overcommit

Git Hooks is a technique that can be used to trigger the executions of custom scripts when specific events happen such as committing code or rebasing a branch. There are two types of git hooks: client-side such as adding a new commit locally and server-side such as receiving pushed commit hooks. We can use Git Hooks to execute our scripts to verify the code style before pushing the changes to the remote repository and create the Pull Request.

One further step that we can do here is to use the Overcommit gem for handling the git hooks and the verifications scripts instead of reinventing the wheel and writing these scripts from scratch.

Overcommit is a ruby gem that manage and configure Git hooks. The gem allows us to define the supported hooks in a yaml files and to customize the scripts to our needs. The Gem is providing a long list of verification scripts for all the supported Git hooks. In addition, The gem is also allows writing and integrating custom scripts.

Install and integrate Overcommit

Integrating overcommit with a git project can be simply done by running the below commands in the root directory of the project.

$ gem install overcommit

$ overcommit --install

In case that project is using bundle to install the gems you can add the overcommit gem to the project Gemfile and then install the gem. Below are the commands needed for doing the task.

$ echo "gem 'overcommit', '~> 0.52.0'" >> Gemfile

$ bundle install

$ overcommit --install

The command overcommit — install will install overcommit hooks in the respective repository, create a .overcommit.yml settings file in the current folder and backup project existing hooks.

Overcommit is supporting the following Built-In Hooks.

post-checkout hooks will be executed only after a successful git checkout command is executed.

hooks will be executed only after a successful command is executed. post-merge hooks run after a git merge executes successfully with no merge conflicts.

hooks run after a executes successfully with no merge conflicts. post-rewrite hooks run after a commit is modified by a git commit --amend or git rebase

hooks run after a commit is modified by a or commit-msg hooks are run against every commit message you write before a commit is created

hooks are run against every commit message you write before a commit is created pre-commit hooks are run after git commit is executed, but before the commit message editor is displayed.

hooks are run after is executed, but before the commit message editor is displayed. pre-push hooks are run during git push command, after remote refs have been updated but before any objects have been transferred.

hooks are run during command, after remote refs have been updated but before any objects have been transferred. pre-rebase hooks are run during the command git rebase and before any commits are rebased.

The default configuration file of all these hooks can be found here, you can use this file as a reference to fill the .overcommit.yml file for your project.

The first section that I configure usually is the PostCheckout section, In this section I define all the steps needed to be performed after checking out a new branch locally. For instance, for most ruby applications there is a need to install all dependencies of the project after the checkout, this step can be configured to be triggered automatically by including the below configuration the in .overcommit.yml

The next section that I configure is the CommitMsg section to define and force the commit messages standards for the project. If one of these hooks fail, adding the commit to the git project will fail also.

→ EmptyMessage this hook will ensure that the git history of the project will not contain commits with empty messages.

→ TextWidth Define a minimum and max length for the commit messages. This is also helpful to avoid unclear or short commit messages.

→ CapitalizedSubject : This is to ensure that each of the commit messages starts with a capital letter.

→ SingleLineSubject : Ensure that the first line of a commit message ends with a new blank line.

→ TrailingPeriod : Ensure that the commit message subject does not end with a period.

→ MessageFormat : Ensure a specific format for the git commit messages. The example below will only accept commits that are following the defined pattern.

→ SpellCheck : Check for misspelled words in the git commit messages.

The next configuration section is the PreCommit section and in this section we can verify the commit data and validate the introduced source code changes. If any of the implemented hooks fails, the commit will fail too and the engineers will be forced to make changes to comply with the defined standards.

→ AuthorEmail : This hook ensures that the contributors configured their git clients with valid email addresses. For instance, with the below configs engineers will be able to commit changes only with Gmail emails. This is a good idea if you would like to ensure that only the company emails are used for the development and personal emails are forbidden.

→ AuthorName : This hook ensures that the contributors configured their git client with a valid author name.

→ BrokenSymlinks : This hook checks for broken symlinks within the project files.

→ BundleAudit : Checks for vulnerable versions of gems in Gemfile.lock using the bundler-audit gem.

→ BundleOutdated : Check for outdated gems within the project, Only gems that have warning or deprecation notes will be displayed.

→ CaseConflicts : This hook is Checking for files that would conflict in case-insensitive filesystems

→ FixMe : This hook is checking for files that contain the any of defined keywords. This Hook can help in preventing commuting files that contain keywords such as TODO .

→ FileSize : This hooks is checking for oversized files before committing.

→ ForbiddenBranches : This hook can be used to prevent commits to the defined branches. This is very helpful in case you would like to freeze code changes on specific branches.

→ MergeConflicts : This hook checks for unresolved merge conflicts in the source code.

→ RailsBestPractices : Validate the source code using the style and syntax using the rails_best_paractices gem.

→ RailsSchemaUpToDate : This hook Validates if the schema file is up to date and includes all the defined database migrations or not.

→ Reek : Reek is a Code smell detector for Ruby applications, This hook will execute reek against all modified files.

→ RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. This hook will run the rubocop command against all the modified files in the commit.

→ RubySyntax : This hook tries to execute the source code in a ruby shell to check for any syntax errors or bugs.

The presented list above is not the only hooks that Overcommit is supporting, actually, Overcommit is supporting many more hooks for validating and checking different source codes built using different programming languages such as PythonFlake8, PhpCsFixer, NginxTest, TravisLint, and many more.

The last configuration section that I would like to mention is the PrePush section, In this section, we can trigger scripts that need to be executed before pushing the changes to the remote repository and creating the Pull Request. For instance, Running unit tests RSpecs locally to ensure that the new changes did not break any feature in the application.

The complete implementation of the .overcommit.yml with the hooks presented in this post is shown below.

Conclusion

Overcommit is a great tool that can be used to improve the code quality and the git logs of software development projects. This tool can help us in defining and ensuring a specific format for git messages, validate the source code syntax and style, and prevent committing codes that do not comply with the project standards.