tenseleyflow/shithub / aa9ab45

Browse files

S14: install hooks on repo create; thread shithubd path from web layer

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
aa9ab459f5bcea69fa4df234c0107d4fac49f26c
Parents
a6e775f
Tree
000e13d

3 changed files

StatusFile+-
M internal/repos/create.go 18 0
M internal/web/handlers/repo/repo.go 10 5
M internal/web/repo_wiring.go 19 6
internal/repos/create.gomodified
@@ -17,6 +17,7 @@ import (
1717
 
1818
 	"github.com/tenseleyFlow/shithub/internal/auth/audit"
1919
 	"github.com/tenseleyFlow/shithub/internal/auth/throttle"
20
+	"github.com/tenseleyFlow/shithub/internal/git/hooks"
2021
 	"github.com/tenseleyFlow/shithub/internal/infra/storage"
2122
 	repogit "github.com/tenseleyFlow/shithub/internal/repos/git"
2223
 	reposdb "github.com/tenseleyFlow/shithub/internal/repos/sqlc"
@@ -41,6 +42,11 @@ type Deps struct {
4142
 	Limiter *throttle.Limiter
4243
 	Logger  *slog.Logger
4344
 	Now     func() time.Time
45
+	// ShithubdPath is the absolute path to the running shithubd binary,
46
+	// baked into the hook shims so push -> hook -> shithubd round-trip
47
+	// works in dev and prod. Empty disables hook installation (tests
48
+	// that don't care about hooks; the full E2E happy path provides it).
49
+	ShithubdPath string
4450
 }
4551
 
4652
 // Params describes one repo-create request as it arrives from the
@@ -164,6 +170,18 @@ func Create(ctx context.Context, deps Deps, p Params) (Result, error) {
164170
 		return Result{}, fmt.Errorf("repos: init bare: %w", err)
165171
 	}
166172
 
173
+	// Install push-pipeline hooks. Skipped when ShithubdPath is empty
174
+	// (test fixtures that exercise repo creation without the hook
175
+	// stack). The plumbing-driven initial commit doesn't fire hooks —
176
+	// hooks only run on user-driven pushes — so this is the right
177
+	// boundary.
178
+	if deps.ShithubdPath != "" {
179
+		if err := hooks.Install(diskPath, deps.ShithubdPath); err != nil {
180
+			_ = os.RemoveAll(diskPath)
181
+			return Result{}, fmt.Errorf("repos: install hooks: %w", err)
182
+		}
183
+	}
184
+
167185
 	var commitOID string
168186
 	if wantInit {
169187
 		commitWhen := p.InitialCommitWhen
internal/web/handlers/repo/repo.gomodified
@@ -47,6 +47,10 @@ type Deps struct {
4747
 	Audit     *audit.Recorder
4848
 	Limiter   *throttle.Limiter
4949
 	CloneURLs CloneURLs
50
+	// ShithubdPath is forwarded to repos.Create so newly-init'd repos
51
+	// have hook shims pointing at the right binary. Empty in test fixtures
52
+	// that don't exercise hooks.
53
+	ShithubdPath string
5054
 }
5155
 
5256
 // Handlers is the registered handler set. Construct via New.
@@ -133,6 +137,7 @@ func (h *Handlers) newRepoSubmit(w http.ResponseWriter, r *http.Request) {
133137
 		Audit:        h.d.Audit,
134138
 		Limiter:      h.d.Limiter,
135139
 		Logger:       h.d.Logger,
140
+		ShithubdPath: h.d.ShithubdPath,
136141
 	}, repos.Params{
137142
 		OwnerUserID:   user.ID,
138143
 		OwnerUsername: user.Username,
internal/web/repo_wiring.gomodified
@@ -7,6 +7,7 @@ import (
77
 	"fmt"
88
 	"io/fs"
99
 	"log/slog"
10
+	"os"
1011
 	"path/filepath"
1112
 
1213
 	"github.com/jackc/pgx/v5/pgxpool"
@@ -43,6 +44,17 @@ func buildRepoHandlers(
4344
 	if err != nil {
4445
 		return nil, fmt.Errorf("repo: render.New: %w", err)
4546
 	}
47
+	// shithubdPath is the running binary, baked into hook shims by
48
+	// repos.Create. os.Executable can rarely fail (e.g. exec name
49
+	// stripped); when it does we fall back to "shithubd" on PATH so
50
+	// hook shims still resolve in unusual environments.
51
+	shithubdPath := "shithubd"
52
+	if exe, err := os.Executable(); err == nil {
53
+		if abs, err := filepath.Abs(exe); err == nil {
54
+			shithubdPath = abs
55
+		}
56
+	}
57
+
4658
 	return repoh.New(repoh.Deps{
4759
 		Logger:       logger,
4860
 		Render:       rr,
@@ -50,6 +62,7 @@ func buildRepoHandlers(
5062
 		RepoFS:       rfs,
5163
 		Audit:        audit.NewRecorder(),
5264
 		Limiter:      throttle.NewLimiter(),
65
+		ShithubdPath: shithubdPath,
5366
 		CloneURLs: repoh.CloneURLs{
5467
 			BaseURL:    cfg.Auth.BaseURL,
5568
 			SSHEnabled: false, // S12/S13 will flip this when SSH service ships.