Skip to content
Krzysztof Czarnecki edited this page Oct 26, 2021 · 6 revisions

Hooks

A slightly more complex situation is when you want to:

  • provide the ability to autogenerate commit messages
  • but also check the ones that were not generated by mkcommit.

For this purpose standard Git Hooks could be used but for convenience we've created a way for you to run mkcommit as a hook.

Because this is a completely different paradigm of operation, apart from commit function you will have to define a separate on_commit function to define how you want to validate textual commit messages.

Example with Semantic Commits

Existing suites like mkcommit.suites.semantic have a built-in set of on_commit validators.

from mkcommit import CommitMessage, to_stdout
from mkcommit.suites import semantic

def commit():
    return CommitMessage(semantic.default_short(), semantic.default_long())

def on_commit(msg: CommitMessage):
    semantic.is_semantic(msg.first_line)
    semantic.has_short_commit_msg_proper_length(msg.first_line)

if __name__ == "__main__":
    to_stdout(commit())
  • semantic.is_semantic() simply checks whether the provided message is in the form of {keyword}({scope}): {description}.
  • semantic.has_short_commit_msg_proper_length extracts the {description} portion from the original commit message and checks if it doesn't exceed 55 characters in length.

Extended example

As always, you can use existing building blocks (validators in particular) to define your own validation steps for externally-fed commit messages in the on_commit definition. The pattern you should be using is raising a ValidationFailedException each time the commit message fails to comply with some particular rule:

from mkcommit import CommitMessage, to_stdout, ask, ValidationFailedException
from mkcommit.validators import validate_initials, matches

def initials_are_two_letter(s: str) -> bool:
    if not validate_initials(2, 2)(s):
        raise ValidationFailedException("initials")
    else:
        return True

def something_matches_blah(s: str) -> bool:
    if not matches(r"blah")(s):
        raise ValidationFailedException("something")
    else:
        return True

def commit() -> CommitMessage:
    initials = ask("Your initials: ", check=initials_are_two_letter)
    something = ask("Your something: ", check=something_matches_blah)
    return CommitMessage(
        f"{initials} | {something}"
    )

def on_commit(commit_message: CommitMessage):
    initials, something = commit_message.first_line.split(" | ")
    initials_are_two_letter(initials)
    something_matches_blah(something)

if __name__ == "__main__":
    to_stdout(commit())

In the example above, on_commit provides a validation procedure for a commit message that will be provided through the command line as input. Note how the two functions: initials_are_two_letter and something_matches_blah reuse the validation logic between the commit and on_commit definition. This pattern is strongly encouraged.

Using mkcommit as a Git Hook

When mkcommit is called with -x "some commit message" argument, the provided commit message will be fed into on_commit function and validated according to your own definition of on_commit. Hence you can simply add the following call to the commit-msg Git Hook script in .git/hooks.

  1. Create or open the exisitng ./.git/hooks/commit-msg hook in your repo.

  2. Append the mkcommit hook call to the end of the file:

    #!/usr/bin/env bash
    mkcommit -x "$(cat $1)" --autoselect

    Note: shebang (#!/usr/bin/env bash) should be placed only at the very top of the file.

    • --autoselect flag will automatically select the first found *.mkcommit.py file as the associated config.
    • You can use an explicit file path using the -f flag, e.g.
    #!/usr/bin/env bash
    mkcommit -x "$(cat $1)" -f ".mkcommit.py"
  3. You might also need to run chmod +x ./.git/hooks/commit-msg to mark the hook script as executable. If you're setting this up on Windows, make sure you run this command from within Git Bash at the root of your repository.

How it works

mkcommit -x "$(cat $1)" command will load the contents of the COMMIT_EDITMSG file (the path is under $1 in the commit-msg hook) where the commit message is stored, create a CommitMessage instance from raw input and feed this instance to the on_commit function.

Clone this wiki locally