mirror of
https://github.com/AdaCore/git-hooks.git
synced 2026-02-12 12:43:11 -08:00
We noticed that Gerrit's ref-updated hook was reporting some
errors when Gerrit makes updates to some of its internal references.
For instance:
| Traceback (most recent call last):
| File "./hooks/post_receive.py", line 126, in <module>
[...]
| errors.InvalidUpdate: ('Unable to determine the type of reference
| for: refs/changes/01/104201/meta', '',
[...]
This commit avoids this error by making sure that we properly
ignore all references that match the hooks.ignore-refs config
(note that, by default, hooks.ignore-refs includes matches for
those special Gerrit references).
A new testcase is added to verify that this is the case.
Note that the minor reformatting in maybe_update_hook comes from
black, which adds the extra coma only when the changes made in
this commit are made as well. This is why this reformatting change
is bundled with this commit.
Change-Id: Id94129ad1a9d84ccba6acafef3d8e98f62ec0239
TN: UA21-052
134 lines
4.7 KiB
Python
134 lines
4.7 KiB
Python
"""Implements git's post-receive hook.
|
|
|
|
The arguments for this hook are passed via stdin: For each reference
|
|
that is updated, stdin contains one line with 3 space-separated
|
|
tokens: the old SHA1, the new SHA1, and the reference name (Eg:
|
|
refs/heads/master).
|
|
"""
|
|
from argparse import ArgumentParser
|
|
from collections import OrderedDict
|
|
import sys
|
|
|
|
from config import ThirdPartyHook
|
|
from daemon import run_in_daemon
|
|
from git import git_show_ref
|
|
from init import init_all_globals
|
|
from requirements import check_minimum_system_requirements
|
|
from updates.emails import EmailQueue
|
|
from updates.factory import new_update
|
|
from utils import debug, warn, search_config_option_list
|
|
|
|
|
|
def post_receive_one(ref_name, old_rev, new_rev, refs, submitter_email):
|
|
"""post-receive treatment for one reference.
|
|
|
|
PARAMETERS
|
|
ref_name: The name of the reference.
|
|
old_rev: The SHA1 of the reference before the update.
|
|
new_rev: The SHA1 of the reference after the update.
|
|
refs: A dictionary containing all references, as described
|
|
in git_show_ref.
|
|
submitter_email: Same as AbstractUpdate.__init__.
|
|
"""
|
|
debug(
|
|
"post_receive_one(ref_name=%s\n"
|
|
" old_rev=%s\n"
|
|
" new_rev=%s)" % (ref_name, old_rev, new_rev)
|
|
)
|
|
|
|
check_minimum_system_requirements()
|
|
|
|
# Do nothing if the reference is in the hooks.ignore-refs list.
|
|
ignore_refs_match = search_config_option_list("hooks.ignore-refs", ref_name)
|
|
if ignore_refs_match is not None:
|
|
debug(f"{ref_name} ignored due to hooks.ignore-refs" f" ({ignore_refs_match})")
|
|
return
|
|
|
|
update = new_update(ref_name, old_rev, new_rev, refs, submitter_email)
|
|
if update is None:
|
|
# We emit a warning, rather than trigger an assertion, because
|
|
# it gives the script a chance to process any other reference
|
|
# that was updated, but not processed yet.
|
|
warn(
|
|
"post-receive: Unsupported reference update: %s (ignored)." % ref_name,
|
|
" old_rev = %s" % old_rev,
|
|
" new_rev = %s" % new_rev,
|
|
)
|
|
return
|
|
update.send_email_notifications()
|
|
|
|
|
|
def post_receive(updated_refs, submitter_email):
|
|
"""Implement the post-receive hook for all given updated_refs.
|
|
|
|
PARAMETERS
|
|
updated_refs: An OrderedDict, indexed by the name of the ref
|
|
being updated, and containing 2-elements tuple. This tuple
|
|
contains the previous revision, and the new revision of the
|
|
reference.
|
|
submitter_email: Same as AbstractUpdate.__init__.
|
|
"""
|
|
refs = git_show_ref()
|
|
|
|
for ref_name in updated_refs.keys():
|
|
(old_rev, new_rev) = updated_refs[ref_name]
|
|
post_receive_one(ref_name, old_rev, new_rev, refs, submitter_email)
|
|
|
|
# Flush the email queue. Since this involves creating a daemon,
|
|
# only do so if there is at least one email to be sent.
|
|
email_queue = EmailQueue()
|
|
if email_queue.queue:
|
|
run_in_daemon(email_queue.flush)
|
|
|
|
|
|
def maybe_post_receive_hook(post_receive_data):
|
|
"""Call the post-receive-hook is required.
|
|
|
|
This function implements supports for the hooks.post-receive-hook
|
|
config variable, by calling this function if the config variable
|
|
is defined.
|
|
"""
|
|
result = ThirdPartyHook("hooks.post-receive-hook").call_if_defined(
|
|
hook_input=post_receive_data
|
|
)
|
|
if result is not None:
|
|
hook_exe, p, out = result
|
|
sys.stdout.write(out)
|
|
# Flush stdout now, to make sure the script's output is printed
|
|
# ahead of the warning below, which is directed to stderr.
|
|
sys.stdout.flush()
|
|
if p.returncode != 0:
|
|
warn("!!! WARNING: %s returned code: %d." % (hook_exe, p.returncode))
|
|
|
|
|
|
def parse_command_line():
|
|
"""Return a namespace built after parsing the command line."""
|
|
# The command-line interface is very simple, so we could possibly
|
|
# handle it by hand. But it's nice to have features such as
|
|
# -h/--help switches which come for free if we use argparse.
|
|
ap = ArgumentParser(description='Git "post-receive" hook.')
|
|
ap.add_argument(
|
|
"--submitter-email",
|
|
help=(
|
|
"Use this email address as the sender"
|
|
" of email notifications instead of using the"
|
|
" email address of the user calling this"
|
|
" script"
|
|
),
|
|
)
|
|
return ap.parse_args()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_command_line()
|
|
|
|
stdin = sys.stdin.read()
|
|
refs_data = OrderedDict()
|
|
for line in stdin.splitlines():
|
|
old_rev, new_rev, ref_name = line.strip().split()
|
|
refs_data[ref_name] = (old_rev, new_rev)
|
|
|
|
init_all_globals(refs_data)
|
|
post_receive(refs_data, args.submitter_email)
|
|
maybe_post_receive_hook(stdin)
|