Skip to content

Instantly share code, notes, and snippets.

@laukhin
Last active January 22, 2020 13:47
Show Gist options
  • Save laukhin/1884d9f5c85c3679e595298b82c72c50 to your computer and use it in GitHub Desktop.
Save laukhin/1884d9f5c85c3679e595298b82c72c50 to your computer and use it in GitHub Desktop.

Git hooks for convenient development

Hooks description

  • commit-msg: add ticket id from current branch name to the commit message
  • pre-push: check if CHANGELOG.md has been changed and prompts a warning message if not

Quickstart

Set hooks for all repos

  • create hooks directory (i.e. ~/.git-hooks) and place hooks to it
  • grant hooks permissions to execute (i.e. chmod a+x ~/.git-hooks/*)
  • configure global hooks path git config --global core.hooksPath ~/.git-hooks

Set hooks for a single repo

  • place hooks in the <REPO_PATH>/.git/hooks dir
  • grant hooks permissions to execute (i.e. <REPO_PATH>/.git/hooks/*)

Prerequisites

  • Unix-like system (Linux, MacOS)
  • python3
#!/usr/local/bin/python3
"""commit-msg hook for git
Add jira task number before the commit
"""
import sys
import subprocess
import typing
import re
def get_ticket_id() -> typing.Optional[str]:
"""get ticket id from current git branch
"""
branch_name: str = subprocess.check_output(['git', 'symbolic-ref', '--short', 'HEAD']).decode().strip()
match = re.match(r'(feature|bugfix|hotfix)/([A-Za-z]+[-_][0-9]+)[-_][A-Za-z-_]+', branch_name)
if match:
return match.group(2)
return None
def add_ticket_id_to_commit_message(ticket_id: str, commit_message: str) -> str:
"""form commit message with ticket id in the beginning
"""
if commit_message.startswith(ticket_id):
return commit_message
return f'{ticket_id}: {commit_message}'
def main() -> None:
"""main hook logic
"""
commit_message_file_path: str = sys.argv[1]
with open(commit_message_file_path) as commit_message_file:
commit_message_list: typing.List[str] = commit_message_file.readlines()
ticket_id: typing.Optional[str] = get_ticket_id()
if not ticket_id:
print('There is no ticket id in current branch name', file=sys.stderr)
sys.exit(0)
old_commit_message = str.join("", commit_message_list)
new_commit_message = add_ticket_id_to_commit_message(ticket_id, old_commit_message)
with open(commit_message_file_path, 'w') as commit_message_file:
commit_message_file.write(new_commit_message)
if __name__ == '__main__':
main()
#!/usr/local/bin/python3
"""pre-push hook for git
Check CHANGELOG updates in push
"""
import sys
import subprocess
import typing
def main() -> None:
"""Main hook logic
"""
git_proccess: subprocess.Popen = subprocess.Popen(
('git', 'diff', '--name-only', 'HEAD..dev'), stdout=subprocess.PIPE
)
changed_files: str = subprocess.check_output(('cat',), stdin=git_proccess.stdout).decode('utf-8')
git_proccess.wait()
parsed_changed_files: typing.List = changed_files.split('\n')
if 'CHANGELOG.md' not in parsed_changed_files:
sys.stdin = open("/dev/tty", "r") # substitute stdin to current terminal to read user input
user_answer: str = input('Looks like you forgot to update CHANGELOG. Do you still want to push? [y/n] (default n): ')
if user_answer != 'y':
print('Aborting push...', file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment