Running tasks before a commit with Ready and Docker
There are some tasks I really find necessary to do before committing code and reaching the CI pipeline, for example formatting, linting, and running unit tests. The sooner any issue can be catch, the quicker a feature or bugfix can be delivered.
As a personal project, I created Ready, which is a program to run tasks before a commit using a pre-commit git hook, to perform tasks on staged files.
The way I prefer to run these tasks is with Docker, creating a CI image with all required dependencies in order to remove the need to have tools and packages installed locally, and to have a reproducible way to run the same tasks either in our computers or in our colleagues'.
Getting started
- Install Ready
If you are using Go you can run go install github.com/lewislbr/ready@latest
. If not, download the binary from the releases page and place it in your $PATH
.
- Create hook
Run ready init
in the repository root path (where the folder .git
is located).
This will check for any existing pre-commit hook, and if found, it will prompt to override it or abort the process. If no hook is found, a new one with execution rights will be created.
- Create tasks file
Create a file named ready.yaml
and place it in the repository root path (where the folder .git
is located).
Add the tasks you want to run:
tasks:
- name: format
command: gofumpt -l -w .
- name: lint
command: golangci-lint run
By default, commands will be run in the root directory, but they can be scoped to nested directories with the directory
option.
Example:
tasks:
- name: build CI image
directory: backend
# This will run in the backend directory (./backend)
command: docker build -t foo/backend:ci --target=ci .
- name: lint
directory: backend
# Run the command using the Docker container
command: docker run --rm -v $(pwd):/app -w /app foo/backend:ci gofumpt -extra -l -w .
In this example, using the backend
folder we create a Docker container that contains all CI tools we need, and then using that container we run a formatter command that will be applied to the staged files that are located inside the folder backend
.
Each task will be executed independently in sequential order.
From now on any commit will trigger the hook that will in turn execute the defined tasks. If any task fails or a file is modified automatically, the commit will be stopped, saving us from commiting non-ready code to the repository.