Skip to content

Instantly share code, notes, and snippets.

@alfredodeza
Last active October 13, 2021 10:39
Show Gist options
  • Save alfredodeza/252d66dbf4a5c36cfb7b1cb3c0faf445 to your computer and use it in GitHub Desktop.
Save alfredodeza/252d66dbf4a5c36cfb7b1cb3c0faf445 to your computer and use it in GitHub Desktop.
Append a "Resolves: {tracker}#{ticket-id}" to commit messages based on branch names
#!/usr/bin/python
"""
This is a prepare-commit-msg hook that fill append commit messages with::
Resolves: {TRACKER}#{TICKET-ID}
For example a RedHat BZ 0001 would look like::
Correct the syntax error
Signed-off-by: Alfredo Deza <adeza@redhat.com>
Resolves: rhbz#0001
The requirement is to branch with the right identifier. For the above example
the branch name would need to be: rhbz-0001
This hook will split on `-` and use all lower casing to transform the branch
into the "Resolves" line.
Copy this file to $GITREPOSITORY/.git/hooks/prepare-commit-msg
and mark it executable.
"""
import subprocess
import sys
import os
def which(executable):
locations = (
'/usr/local/bin',
'/bin',
'/usr/bin',
'/usr/local/sbin',
'/usr/sbin',
'/sbin',
)
for location in locations:
executable_path = os.path.join(location, executable)
if os.path.exists(executable_path):
return executable_path
GIT = which('git')
def branch_name():
try:
name = subprocess.check_output(
[GIT, "symbolic-ref", "HEAD"],
stderr=subprocess.STDOUT)
except Exception as err:
if 'fatal: ref HEAD is not a symbolic ref' in err.output:
# we are in a rebase or detached head state
return ''
# This looks like: refs/heads/12345678/my-cool-feature
# if we ever get a branch that has '/' in it we are going to have
# some issues.
return name.split('/')[-1]
parts = name.split('/')
if len(parts) != 4:
raise ValueError("Branch name has '/' in it which is not allowed")
branch = parts[-1]
return branch
def prepend_commit_msg(branch):
"""Prepend the commit message with `text`"""
msgfile = sys.argv[1]
with open(msgfile) as f:
contents = f.read()
if not branch:
return contents
try:
prefix, ticket_id = branch.split('-')
ticket_id = int(ticket_id)
except ValueError:
# We used to raise here, but if cherry-picking to a different branch
# that doesn't comply it would break preventing the cherry-pick. So we
# print out the warning, but end up returning the contents.
print 'skipping commit msg change: Branch name "%s" does not follow required format: {tracker}-{ID}' % branch # NOQA
return contents
if prefix == 'wip':
# Skip "wip" branches, ie "work in progress"
return contents
resolves_line = "\nResolves: %s#%s" % (prefix.lower(), ticket_id)
with open(msgfile, 'a') as f:
# Don't append if it's already there
if resolves_line not in contents:
f.write(resolves_line)
def main():
branch = branch_name().strip().strip('\n')
prepend_commit_msg(branch)
if __name__ == '__main__':
main()
@epuertat
Copy link

epuertat commented Nov 8, 2019

Had a SyntaxError: Missing parentheses in call to 'print' when running downstream-cherry-pick in my Fedora 29 py3 environment, and fixed it with futurize -w0 prepare-commit-msg (trivial fix though):

--- .git/hooks/prepare-commit-msg	(original)
+++ .git/hooks/prepare-commit-msg	(refactored)
@@ -21,6 +21,7 @@
 Copy this file to $GITREPOSITORY/.git/hooks/prepare-commit-msg
 and mark it executable.
 """
+from __future__ import print_function
 import subprocess
 import sys
 import os
@@ -80,7 +81,7 @@
         # We used to raise here, but if cherry-picking to a different branch
         # that doesn't comply it would break preventing the cherry-pick. So we
         # print out the warning, but end up returning the contents.
-        print 'skipping commit msg change: Branch name "%s" does not follow required format: {tracker}-{ID}' % branch  # NOQA
+        print('skipping commit msg change: Branch name "%s" does not follow required format: {tracker}-{ID}' % branch)  # NOQA
         return contents
 
     if prefix == 'wip':

@ktdreyer
Copy link

ktdreyer commented Nov 8, 2019

Can you revise this gist?

@epuertat
Copy link

epuertat commented Nov 8, 2019

Additionally, decode() is required. These 2 things fix the py2-3 compatibility issues:

        name = subprocess.check_output(
            [GIT, "symbolic-ref", "HEAD"],
            stderr=subprocess.STDOUT)
+        if isinstance(name, bytes):
+          name = name.decode()

@alfredodeza
Copy link
Author

This probably can't be a gist anymore and should be an actual repository. Will make some updates to this. Thanks for the hints

@ktdreyer
Copy link

@sebastian-philipp
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment