Pre-commit hooks are great to reduce the feedback loop for things like linting and auto-formatting. Git supports them out of the box, but they are not easy to share across all developers working on a project, they need to be installed by each developers.
Several tools exist to solve this problem, but my favorite is pre-commit. It’s written in Python, but it aims at being language agnostic. It saves your setup in a config file and developers can install all of them with a single command.
Each tool is referenced by their github repo and tag to install, which is great because each tool is pinned to a specific version. However, I usually have the tool versions already elsewhere in my repository, for example in requirements.txt
, causing some duplication. The main project dependencies are automatically updated with Dependabot, PyUP or Renovate but none of these tools supports the pre-commit config file. After a while, it’s easy to end up with versions discrepancies.
That is until this week-end, where I stumbled upon the autoupdate
command from pre-commit. I’m not sure how I missed this before, it looks like it’s been part of pre-commit for a really long time. By combining this with the power of Github actions, I was able to get it to send me a pull request each time a new version is available:
<span>name</span><span>:</span> <span>Pre-commit auto-update</span><span>on</span><span>:</span><span>schedule</span><span>:</span><span>-</span> <span>cron</span><span>:</span> <span>'</span><span>0</span><span> </span><span>0</span><span> </span><span>*</span><span> </span><span>*</span><span> </span><span>*'</span><span>jobs</span><span>:</span><span>auto-update</span><span>:</span><span>runs-on</span><span>:</span> <span>ubuntu-latest</span><span>steps</span><span>:</span><span>-</span> <span>uses</span><span>:</span> <span>actions/checkout@v2</span><span>-</span> <span>name</span><span>:</span> <span>Set up Python</span><span>uses</span><span>:</span> <span>actions/setup-python@v2</span><span>with</span><span>:</span><span>python-version</span><span>:</span> <span>3.8</span><span>-</span> <span>name</span><span>:</span> <span>Install pre-commit</span><span>run</span><span>:</span> <span>pip install pre-commit</span><span>-</span> <span>name</span><span>:</span> <span>Run pre-commit autoupdate</span><span>run</span><span>:</span> <span>pre-commit autoupdate</span><span>-</span> <span>name</span><span>:</span> <span>Create Pull Request</span><span>uses</span><span>:</span> <span>peter-evans/create-pull-request@v2</span><span>with</span><span>:</span><span>token</span><span>:</span> <span>${{ secrets.CPR_GITHUB_TOKEN }}</span><span>branch</span><span>:</span> <span>update/pre-commit-autoupdate</span><span>title</span><span>:</span> <span>Auto-update pre-commit hooks</span><span>commit-message</span><span>:</span> <span>Auto-update pre-commit hooks</span><span>body</span><span>:</span> <span>|</span><span>Update versions of tools in pre-commit </span><span>configs to latest version</span><span>labels</span><span>:</span> <span>dependencies</span><span>name</span><span>:</span> <span>Pre-commit auto-update</span> <span>on</span><span>:</span> <span>schedule</span><span>:</span> <span>-</span> <span>cron</span><span>:</span> <span>'</span><span>0</span><span> </span><span>0</span><span> </span><span>*</span><span> </span><span>*</span><span> </span><span>*'</span> <span>jobs</span><span>:</span> <span>auto-update</span><span>:</span> <span>runs-on</span><span>:</span> <span>ubuntu-latest</span> <span>steps</span><span>:</span> <span>-</span> <span>uses</span><span>:</span> <span>actions/checkout@v2</span> <span>-</span> <span>name</span><span>:</span> <span>Set up Python</span> <span>uses</span><span>:</span> <span>actions/setup-python@v2</span> <span>with</span><span>:</span> <span>python-version</span><span>:</span> <span>3.8</span> <span>-</span> <span>name</span><span>:</span> <span>Install pre-commit</span> <span>run</span><span>:</span> <span>pip install pre-commit</span> <span>-</span> <span>name</span><span>:</span> <span>Run pre-commit autoupdate</span> <span>run</span><span>:</span> <span>pre-commit autoupdate</span> <span>-</span> <span>name</span><span>:</span> <span>Create Pull Request</span> <span>uses</span><span>:</span> <span>peter-evans/create-pull-request@v2</span> <span>with</span><span>:</span> <span>token</span><span>:</span> <span>${{ secrets.CPR_GITHUB_TOKEN }}</span> <span>branch</span><span>:</span> <span>update/pre-commit-autoupdate</span> <span>title</span><span>:</span> <span>Auto-update pre-commit hooks</span> <span>commit-message</span><span>:</span> <span>Auto-update pre-commit hooks</span> <span>body</span><span>:</span> <span>|</span> <span>Update versions of tools in pre-commit </span> <span>configs to latest version</span> <span>labels</span><span>:</span> <span>dependencies</span>name: Pre-commit auto-update on: schedule: - cron: '0 0 * * *' jobs: auto-update: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: 3.8 - name: Install pre-commit run: pip install pre-commit - name: Run pre-commit autoupdate run: pre-commit autoupdate - name: Create Pull Request uses: peter-evans/create-pull-request@v2 with: token: ${{ secrets.CPR_GITHUB_TOKEN }} branch: update/pre-commit-autoupdate title: Auto-update pre-commit hooks commit-message: Auto-update pre-commit hooks body: | Update versions of tools in pre-commit configs to latest version labels: dependencies
Enter fullscreen mode Exit fullscreen mode
This workflow is scheduled every day at midnight, runs pre-commit autoupdate
and sends a pull request if there are any changes.
The piece that required a bit of fiddling is the action creating the pull request, partly to get commit message, title, content and labels right, but mostly because I initially used secrets.GITHUB_TOKEN
as token, but it wouldn’t trigger the CI build for that pull request.
It’s a limitation which is well documented on the action’s README, and is intentional from Github. I chose the solution to create a PAT scoped to repo
and added it to the secrets as CPR_GITHUB_TOKEN
. It’s deployed and running on the repo of django-codemod
.
The pull request action has fixed inputs, so it will create one pull request at a time for all updates. If several tools get a new version, they would all be updated at once, and if a pull request already exists, it would receive more updates. This is not necessarily a bad thing, but if one tool breaks the build due to new linting rules, all are stuck.
Maybe I’ll look into making the pull request content a bit more dynamic, but for now it does the job I need to. I’m also planning to add this to my Cookiecutter template for Python package, so I can get it for all my new projects.
I hope this can help folks keep their pre-commit hook up to date, maybe this will become obsolete when pre-commit CI is ready, or maybe it will be a cheaper and simpler alternative
暂无评论内容