3

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]
ignoring_gravity
  • 6,677
  • 4
  • 32
  • 65

1 Answers1

4

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

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • "disclaimer: I'm the author of pre-commit" Looks like flattery _is_ a good strategy :) Thanks! – ignoring_gravity Oct 14 '20 at 07:20
  • I'm finding this solution to be slow, even though it works - is there an option to reverse the exit code of `pygrep`? If not, would you take a pull request to add that? – ignoring_gravity Oct 14 '20 at 08:15
  • there is not or I would have suggested it. A PR may be considered if you can demonstrate a real use case for it – anthony sottile Oct 14 '20 at 15:40
  • @AnthonySottile Did inverting the condition every become a thing? I have a use case where we have a version file with a magic string we never want changed. A tox job replaces it. If someone runs it locally we want to make sure they can't commit it if the magic string isn't still there. – Mike Barry Oct 27 '22 at 01:06
  • @MikeBarry easy to [check the docs](https://pre-commit.com/#pygrep) – anthony sottile Oct 27 '22 at 03:58