Git itself provides support for running hook scripts at many events. It would be nice to run some checks automatically, for example when creating a commit.
The problem is not how to run the checks but how to integrate them, make them fast and safe, provide a nice output, etc…
By chance I came across Overcommit, a nice framework for running Git hooks.
It provides a wide variety of predefined checks which are easy to use. I found some of them really useful:
Forbid commits to blacklisted branches - e.g. you can forbid direct commits to
masterbecause you want to use Pull Requests. This can also avoid mistakes, e.g. once I did a typo in
git checkout -band overlooked that. The following
pushwent by mistake directly to
Run Rubocop automatically to avoid fix up commits later. I see “make Rubocop happy” commits quite often in YaST.
Run the tests locally before pushing the changes, that makes sure the tests still pass. Sometimes you forget to run the tests or simply you are too lazy to run them.
And last but not least it can check spelling of the commit messages to avoid typos.
For more details see the Overcommit documentation.
A very nice Overcommit feature is that it wants to be quick, your usual git workflow should not be slowed down because of the hooks.
For example it tries running all hooks in parallel and the Rubocop hook checks only the changed files, which speeds it up for large repositories a lot. Running Rubocop over all source files in the YaST registration module takes about 7 seconds on my machine, but when a single file is checked it takes just a fraction of a second.
I have prepared RPM packages with Overcommit, simply add the YaST:Head repository and run
zypper in "rubygem(overcommit)"
Initializing the Hooks
Now go to your Git repository and set up the hooks:
overcommit --installto install the hooks.
- Add the
overcommit --signto sign the current configuration. You will need to run it again whenever the config files is changed. See the Security section in the documentation for more details.
You need to install Overcommit in each Git repository separately, but it is possible to automate the setup.
Using the Hooks
Then you use the
git commands as usually, you do not need to change anything
to run the hooks. You will just see the results of the Overcommit hooks
in the output.
If a hook fails the whole
git command fails. So if for example the Rubocop
hook fails when creating a commit then the commit is not created and you can fix
the problem early.
If for some reason you want to temporarily disable the Overcommit checks run
git command with
OVERCOMMIT_DISABLE=1 environment setting.
Here is an example
.overcommit.yml file proposed for YaST:
PreCommit: # do not commit directly to these branches, use Pull Requests! ForbiddenBranches: enabled: true branch_patterns: - master - openSUSE-* - SLE-10-* - Code-11* - SLE-12-* RuboCop: enabled: true # treat all warnings as failures on_warn: fail CommitMsg: SpellCheck: enabled: true # force using the English dictionary env: LC_ALL: en_US.UTF-8 PrePush: RSpec: enabled: true command: [ "rake", "test:unit" ] # do not fail because of translations env: LC_ALL: en_US.UTF-8
I recorded an example session to show the mentioned Overcommit features in action in the registration repository:
It looks nice, isn’t it? (If you like the git status in the bash prompt check this older post).
It looks very promising and it could catch some obvious mistakes early, I will give it a try. I will try using it for some time and then we will see if it could be used in YaST more widely.