evilmartians / lefthook

Fast and powerful Git hooks manager for any type of projects.
MIT License
4.66k stars 211 forks source link

fix: share STDIN across different commands on pre-push hook #732

Closed mrexox closed 2 months ago

mrexox commented 2 months ago

Closes https://github.com/evilmartians/lefthook/issues/511 Closes https://github.com/evilmartians/lefthook/issues/611 Closes https://github.com/evilmartians/lefthook/issues/147

:zap: Summary

Right now git lfs pre-push hook does not receive STDIN. We should pass it there but some other hooks may also use it.

For this purpose I've added a cachedReader that reads from STDIN once and cached the read data. Not only for pre-push but for all hooks that specify use_stdin option the cachedReader will be used.

However with parallel: true the read data may be incorrect because of random reads from different commands that run cuncurrently. So, when you use use_stdin for more that one command/script, please consider not using parallel: true.

:ballot_box_with_check: Checklist

mrexox commented 2 months ago

Hey @tdesveaux, I've implemented a slightly different approach but it should solve the issue.

  1. STDIN is passed to git lfs hooks whether it uses it or not. I think this is better to provide it always and avoid being responsible for managin STDIN.
  2. But the STDIN is wrapped in a struct that caches all read bytes and allows to re-read them again and again. This solves issues when you have your own script/command that utilizes stdin together with Git LFS.

Do you have some time to test this code for your case? I've done some testing locally but I'd like to hear some feedback from you since this fix should solve your issue.

tdesveaux commented 2 months ago

This is a far better approach, thanks for the fix. I'll test try to test this today.

From a cursory review of the code:

mrexox commented 2 months ago

Thank you for the review. Yes, it seems like Git LFS error is a crucial thing so it should fail the whole hook.

I will consider using file for caching. I think it makes sense when STDIN has about 1+ mb of data. Do you think such cases happen often?

tdesveaux commented 2 months ago

https://git-scm.com/docs/githooks#_pre_push

I might have been far too cautious in thinking file buffering might be needed. There is one line per ref pushed (branch, tag, etc). For it to attain >1mb, it would take a very large repository being pushed in it's entirety. Not sure someone doing this would have lefthook enabled.

You can disregard this IMHO, this would add complexity to the code for no real benefit.

tdesveaux commented 2 months ago

@mrexox Just tested this branch. This fix the issue I reproduced.

FYI, here is what I did to reproduce.

I also tested your branch with a cheeky:

pre-push:
  commands:
    cat-stdin
      run: cat
      use_stdin: true

and it works.