82c4c604da95cc46767072f99f73da61233014cb
- Author
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Committer
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/cmd/soft/hook.go b/cmd/soft/hook.go
2index a24fc6b33c20ee7e1e83147beb6112f7f0b368a2..fc78221722e4c0b5801cdc24fe30e9456786d325 100644
3--- a/cmd/soft/hook.go
4+++ b/cmd/soft/hook.go
5@@ -5,7 +5,10 @@ import (
6 "bytes"
7 "context"
8 "fmt"
9+ "io"
10 "os"
11+ "os/exec"
12+ "path/filepath"
13 "strings"
14
15 "github.com/charmbracelet/soft-serve/server/backend"
16@@ -34,6 +37,16 @@ var (
17 return fmt.Errorf("could not parse config: %w", err)
18 }
19
20+ customHooksPath := filepath.Join(filepath.Dir(configPath), "hooks")
21+ if _, err := os.Stat(customHooksPath); err != nil && os.IsNotExist(err) {
22+ os.MkdirAll(customHooksPath, os.ModePerm)
23+ // Generate update hook example without executable permissions
24+ hookPath := filepath.Join(customHooksPath, "update.sample")
25+ if err := os.WriteFile(hookPath, []byte(updateHookExample), 0744); err != nil {
26+ return fmt.Errorf("failed to generate update hook example: %w", err)
27+ }
28+ }
29+
30 // Set up the backend
31 // TODO: support other backends
32 sb, err := sqlite.NewSqliteBackend(cmd.Context(), cfg)
33@@ -57,21 +70,24 @@ var (
34 // This is set in the server before invoking git-receive-pack/git-upload-pack
35 repoName := os.Getenv("SOFT_SERVE_REPO_NAME")
36
37- in := cmd.InOrStdin()
38- out := cmd.OutOrStdout()
39- err := cmd.ErrOrStderr()
40+ stdin := cmd.InOrStdin()
41+ stdout := cmd.OutOrStdout()
42+ stderr := cmd.ErrOrStderr()
43
44 cmdName := cmd.Name()
45+ customHookPath := filepath.Join(filepath.Dir(configPath), "hooks", cmdName)
46+
47+ var buf bytes.Buffer
48+ opts := make([]backend.HookArg, 0)
49+
50 switch cmdName {
51 case hooks.PreReceiveHook, hooks.PostReceiveHook:
52- var buf bytes.Buffer
53- opts := make([]backend.HookArg, 0)
54- scanner := bufio.NewScanner(in)
55+ scanner := bufio.NewScanner(stdin)
56 for scanner.Scan() {
57 buf.Write(scanner.Bytes())
58 fields := strings.Fields(scanner.Text())
59 if len(fields) != 3 {
60- return fmt.Errorf("invalid pre-receive hook input: %s", scanner.Text())
61+ return fmt.Errorf("invalid hook input: %s", scanner.Text())
62 }
63 opts = append(opts, backend.HookArg{
64 OldSha: fields[0],
65@@ -82,22 +98,30 @@ var (
66
67 switch cmdName {
68 case hooks.PreReceiveHook:
69- hks.PreReceive(out, err, repoName, opts)
70+ hks.PreReceive(stdout, stderr, repoName, opts)
71 case hooks.PostReceiveHook:
72- hks.PostReceive(out, err, repoName, opts)
73+ hks.PostReceive(stdout, stderr, repoName, opts)
74 }
75 case hooks.UpdateHook:
76 if len(args) != 3 {
77 return fmt.Errorf("invalid update hook input: %s", args)
78 }
79
80- hks.Update(out, err, repoName, backend.HookArg{
81+ hks.Update(stdout, stderr, repoName, backend.HookArg{
82 OldSha: args[0],
83 NewSha: args[1],
84 RefName: args[2],
85 })
86 case hooks.PostUpdateHook:
87- hks.PostUpdate(out, err, repoName, args...)
88+ hks.PostUpdate(stdout, stderr, repoName, args...)
89+ }
90+
91+ // Custom hooks
92+ if stat, err := os.Stat(customHookPath); err == nil && !stat.IsDir() && stat.Mode()&0o111 != 0 {
93+ // If the custom hook is executable, run it
94+ if err := runCommand(cmd.Context(), &buf, stdout, stderr, customHookPath, args...); err != nil {
95+ return fmt.Errorf("failed to run custom hook: %w", err)
96+ }
97 }
98
99 return nil
100@@ -138,3 +162,54 @@ func init() {
101 postUpdateCmd,
102 )
103 }
104+