nedbat / cog

Small bits of Python computation for static files
MIT License
332 stars 26 forks source link

Add support for use as pre-commit hook #21

Open nialov opened 1 year ago

nialov commented 1 year ago

Hey,

Thanks for the useful tool! Using cog as a pre-commit hook would increase its usefulness as you could verify that all cog code is run before committing. The config is as simple as I have implemented here: https://github.com/nialov/cog/blob/feat-add-as-pre-commit-hook/.pre-commit-hooks.yaml. I have configured the implemented hook locally in a project as such:

  - repo: https://github.com/nialov/cog
    rev: 6d73562c5cb38753bd94414a6e7612b263bc278d
    hooks:
      - id: cog
        files: "(docs_src/index.rst)"

However, what flags to use and what to put as the default is definitely an open question. In my example I have used the checksum (-c) and inplace conversion (-r) flags. These probably cannot be defaults as cog can be used in numerous different ways.

Secondly, the command line cog should not fail when ran with no files inputted. This does not have to be the default but should be enabled by e.g., a flag (--no-fail-on-no-filenames or something more succinct).

I would not be surprised if multiple have not already implemented this functionality in their own projects/forks. A caveat in the implementation as a pre-commit hook is that the Python interpreter will not have access to any other packages other than cog and the standard library of Python so more advanced use cases are probably out of scope of the hook implementation.

nedbat commented 8 months ago

I like the idea of using cog as a pre-commit hook. I'm not sure what your first requested change is. It sounds like you have cog running just fine, so you don't need a change?

The second change (being ok with no files) makes sense. I'm not sure why I had it checking for that case explicitly.

nialov commented 8 months ago

The second change (being ok with no files) makes sense. I'm not sure why I had it checking for that case explicitly.

Sorry for the confusion, as I remember and from short testing right now the ability to not error when no files are passed is the only change I would require in the actual code.

Other than that, if you support the idea I think the .pre-commit-hooks.yaml file could be added so that this repo could be directly used in other people's pre-commit-config.yaml configuration. However, there is the caveat that the user will always have to explicitly setup the files in pre-commit-config.yaml that they want to run the cog hook on as there is no way for pre-commit to know which files to pass to cog otherwise.

I can make a pull request with these minor changes if you give a thumbs up!

vergenzt commented 6 months ago

FYI here's a pre-commit hook I've used locally that installs cogapp as a dependency and uses my preferred set of options (feel free to change for yourself):

click to expand ```yaml - repo: local hooks: - # https://github.com/nedbat/cog/issues/21#issuecomment-1919626992 id: cog name: cog (regenerate files) language: python additional_dependencies: - cogapp entry: cog args: - -r # Replace the input file with the output. - -c # Checksum the output to protect it against accidental change. - -P # Use print() instead of cog.outl() for code output. - -p # Prepend the generator source with PROLOGUE: - 'import subprocess as sp, re, os, sys' always_run: true # so that new files get picked up in generated file list below files: | (?x)^( # (auto-determine which files have cog snippets) #[[[cog # cog_files = sp.check_output(["git", "grep", "-lF", "[[[" + "cog"], text=True).splitlines() # print(" |\n".join(map(re.escape, cog_files))) #]]] \.pre\-commit\-config\.yaml #[[[end]]] (checksum: c9a00cdff387b441693470ba709fa23d) )$ ```

edit 2024-04-05: After using this for a while I've found that pre-commit's "only run on changed files" filter misses times that it needs to re-run cog. Since I always keep my cog snippets fast I'm now using this config:

  - # https://github.com/nedbat/cog/issues/21#issuecomment-1919626992
    id: cog
    name: cog (regenerate files)
    language: python
    additional_dependencies:
    - cogapp
    entry: bash -c 'git grep -lzF "[[[""cog" | xargs -0 cog "$@"'
    args:
    - -r # Replace the input file with the output.
    - -c # Checksum the output to protect it against accidental change.
    - -P # Use print() instead of cog.outl() for code output.
    - -p # Prepend the generator source with PROLOGUE:
    - 'import subprocess as sp, re, os, sys, pathlib as pl'
    pass_filenames: false
    always_run: true