commitizen icon indicating copy to clipboard operation
commitizen copied to clipboard

cz commit with prepare-commit-msg hook

Open saygox opened this issue 5 years ago • 11 comments

Description

cz commit is very good tool. If prepare-commit-msg hook calls cz commit, become easy to commit by many user.

Possible Solution

like cz check, writing pre-commit config

---
repos:
- hooks:
  - id: commitizen-prepare-commit-msg
    stages: [prepare-commit-msg]

and user type git comit, then prepare-commit-msg hook works and invokes cz commit.

Is this feature accepted as this product policy?

Additional context

I did a basic research. And I found that there are two issues.

  • The current cz commit calls git. But in this case, git calls cz commit
  • Git hook is started without standard input, so we can't create commit message interactively

I made a test implementation to solve the problem by the following method

  • When called from git, write the commit message to the file which is set by "--commit-msg-file" argument
  • Open tty manualy and use as stdio.

but this change has sideffect.

tty is manually opened as io.FileIO. But prompt_toolkit (which used by questionary) assumes tty is opened as io.TextIOWrapper. As a workaround I added wrap class

class WrapStdin:
    def __init__(self):
        fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
        tty = open(fd, "wb+", buffering=0)
        self.tty = tty

    def __getattr__(self, key):
        if key == "encoding":
            return "UTF-8"
        return getattr(self.tty, key)

    def __del__(self):
        self.tty.close()

All patch code is here. https://github.com/saygox/commitizen/commit/033159d08e240c493b5fa36d67e870e3b443d4d6

saygox avatar Aug 14 '20 00:08 saygox

I love this new feature! I never thought we could use git hook like this. One problem I can think of is the compatibility for windows users. We might make some more tests before we can accept it. @Woile What do you think?

Lee-W avatar Aug 14 '20 03:08 Lee-W

Quite interesting indeed, please open a PR so we can discuss it there!

woile avatar Aug 14 '20 07:08 woile

Although we have a PR https://github.com/commitizen-tools/commitizen/pull/250, I'm not able to reproduce the result. Might need some help from one with linux machine

Lee-W avatar Sep 25 '21 08:09 Lee-W

Hi @Lee-W, is there any update on this? Would love to automatically replace git commit with cz commit the same way I am able to in npm projects!

mrlubos avatar Dec 10 '21 21:12 mrlubos

Hi @mrlubos , @saygox is working on that and is almost done. But we encounter this issue and might need some time to tackle it. Would love to hear your thought if you have an idea on how this could be solved

Lee-W avatar Dec 11 '21 04:12 Lee-W

Awesome @Lee-W! Admittedly, I am not very familiar with the Python ecosystem, but I wonder if you're able to solve this similarly to how npm packages handle it? https://github.com/commitizen/cz-cli

mrlubos avatar Dec 13 '21 14:12 mrlubos

@mrlubos Thanks for your sharing! In fact, part of the code I contribute is inspired by theirs. Wondering would it be possible for you to point out what might be the modules that I need to take a look at in that project? I must admit I'm not super familiar with JS. With your help, I believe we can solve this issue much faster.

Lee-W avatar Dec 14 '21 02:12 Lee-W

@Lee-W Let's try!

It appears to me that we're not actually looking to replace git commit, but add a prepare-commit-msg hook.

The way it works in npm with husky (npm equivalent of pre-commit) is you need to create a prepare-commit-msg hook which is a shell file that looks like this

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

if [ -n "$CI" ]; then
  yarn git-cz --hook || true;
else
  exec < /dev/tty && yarn git-cz --hook || true;
fi

When I run git commit, this hook gets executed which is what actually triggers commitizen. All it does is run git-cz with the --hook flag. If we're in CI mode, we skip the interactive console as it doesn't make sense to wait for user input, otherwise we use the interactive mode. The interactive mode shows the same menu as running cz c in this project.

Based on the commitizen CLI docs, git-cz is just an alias for cz. The next step is looking at what git-cz does, which can be found in the git-cz.js file.

As it turns out, the git-cz file only decides whether to use commitizen or fallback to default Git CLI. It decides that based on whether it found any config. If not, it uses the Git strategy which is just executing the regular git commit command.

The important part of this hook can be found in the git-cz.js strategy file. I think you already have similar functionality in this repository, maybe commit.py is the equivalent in this project?


In summary, I understand that we want to add a prepare-commit-msg hook that calls our CLI in interactive mode unless in CI. The user creates a commit formatted according to the config and this string gets passed to the git commit command which gets called by our CLI.

Let me know if you want me to dig into anything else in that repository!

mrlubos avatar Dec 14 '21 14:12 mrlubos

@mrlubos Thanks for the summary! It's super helpful. I'll take a deeper look and see how I can fix it when I have time 💪

Lee-W avatar Dec 15 '21 01:12 Lee-W

Any update on this feature or is there no longer interest?

woile avatar Apr 28 '23 10:04 woile

I've not yet had the time to get back to it. The last time I tested on my local machine. It failed.

Lee-W avatar May 06 '23 10:05 Lee-W