def new_update(ref_name, old_rev, new_rev, all_refs, submitter_email): """Return the correct object for the given parameters. PARAMETERS See AbstractUpdate.__init__. RETURN VALUE An object of the correct AbstractUpdate (child) class. """ # At least one of the references must be non-null... assert not (is_null_rev(old_rev) and is_null_rev(new_rev)) if is_null_rev(old_rev): change_type = CREATE object_type = get_object_type(new_rev) elif is_null_rev(new_rev): change_type = DELETE object_type = get_object_type(old_rev) else: change_type = UPDATE object_type = get_object_type(new_rev) new_cls = None for key in REF_CHANGE_MAP: (map_ref_prefix, map_change_type, map_object_type) = key if ((change_type == map_change_type and object_type == map_object_type and ref_name.startswith(map_ref_prefix))): new_cls = REF_CHANGE_MAP[key] break if new_cls is None: return None return new_cls(ref_name, old_rev, new_rev, all_refs, submitter_email)
def check_update(ref_name, old_rev, new_rev): """General handler of the given update. Raises InvalidUpdate if the update cannot be accepted (usually because one of the commits fails a style-check, for instance). PARAMETERS ref_name: The name of the reference being update (Eg: refs/heads/master). old_rev: The commit SHA1 of the reference before the update. new_rev: The new commit SHA1 that the reference will point to if the update is accepted. REMARKS This function assumes that scratch_dir has been initialized. """ debug('check_update(ref_name=%s, old_rev=%s, new_rev=%s)' % (ref_name, old_rev, new_rev), level=2) update_cls = new_update(ref_name, old_rev, new_rev, git_show_ref(), submitter_email=None) if update_cls is None: raise InvalidUpdate( "This type of update (%s,%s) is currently unsupported." % (ref_name, get_object_type(new_rev))) with FileLock('git-hooks::update.token'): update_cls.validate()
def test_get_object_type_null_rev(self): """Unit test get_object_type with a null SHA1.""" self.enable_unit_test() from git import get_object_type object_type = get_object_type( '0000000000000000000000000000000000000000') self.assertEqual(object_type, 'delete')
def new_update(ref_name, old_rev, new_rev, all_refs, submitter_email): """Return the correct object for the given parameters. PARAMETERS See AbstractUpdate.__init__. RETURN VALUE An object of the correct AbstractUpdate (child) class. """ if is_null_rev(old_rev) and is_null_rev(new_rev): # This happens when the user is trying to delete a specific # reference which does not exist in the repository. # # Note that this seems to only happen when the user passes # the full reference name in the delete-push. When using # a branch name (i.e. 'master' instead of 'refs/heads/master'), # git itself notices that the branch doesn't exist and returns # an error even before calling the hooks for validation. raise InvalidUpdate( "unable to delete '{}': remote ref does not exist".format( ref_name)) if is_null_rev(old_rev): change_type = UpdateKind.create object_type = get_object_type(new_rev) elif is_null_rev(new_rev): change_type = UpdateKind.delete object_type = get_object_type(old_rev) else: change_type = UpdateKind.update object_type = get_object_type(new_rev) ref_kind = get_ref_kind(ref_name) if ref_kind is None: raise_unrecognized_ref_name(ref_name) new_cls = REF_CHANGE_MAP.get((ref_kind, change_type, object_type), None) if new_cls is None: return None return new_cls(ref_name, ref_kind, object_type, old_rev, new_rev, all_refs, submitter_email)
def __init__(self, ref_name, old_rev, new_rev, all_refs, submitter_email): """The constructor. Also calls self.auto_sanity_check() at the end. PARAMETERS ref_name: Same as the attribute. old_rev: Same as the attribute. new_rev: Same as the attribute. all_refs: Same as the attribute. submitter_email: Same as parameter from_email in class EmailInfo's constructor. This is used to override the default "from" email when the user sending the emails is different from the user that pushed/submitted the update. """ # If the repository's configuration does not provide # the minimum required to email update notifications, # refuse the update. if not git_config('hooks.mailinglist'): raise InvalidUpdate( 'Error: hooks.mailinglist config option not set.', 'Please contact your repository\'s administrator.') m = re.match(r"([^/]+/[^/]+)/(.+)", ref_name) self.ref_name = ref_name self.short_ref_name = m.group(2) if m else ref_name self.ref_namespace = m.group(1) if m else None self.old_rev = old_rev self.new_rev = new_rev self.new_rev_type = get_object_type(self.new_rev) self.all_refs = all_refs self.email_info = EmailInfo(email_from=submitter_email) # Implement the added_commits "attribute" as a property, # to allow for initialization only on-demand. This allows # us to avoid computing this list until the moment we # actually need it. To help caching its value, avoiding # the need to compute it multiple times, we introduce # a private attribute named __added_commits. # # Same treatment for the lost_commits "attribute". self.__added_commits = None self.__lost_commits = None self.self_sanity_check()
def check_update(ref_name, old_rev, new_rev): """General handler of the given update. Raises InvalidUpdate if the update cannot be accepted (usually because one of the commits fails a style-check, for instance). PARAMETERS ref_name: The name of the reference being update (Eg: refs/heads/master). old_rev: The commit SHA1 of the reference before the update. new_rev: The new commit SHA1 that the reference will point to if the update is accepted. REMARKS This function assumes that scratch_dir has been initialized. """ debug( "check_update(ref_name=%s, old_rev=%s, new_rev=%s)" % (ref_name, old_rev, new_rev), level=2, ) check_minimum_system_requirements() # Do nothing if the reference is in the hooks.ignore-refs list. ignore_refs_match = utils.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_cls = new_update( ref_name, old_rev, new_rev, git_show_ref(), submitter_email=None ) if update_cls is None: # Report an error. We could look more precisely into what # might be the reason behind this error, and print more precise # diagnostics, but it does not seem like this would be worth # the effort: It requires some pretty far-fetched scenarios # for this to trigger; so, this should happen only very seldomly, # and when a user does something very unusual. raise InvalidUpdate( "This type of update (%s,%s) is not valid." % (ref_name, get_object_type(new_rev)) ) with FileLock("git-hooks::update.token"): update_cls.validate() maybe_update_hook(ref_name, old_rev, new_rev)
from git import git, get_object_type print("DEBUG: Test the git --switch=False attribute") print(git.log("-n1", pretty="format:%P", _decode=True).strip()) print("DEBUG: A Test to verify that git does not do any lstrip-ing...") print(git.log("-n1", "space-subject", pretty="format:%s", _decode=True)) print("DEBUG: Unit test get_object_type with a null SHA1...") print(get_object_type("0000000000000000000000000000000000000000"))