pass hook configuration through CLI arguments

This commit is contained in:
Jabberwocky238
2026-07-30 01:15:49 -04:00
parent 1e5b0225f5
commit 8d299013f9
4 changed files with 54 additions and 36 deletions
+6 -12
View File
@@ -96,21 +96,15 @@ simpleci 提供集成适配器 `pkgs/simpleci/simplegit-hook.sh`。联合部署
显式使用该脚本,并配置:
```sh
export SIMPLECI_URL=http://simpleci:8095
export SIMPLECI_HOOK_TOKEN=replace-with-a-shared-secret
export SIMPLECI_WORKFLOW=.github/workflows/deploy.yml # 可选
simplegit daemon -hook-script /path/to/simplegit-hook.sh
simplegit daemon \
-hook-script=/path/to/simplegit-hook.sh \
-hook-arg=--url=http://simpleci:8095 \
-hook-arg=--workflow=.github/workflows/deploy.yml \
-hook-arg=--
```
tag push 和分支删除不会触发构建;simpleci 不可用时通知最多等待 5 秒,且不影响
push 的成功结果。simpleci 使用相同 secret 启动:
```sh
simpleci -hook-token replace-with-a-shared-secret
```
`SIMPLECI_HOOK_TOKEN``-hook-token` 都为空时不启用鉴权,适合仅在受信任的
本机或内部网络开发;生产环境应从同一个 Secret 分别注入两端。
push 的成功结果。`POST /runs` 应只暴露在受信任的内部网络。
---
+29 -19
View File
@@ -33,6 +33,10 @@ func Run(args []string) {
return nil
})
fs.StringVar(&cfg.HookScript, "hook-script", "./hook.sh", "script run by every Git hook; receives hook type and owner/name as its first two arguments")
fs.Func("hook-arg", "fixed argument passed to -hook-script before hook type and owner/name (repeatable)", func(arg string) error {
cfg.HookArgs = append(cfg.HookArgs, arg)
return nil
})
fs.StringVar(&cfg.DBUri, "db", "sqlite://./db.sqlite", "private state DB URI (sqlite://<path> or postgres://<dsn>) - backs PAT/SSH-key ACLs and repo metadata")
fs.Parse(args)
@@ -51,9 +55,6 @@ func Run(args []string) {
app := NewApp(cfg.RepoRoot(), store)
server := gitrpc.NewServer(&cfg, store)
if _, err := ensureHookTemplate(cfg.Root); err != nil {
log.Printf("simplegit: hook template: %v (hooks disabled)", err)
}
if cfg.HookScript != "" {
hookScript, err := resolveHookScript(cfg.HookScript)
if err != nil {
@@ -67,15 +68,10 @@ func Run(args []string) {
log.Fatalf("simplegit: hook script %s is not executable", hookScript)
}
cfg.HookScript = hookScript
_ = os.Setenv("SIMPLEGIT_HOOK_SCRIPT", hookScript)
repoRoot, err := filepath.Abs(cfg.RepoRoot())
if err != nil {
log.Fatalf("simplegit: resolve repository root: %v", err)
log.Printf("simplegit: Git hooks execute %s %s", hookScript, strings.Join(cfg.HookArgs, " "))
}
_ = os.Setenv("SIMPLEGIT_REPO_ROOT", repoRoot)
log.Printf("simplegit: Git hooks execute %s", hookScript)
} else {
_ = os.Unsetenv("SIMPLEGIT_HOOK_SCRIPT")
if _, err := ensureHookTemplate(cfg.Root, cfg.HookScript, cfg.HookArgs); err != nil {
log.Printf("simplegit: hook template: %v (hooks disabled)", err)
}
// gitrpc mux: Connect-RPC (GitService + ManageService) + the binary content
@@ -153,16 +149,18 @@ var gitHookNames = []string{
"p4-prepare-changelist", "p4-changelist",
}
const hookWrapper = `#!/bin/sh
# Generated by simplegit. The operator controls hook behavior with -hook-script.
test -n "$SIMPLEGIT_HOOK_SCRIPT" || exit 0
const hookWrapperTemplate = `#!/bin/sh
# Generated by simplegit. The operator controls behavior with -hook-script.
repo_dir=$(pwd -P)
repo=${repo_dir#"$SIMPLEGIT_REPO_ROOT"/}
repo=${repo%%.git}
exec "$SIMPLEGIT_HOOK_SCRIPT" %s "$repo" "$@"
repo_name=${repo_dir##*/}
repo_name=${repo_name%%.git}
owner_dir=${repo_dir%%/*}
owner=${owner_dir##*/}
repo=$owner/$repo_name
exec %s %s "$repo" "$@"
`
func ensureHookTemplate(root string) (string, error) {
func ensureHookTemplate(root, script string, args []string) (string, error) {
dir := filepath.Join(root, "template")
hooksDir := filepath.Join(dir, "hooks")
if err := os.MkdirAll(hooksDir, 0o755); err != nil {
@@ -170,7 +168,15 @@ func ensureHookTemplate(root string) (string, error) {
}
for _, name := range gitHookNames {
path := filepath.Join(hooksDir, name)
if err := os.WriteFile(path, []byte(fmt.Sprintf(hookWrapper, name)), 0o755); err != nil {
body := "#!/bin/sh\nexit 0\n"
if script != "" {
command := shellQuote(script)
for _, arg := range args {
command += " " + shellQuote(arg)
}
body = fmt.Sprintf(hookWrapperTemplate, command, shellQuote(name))
}
if err := os.WriteFile(path, []byte(body), 0o755); err != nil {
return "", fmt.Errorf("write hook %s: %w", name, err)
}
}
@@ -180,6 +186,10 @@ func ensureHookTemplate(root string) (string, error) {
return dir, nil
}
func shellQuote(value string) string {
return "'" + strings.ReplaceAll(value, "'", `'"'"'`) + "'"
}
func refreshRepositoryHooks(reposRoot, templateHooks string) error {
if _, err := os.Stat(reposRoot); os.IsNotExist(err) {
return nil
+2
View File
@@ -27,6 +27,8 @@ type Config struct {
// The hook name is its first argument; Git's original args, stdin and
// environment are preserved. Empty disables hook effects.
HookScript string
// HookArgs are fixed CLI arguments placed before the hook type and repo.
HookArgs []string
DBUri string
preparedDbUri string
+15 -3
View File
@@ -1,8 +1,20 @@
#!/bin/sh
# Default standalone policy: append the hook invocation and its stdin to a log.
# Integrations can supply another script with simplegit daemon -hook-script.
# Default standalone policy. Optional CLI: --log=/path/to/hooks.log --
log_file=${SIMPLEGIT_HOOK_LOG:-${SIMPLEGIT_REPO_ROOT%/repos}/hooks.log}
log_file=
while [ "$#" -gt 0 ]; do
case "$1" in
--log=*) log_file=${1#--log=}; shift ;;
--log) log_file=$2; shift 2 ;;
--) shift; break ;;
*) break ;;
esac
done
[ "$#" -ge 2 ] || exit 0
if [ -z "$log_file" ]; then
repo_dir=$(pwd -P)
log_file=${repo_dir%/*/*}/hooks.log
fi
{
printf '%s\t%s\t%s' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$1" "$2"
shift 2