Search code examples
greppre-commitpre-commit.com

pygrep pre-commit hook to check string is present


If I want to write a pre-commit hook to check that, e.g., the string "I love pre-commit" isn't anywhere in my source code, I could do

- repo: local
  hooks:
    - id: love_statement
      name: Check that I love pre-commit isn't in source code
      types: [python]
      entry: 'I love pre-commit'
      language: pygrep

However, what if I want to do this opposite - that is, check that "I love pre-commit" is in every source code file? How could I modify my hook so that, instead of failing if "I love pre-commit" is found, it would fail if "I love pre-commit" isn't found?


this can now be done with

args: [--negate]

Solution

  • You can use a few regex tricks to do this:

    repos:
    - repo: local
      hooks:
        - id: love_statement
          name: Check that I love pre-commit is in source code
          types: [python]
          args: [--multiline]
          entry: '\A((?!I love pre-commit).)*\Z'
          language: pygrep
    

    this combines the following:

    • use the rough negative lookbehind pattern from this answer
    • use args: [--multiline] to push pygrep into whole-file matching mode
    • switch from ^ and $ (per line anchors) to \A and \Z (whole string anchors)

    here's an example execution:

    $ git ls-files -- '*.py' | xargs tail -n999
    ==> t.py <==
    print('I do not love pre-commit')
    
    ==> t2.py <==
    print('I love pre-commit')
    
    $ pre-commit  run --all-files
    Check that I love pre-commit is in source code...........................Failed
    - hook id: love_statement
    - exit code: 1
    
    t.py:1:print('I do not love pre-commit')
    

    disclaimer: I'm the author of pre-commit