diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 9196180d81..90024b6be4 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -421,6 +421,19 @@ USER = root ;; ;SLOW_QUERY_THRESHOLD = 5s +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +[git.hooks] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Git prereceive hook name +;GIT_HOOK_PRERECEIVE_NAME = pre-receive +;; Git update hook name +;GIT_HOOK_UPDATE_NAME = update +;; Git post receive hook name +;GIT_HOOK_POSTRECEIVE_NAME = post-receive + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [security] diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 0c15a866b6..d9b55104f3 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1125,6 +1125,12 @@ This section only does "set" config, a removed config key from this section won' - `core.logAllRefUpdates`: **true** - `gc.reflogExpire`: **90** +### Git - Hook options (`git.hooks`) + +- `GIT_HOOK_PRERECEIVE_NAME`: **pre-receive**: Specifies the name of the pre-receive hook. Wont accept paths as value, will only accept filenames. +- `GIT_HOOK_UPDATE_NAME`: **update**: Specifies the name of the update hook. Wont accept paths as value, will only accept filenames. +- `GIT_HOOK_POSTRECEIVE_NAME`: **post-receive**: Specifies the name of the post-receive hook. Wont accept paths as value, will only accept filenames. + ## Metrics (`metrics`) - `ENABLED`: **false**: Enables /metrics endpoint for prometheus. diff --git a/modules/git/git.go b/modules/git/git.go index 05ca260855..bb8f72a4c4 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -25,8 +25,7 @@ import ( const RequiredVersion = "2.0.0" // the minimum Git version required type Features struct { - gitVersion *version.Version - + gitVersion *version.Version UsingGogit bool SupportProcReceive bool // >= 2.29 SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ diff --git a/modules/git/hook.go b/modules/git/hook.go index 46f93ce13e..6fbd5df805 100644 --- a/modules/git/hook.go +++ b/modules/git/hook.go @@ -12,27 +12,19 @@ import ( "strings" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) -// hookNames is a list of Git server hooks' name that are supported. -var hookNames = []string{ - "pre-receive", - "update", - "post-receive", -} +var hookNames = []string{"pre-receive", "update", "post-receive"} -// ErrNotValidHook error when a git hook is not valid -var ErrNotValidHook = errors.New("not a valid Git hook") - -// IsValidHookName returns true if given name is a valid Git hook. -func IsValidHookName(name string) bool { - for _, hn := range hookNames { - if hn == name { - return true - } +// hookNames contains the hook name (key) linked with the filename of the resulting hook. +func GetHookNames() map[string]string { + return map[string]string{ + "pre-receive": setting.GitHookPrereceiveName, + "update": setting.GitHookUpdateName, + "post-receive": setting.GitHookPostreceiveName, } - return false } // Hook represents a Git hook. @@ -44,6 +36,19 @@ type Hook struct { path string // Hook file path. } +// ErrNotValidHook error when a git hook is not valid +var ErrNotValidHook = errors.New("not a valid Git hook") + +// IsValidHookName returns true if given name is a valid Git hook. +func IsValidHookName(name string) bool { + for hn := range GetHookNames() { + if hn == name { + return true + } + } + return false +} + // GetHook returns a Git hook by given name and repository. func GetHook(repoPath, name string) (*Hook, error) { if !IsValidHookName(name) { @@ -51,7 +56,7 @@ func GetHook(repoPath, name string) (*Hook, error) { } h := &Hook{ name: name, - path: path.Join(repoPath, "hooks", name+".d", name), + path: filepath.Join(repoPath, "hooks", name+".d", GetHookNames()[name]), } samplePath := filepath.Join(repoPath, "hooks", name+".sample") if isFile(h.path) { @@ -107,9 +112,9 @@ func ListHooks(repoPath string) (_ []*Hook, err error) { return nil, errors.New("hooks path does not exist") } - hooks := make([]*Hook, len(hookNames)) - for i, name := range hookNames { - hooks[i], err = GetHook(repoPath, name) + hooks := make([]*Hook, len(GetHookNames())) + for i := range hookNames { + hooks[i], err = GetHook(repoPath, hookNames[i]) if err != nil { return nil, err } diff --git a/modules/setting/hooks.go b/modules/setting/hooks.go new file mode 100644 index 0000000000..454a4cc9b5 --- /dev/null +++ b/modules/setting/hooks.go @@ -0,0 +1,42 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "fmt" + "path/filepath" + + "code.gitea.io/gitea/modules/log" +) + +var ( + // Git hook settings + GitHookPrereceiveName string + GitHookPostreceiveName string + GitHookUpdateName string +) + +func isValidFileName(filename string) error { + if filepath.Base(filename) != filename || filepath.IsAbs(filename) || filename == "." || filename == ".." { + return fmt.Errorf("can only contain filenames, not other directories") + } + return nil +} + +func loadHooksFrom(rootCfg ConfigProvider) { + githooks := rootCfg.Section("git.hooks") + GitHookPrereceiveName = githooks.Key("GIT_HOOK_PRERECEIVE_NAME").MustString("pre-receive") + GitHookUpdateName = githooks.Key("GIT_HOOK_UPDATE_NAME").MustString("update") + GitHookPostreceiveName = githooks.Key("GIT_HOOK_POSTRECEIVE_NAME").MustString("post-receive") + + if err := isValidFileName(GitHookPrereceiveName); err != nil { + log.Fatal("'%s' is an invalid [git.hooks].GIT_HOOK_PRERECEIVE_NAME: %v", GitHookPrereceiveName, err) + } + if err := isValidFileName(GitHookUpdateName); err != nil { + log.Fatal("'%s' is an invalid [git.hooks].GIT_HOOK_UPDATE_NAME: %v", GitHookUpdateName, err) + } + if err := isValidFileName(GitHookPostreceiveName); err != nil { + log.Fatal("'%s' is an invalid [git.hooks].GIT_HOOK_POSTRECEIVE_NAME: %v", GitHookPostreceiveName, err) + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index b4f913cdae..0a3c4d674e 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -118,6 +118,7 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { loadOAuth2From(cfg) loadSecurityFrom(cfg) + loadHooksFrom(cfg) if err := loadAttachmentFrom(cfg); err != nil { return err } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index fbada5472c..1d7e9b24a5 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3138,6 +3138,9 @@ config.disable_router_log = Disable Router Log config.run_user = Run As Username config.run_mode = Run Mode config.git_version = Git Version +config.git_hookprereceivename = Git Prereceive Hook Name +config.git_hookupdatename = Git Update Hook Name +config.git_postreceivename = Git Postreceive Hook Name config.app_data_path = App Data Path config.repo_root_path = Repository Root Path config.lfs_root_path = LFS Root Path diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 2a842cff82..5a1be0b11c 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -113,7 +113,9 @@ func Config(ctx *context.Context) { ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode) ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo() - + ctx.Data["GitHookPrereceiveName"] = setting.GitHookPrereceiveName + ctx.Data["GitHookUpdateName"] = setting.GitHookUpdateName + ctx.Data["GitHookPostreceiveName"] = setting.GitHookPostreceiveName ctx.Data["AppDataPath"] = setting.AppDataPath ctx.Data["RepoRootPath"] = setting.RepoRootPath ctx.Data["CustomRootPath"] = setting.CustomPath diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 197a6c6add..dc903aff2f 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -311,6 +311,18 @@
{{.Git.Timeout.Pull}} {{ctx.Locale.Tr "tool.raw_seconds"}}
{{ctx.Locale.Tr "admin.config.git_gc_timeout"}}
{{.Git.Timeout.GC}} {{ctx.Locale.Tr "tool.raw_seconds"}}
+ +
+ +
{{ctx.Locale.Tr "admin.config.git_hookprereceivename"}}
+
{{.GitHookPrereceiveName}}
+ +
{{ctx.Locale.Tr "admin.config.git_hookupdatename"}}
+
{{.GitHookUpdateName}}
+ +
{{ctx.Locale.Tr "admin.config.git_postreceivename"}}
+
{{.GitHookPostreceiveName}}
+