@@ -17,6 +17,7 @@ import ( |
| 17 | 17 | |
| 18 | 18 | "github.com/tenseleyFlow/shithub/internal/auth/audit" |
| 19 | 19 | "github.com/tenseleyFlow/shithub/internal/auth/throttle" |
| 20 | + "github.com/tenseleyFlow/shithub/internal/git/hooks" |
| 20 | 21 | "github.com/tenseleyFlow/shithub/internal/infra/storage" |
| 21 | 22 | repogit "github.com/tenseleyFlow/shithub/internal/repos/git" |
| 22 | 23 | reposdb "github.com/tenseleyFlow/shithub/internal/repos/sqlc" |
@@ -41,6 +42,11 @@ type Deps struct { |
| 41 | 42 | Limiter *throttle.Limiter |
| 42 | 43 | Logger *slog.Logger |
| 43 | 44 | 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 |
| 44 | 50 | } |
| 45 | 51 | |
| 46 | 52 | // 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) { |
| 164 | 170 | return Result{}, fmt.Errorf("repos: init bare: %w", err) |
| 165 | 171 | } |
| 166 | 172 | |
| 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 | + |
| 167 | 185 | var commitOID string |
| 168 | 186 | if wantInit { |
| 169 | 187 | commitWhen := p.InitialCommitWhen |