blob: 8feadedff22c5c3c1169abe5611c3958458e40a2 [file] [log] [blame]
iomodob23799d2025-07-31 14:08:22 +04001package app
2
3import (
iomodo13a10fc2025-07-31 17:47:06 +04004 "context"
iomodob23799d2025-07-31 14:08:22 +04005 "fmt"
iomodo13a10fc2025-07-31 17:47:06 +04006 "log/slog"
7 "time"
iomodob23799d2025-07-31 14:08:22 +04008
9 "github.com/iomodo/staff/git"
10)
11
12func (a *App) ProposalApproval(body []byte, signature string) error {
iomodo13a10fc2025-07-31 17:47:06 +040013 // Set reasonable timeout for webhook processing
14 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
15 defer cancel()
16
17 // Validate required dependencies
18 if a.git == nil {
19 return fmt.Errorf("git interface not initialized")
20 }
21 if a.taskManager == nil {
22 return fmt.Errorf("task manager not initialized")
iomodob23799d2025-07-31 14:08:22 +040023 }
24
iomodo13a10fc2025-07-31 17:47:06 +040025 // Process the webhook payload (includes signature validation)
iomodob23799d2025-07-31 14:08:22 +040026 taskID, err := git.ProcessMergeWebhook(body, signature, a.config.GitHub.WebhookSecret)
27 if err != nil {
iomodo8acd08d2025-07-31 16:22:08 +040028 return fmt.Errorf("failed to process webhook: %w", err)
iomodob23799d2025-07-31 14:08:22 +040029 }
30
iomodob23799d2025-07-31 14:08:22 +040031 a.logger.Info("Proposal approved via webhook",
iomodo13a10fc2025-07-31 17:47:06 +040032 slog.String("task_id", taskID),
33 slog.String("repository", fmt.Sprintf("%s/%s", a.config.GitHub.Owner, a.config.GitHub.Repo)),
iomodob23799d2025-07-31 14:08:22 +040034 )
iomodo13a10fc2025-07-31 17:47:06 +040035
36 // Synchronize repository to get any new tasks that were added
37 a.syncRepository(ctx)
38 a.logger.Info("Webhook processing completed successfully",
39 slog.String("task_id", taskID),
40 )
41
iomodob23799d2025-07-31 14:08:22 +040042 return nil
43}
iomodo13a10fc2025-07-31 17:47:06 +040044
45// syncRepository pulls the remote repository to fetch new tasks
46// This is non-critical for webhook success, so failures are logged but don't fail the webhook
47func (a *App) syncRepository(ctx context.Context) {
48 a.logger.Info("Synchronizing repository to fetch new tasks")
49
50 // Get current branch to determine the upstream branch to pull from
51 currentBranch, err := a.git.GetCurrentBranch(ctx)
52 if err != nil {
53 a.logger.Warn("Failed to get current branch, using default pull",
54 slog.String("error", err.Error()),
55 )
56 // Fallback to simple pull without specifying branch
57 if err := a.git.Pull(ctx, "origin", ""); err != nil {
58 a.logger.Warn("Failed to synchronize repository",
59 slog.String("remote", "origin"),
60 slog.String("error", err.Error()),
61 )
62 } else {
63 a.logger.Info("Successfully synchronized repository",
64 slog.String("remote", "origin"),
65 )
66 }
67 return
68 }
69
70 // Get the upstream branch for the current branch
71 upstreamBranch, err := a.git.GetUpstreamBranch(ctx, currentBranch)
72 if err != nil {
73 a.logger.Warn("Failed to get upstream branch, trying simple pull",
74 slog.String("current_branch", currentBranch),
75 slog.String("error", err.Error()),
76 )
77 // Fallback to simple pull without specifying branch
78 if err := a.git.Pull(ctx, "origin", ""); err != nil {
79 a.logger.Warn("Failed to synchronize repository",
80 slog.String("remote", "origin"),
81 slog.String("error", err.Error()),
82 )
83 } else {
84 a.logger.Info("Successfully synchronized repository",
85 slog.String("remote", "origin"),
86 )
87 }
88 return
89 }
90
91 // Use the upstream branch for pulling
92 if err := a.git.Pull(ctx, "origin", upstreamBranch); err != nil {
93 // Don't fail the entire webhook if git pull fails - agents can still work with existing tasks
94 a.logger.Warn("Failed to synchronize repository",
95 slog.String("remote", "origin"),
96 slog.String("branch", upstreamBranch),
97 slog.String("error", err.Error()),
98 )
99 } else {
100 a.logger.Info("Successfully synchronized repository",
101 slog.String("remote", "origin"),
102 slog.String("branch", upstreamBranch),
103 )
104 }
105}