Execute pre-receive git hook from a template directory for all repositories
Description
Hi All,
I manage a gitea server for small company and want to enforce branch naming using server side git pre-receive hook. Now I have enabled git hook execution on server side in app.ini via DISABLE_GIT_HOOKS = false. If i debug print directly in /var/lib/gitea/data/gitea-repositories/<org>/<repo>/hooks/pre-receive.d/gitea then this script is executed. When I place gitea server wide scripts under /var/lib/gitea/custom/hooks/pre-receive.d/branch-policy.sh then this script is not executed. Is this even possible? I cant find anything in the documentation or in the code this path is valid to have a list of scripts to be executed by gitea. It is highly likely Gemini AI search was hallucinating this template/server side directory is available as feature.
It would be nice to have server wide hooks instead of patching every repository. Maybe I'm doing something wrong or don't understand it because of the lack of documentation (or not sure where to find it).
Thanks in advance!
Gitea Version
v1.24.0
Can you reproduce the bug on the Gitea demo site?
No
Log Gist
No response
Screenshots
No response
Git Version
v2.39.5
Operating System
Linux (Debian 12)
How are you running Gitea?
From downloads under systemd, no package from Debian
Database
PostgreSQL
Currently, you can place the scripts under /var/lib/gitea/data/gitea-repositories/<org>/<repo>/hooks/pre-receive.d/ directly. It should work. And the file should have execute permission. And you can also edit the hooks in repository setting if DISABLE_GIT_HOOKS = false.
Probably a symlink to a common folder will work, then there is only one script to maintain and just pointed from /var/lib/gitea/data/gitea-repositories/<org>/<repo>/hooks/pre-receive.d/my-hook.sh to /var/lib/gitea/custom/hooks/pre-receive.d/my-hook.sh. Will test this out. Thanks for pointing this direction. Seems a reasonable workaround.
. When I place gitea server wide scripts under
/var/lib/gitea/custom/hooks/pre-receive.d/branch-policy.shthen this script is not executed.
There is no such feature: Add Global GitHooks #28345
I have mocked together a bash script to sync from a base dir to all the repositories as symlinks, can be revoked when scripts use a prefix like custom-:
#!/bin/bash
# Synchronize git-hooks from common path as symlinks into all gitea-repositories
###
#set -x
set -e
# Configuration
GITEA_WORKDIR="/var/lib/gitea"
GITEA_REPOSITORIES_DIR="${GITEA_WORKDIR}/data/gitea-repositories"
GITEA_CUSTOM_GIT_HOOKS_DIR="${GITEA_WORKDIR}/custom/git-hooks"
##
# Fetch a list of hooks in the gitea custom git-hooks .d folder
# NOTE returns absolute paths
# $1: git_hook_name (e.g "pre-receive")
##
function gitea_custom_git_hooks_get_list() {
git_hook_name="$1"
GITEA_TARGET_HOOKS_DIR="${GITEA_CUSTOM_GIT_HOOKS_DIR}/${git_hook_name}.d"
# Search for all hooks in the gitea custom path
for gitea_custom_hook_filepath in `find "${GITEA_TARGET_HOOKS_DIR}" -maxdepth 1 -type f`; do
repository_hook_symlink_path="${repository_hooks_target_d_dir}/$(basename ${gitea_custom_hook_filepath})"
echo "${gitea_custom_hook_filepath}"
done
}
##
# Synchronize based on hookname
# $1: git_hook_name (e.g "pre-receive")
# $2: hooks_list (array of absolute filepaths)
##
function synchronize_hooks_list() {
git_hook_name="$1"
hooks_list=$2
GITEA_TARGET_HOOKS_DIR="${GITEA_CUSTOM_GIT_HOOKS_DIR}/${git_hook_name}.d"
# Search for .git repository directories in GITEA_REPOSITORIES_DIR basepath (max depth 2: org/repo.git)
for repository_path in `find "$GITEA_REPOSITORIES_DIR" -maxdepth 2 -type d -name "*.git"`; do
hooks_target_d_dir="${GITEA_TARGET_HOOKS_DIR}"
repository_hooks_target_d_dir="${repository_path}/hooks/${git_hook_name}.d"
# Create repository hooks target directory if it doesn't exist yet
if [ ! -d "${repository_hooks_target_d_dir}" ]; then
mkdir -p "${repository_hooks_target_d_dir}"
fi
# Loop over all source path hooks and check if they are already symlinked into the gitea git repo
for hook_filepath in $hooks_list; do
target_hook_filepath="${repository_hooks_target_d_dir}/$(basename $hook_filepath)"
if [ ! -e "${target_hook_filepath}" ]; then
echo "Register ${hook_filepath} -> ${target_hook_filepath}"
ln -s "${hook_filepath}" "${target_hook_filepath}"
fi
done
done
}
##
# Remove all registered adimec hooks in gitea-repositories
# $1: git_hook_name (e.g "pre-receive")
# $2: hooks_prefix (e.g "custom-")
# $3: operation (e.g "list", "unregister")
##
function all_registered_hooks_operation() {
git_hook_name="$1"
hooks_prefix="$2"
operation="$3"
hooks_remove_filter="^${hooks_prefix}"
# Search for .git repository directories in GITEA_REPOSITORIES_DIR basepath (max depth 2: org/repo.git)
for repository_path in `find "$GITEA_REPOSITORIES_DIR" -maxdepth 2 -type d -name "*.git"`; do
repository_hooks_dir="${repository_path}/hooks/${git_hook_name}.d"
for hook_filepath in `find "${repository_hooks_dir}" -maxdepth 1 -type l`; do
hook_filename=$(basename ${hook_filepath})
if [[ "${hook_filename}" =~ ${hooks_remove_filter} ]]; then
if [[ "$operation" == "unregister" ]]; then
echo "Unregister ${hook_filepath}"
rm "${hook_filepath}"
elif [[ "$operation" == "list" ]]; then
echo "${hook_filepath}"
fi
fi
done
done
}
# Fetch hooks list for pre-receive
HOOKS_LIST=($(gitea_custom_git_hooks_get_list "pre-receive"))
for hook_filepath in $HOOKS_LIST; do
echo "System wide hook found: ${hook_filepath}"
done
cli_operation="$1"
case "${cli_operation}" in
sync|"")
# Synchronize the hooks list
synchronize_hooks_list "pre-receive" ${HOOKS_LIST}
;;
list)
# List all registered hooks
all_registered_hooks_operation "pre-receive" "custom-" "list"
;;
unregister)
# Unregistered all hooks
all_registered_hooks_operation "pre-receive" "custom-" "unregister"
;;
esac
I had a similar AI hallucination that found this issue 😂 Seems there might be a way to soft-enforce this, cronjob etc but would be a nice official feature!
I had a similar AI hallucination that found this issue 😂 Seems there might be a way to soft-enforce this, cronjob etc but would be a nice official feature!
Luckily you where directed here! My current solution/workaround is a nightly systemd timer (cron job) which registers hooks from a template. It should indeed not be necessary because for all repositories at gitea hook is installed, the gitea generic hook calls Go code (correct me if i'm wrong) and we should be able to execute other scripts from another directory with same context. But somebody needs to dig deep into the Gitea code to see where it can be added in a good way. I have enough experience with programming and Go/Shell scripts. But have not yet found time/reason to add it as a gitea builtin feature.