diff --git a/downstream_cherry_picker/__init__.py b/downstream_cherry_picker/__init__.py index 0dc408a..fa43dac 100644 --- a/downstream_cherry_picker/__init__.py +++ b/downstream_cherry_picker/__init__.py @@ -5,6 +5,7 @@ import subprocess import sys import requests +from shutil import copyfile __version__ = '1.2.0' @@ -21,8 +22,6 @@ PR_URL_REGEX = r'https://github.com/([^/]+)/([^/]+)/pull/(\d+)$' -HOOK_URL = 'https://gist.githubusercontent.com/alfredodeza/252d66dbf4a5c36cfb7b1cb3c0faf445/raw/08cff9560328c0c03b11b9f6ac9db98dbad0a6e4/prepare-commit-msg' # NOQA - logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) log = logging.getLogger() @@ -125,14 +124,10 @@ def git(*args): def ensure_hook(): """ Ensure that the .git/hooks/prepare-commit-msg file is ready """ + dir = os.path.dirname(os.path.realpath(__file__)) + src_hook = f'{dir}/data/prepare-commit-msg' hook = '.git/hooks/prepare-commit-msg' - # https://gist.github.com/alfredodeza/252d66dbf4a5c36cfb7b1cb3c0faf445 - if not os.path.isfile(hook): - log.warn('%s not found, downloading from Gist' % hook) - r = requests.get(HOOK_URL) - fh = open(hook, 'w') - fh.write(r.text) - fh.close() + copyfile(src_hook, hook) if not os.access(hook, os.X_OK): st = os.stat(hook) os.chmod(hook, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) diff --git a/downstream_cherry_picker/data/prepare-commit-msg b/downstream_cherry_picker/data/prepare-commit-msg new file mode 100644 index 0000000..51b2a00 --- /dev/null +++ b/downstream_cherry_picker/data/prepare-commit-msg @@ -0,0 +1,103 @@ +#!/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 + + 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).decode() + 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() diff --git a/setup.py b/setup.py index cdbfaca..3fe7d00 100644 --- a/setup.py +++ b/setup.py @@ -137,4 +137,5 @@ def run_tests(self): 'pytest-flake8', ], cmdclass={'test': PyTest, 'bump': BumpCommand, 'release': ReleaseCommand}, + package_data={'downstream_cherry_picker': ['data/prepare-commit-msg']} )