1

I have a pre-commit setup with several pretty standard repos (for a Python project anyways), and one heavily magical project-specific action.

Something like this:

repos:
  - repo: https://github.com/timothycrosley/isort
    ...
  - repo: https://github.com/psf/black
    ...
  - repo: https://gitlab.com/pycqa/flake8
    ...

  - repo: local
    hooks:
      - id: local_project_specific_magic
        name: local-magic-script
        entry: magic_script.sh
        language: script

This all runs fine when all of the checks are successful.

What I need to achieve is to have the final local_project_specific_magic hook not execute if any of the previous hooks fail. Is this doable?


I have tried to add fail_fast: true and that seems to work, but it also prevents other hooks from running if any of them fail. For example, even if isort fixes some imports, I still want black to do its thing.

frnhr
  • 12,354
  • 9
  • 63
  • 90

2 Answers2

3

fail_fast: true is as close as you're going to get without significant surgery


you could imagine though that each other hook does something like:

entry: bash -c 'black "$@" || touch .fail' --

and then your script does something like if [ -f .fail ]; then echo 'some other hook failed' && exit 1; fi

you would also need an always_run: true hook at the beginning to make sure .fail doesn't exist as well (rm -f .fail)

but this all sounds like a big, unmaintainable hack. I suspect you have an XY problem as your requirement seems extremely strange -- perhaps elaborate on why you would want this setup?


disclaimer: I created pre-commit

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
2

I had a very similar task and the answer by @Anthony Sottile gave me a new idea.

My solution to this problem is to use the log_file keyword to generate a pre-commit.log. These file only exists if black or isort (or both) pre-commits fails.

My .pre-commit-config.yaml finaly look loke this:

repos:
-   repo: local
    hooks:
    - id: cleaner
      name: cleaner
      entry: bash clean_logfiles.sh
      language: system
-   repo: https://github.com/ambv/black
    hooks:
    - id: black
      log_file: pre-commit.log
-   repo: https://gitlab.com/pycqa/flake8
    hooks:
    - id: flake8
      log_file: pre-commit.log
  - repo: local
    hooks:
      - id: local_project_specific_magic
        name: local-magic-script
        entry: bash magic_script.sh
        language: system

In my local magic_script.sh I added on the top

if [ -f "pre-commit.log" ]; then
    echo "Error in earlier pre-commit! We skip magic_script.sh."
    exit 1
else
   # some more magic_script.sh
fi

In this way I can select which pre-commits are important to me.

To avoid that the next run fails because of old log-files, I added the cleaner pre-commit, which just removes this old log-files.

The code is very basic and looks like this:

if [ -f "pre-commit.log" ]; then
   echo "delete pre-commit.log"
   rm "pre-commit.log"
fi
mosc9575
  • 5,618
  • 2
  • 9
  • 32