blob: 7858d2bcbe573f19170e7dfa15ff25487c8b04b1 [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
iomodoe5970ba2025-07-31 17:59:52 +040031 // Complete the task for the agent that was performing it
32 if err := a.manager.CompleteTaskForAgent(taskID); err != nil {
33 a.logger.Warn("Failed to complete task for agent",
34 slog.String("task_id", taskID),
35 slog.String("error", err.Error()))
36 // Don't fail the webhook if agent completion fails
37 }
38
iomodob23799d2025-07-31 14:08:22 +040039 a.logger.Info("Proposal approved via webhook",
iomodo13a10fc2025-07-31 17:47:06 +040040 slog.String("task_id", taskID),
41 slog.String("repository", fmt.Sprintf("%s/%s", a.config.GitHub.Owner, a.config.GitHub.Repo)),
iomodob23799d2025-07-31 14:08:22 +040042 )
iomodo13a10fc2025-07-31 17:47:06 +040043
44 // Synchronize repository to get any new tasks that were added
45 a.syncRepository(ctx)
46 a.logger.Info("Webhook processing completed successfully",
47 slog.String("task_id", taskID),
48 )
49
iomodob23799d2025-07-31 14:08:22 +040050 return nil
51}
iomodo13a10fc2025-07-31 17:47:06 +040052
53// syncRepository pulls the remote repository to fetch new tasks
54// This is non-critical for webhook success, so failures are logged but don't fail the webhook
55func (a *App) syncRepository(ctx context.Context) {
56 a.logger.Info("Synchronizing repository to fetch new tasks")
57
58 // Get current branch to determine the upstream branch to pull from
59 currentBranch, err := a.git.GetCurrentBranch(ctx)
60 if err != nil {
61 a.logger.Warn("Failed to get current branch, using default pull",
62 slog.String("error", err.Error()),
63 )
64 // Fallback to simple pull without specifying branch
65 if err := a.git.Pull(ctx, "origin", ""); err != nil {
66 a.logger.Warn("Failed to synchronize repository",
67 slog.String("remote", "origin"),
68 slog.String("error", err.Error()),
69 )
70 } else {
71 a.logger.Info("Successfully synchronized repository",
72 slog.String("remote", "origin"),
73 )
74 }
75 return
76 }
77
78 // Get the upstream branch for the current branch
79 upstreamBranch, err := a.git.GetUpstreamBranch(ctx, currentBranch)
80 if err != nil {
81 a.logger.Warn("Failed to get upstream branch, trying simple pull",
82 slog.String("current_branch", currentBranch),
83 slog.String("error", err.Error()),
84 )
85 // Fallback to simple pull without specifying branch
86 if err := a.git.Pull(ctx, "origin", ""); err != nil {
87 a.logger.Warn("Failed to synchronize repository",
88 slog.String("remote", "origin"),
89 slog.String("error", err.Error()),
90 )
91 } else {
92 a.logger.Info("Successfully synchronized repository",
93 slog.String("remote", "origin"),
94 )
95 }
96 return
97 }
98
99 // Use the upstream branch for pulling
100 if err := a.git.Pull(ctx, "origin", upstreamBranch); err != nil {
101 // Don't fail the entire webhook if git pull fails - agents can still work with existing tasks
102 a.logger.Warn("Failed to synchronize repository",
103 slog.String("remote", "origin"),
104 slog.String("branch", upstreamBranch),
105 slog.String("error", err.Error()),
106 )
107 } else {
108 a.logger.Info("Successfully synchronized repository",
109 slog.String("remote", "origin"),
110 slog.String("branch", upstreamBranch),
111 )
112 }
113}