Add repo sync
Change-Id: I6b61873c97e9ff46a699151fc52aa937248bcf81
diff --git a/server/app/app.go b/server/app/app.go
index a016c4b..ace8904 100644
--- a/server/app/app.go
+++ b/server/app/app.go
@@ -7,14 +7,17 @@
"github.com/iomodo/staff/agent"
"github.com/iomodo/staff/config"
"github.com/iomodo/staff/git"
+ "github.com/iomodo/staff/tm"
"github.com/iomodo/staff/tm/git_tm"
)
// App type defines application global state
type App struct {
- logger *slog.Logger
- config *config.Config
- manager *agent.Manager
+ logger *slog.Logger
+ config *config.Config
+ manager *agent.Manager
+ git git.GitInterface
+ taskManager tm.TaskManager
}
// NewApp creates new App
@@ -29,9 +32,11 @@
}
return &App{
- logger: logger,
- config: config,
- manager: manager,
+ logger: logger,
+ config: config,
+ manager: manager,
+ git: gitInterface,
+ taskManager: taskManager,
}, nil
}
diff --git a/server/app/proposal.go b/server/app/proposal.go
index 165f336..8feaded 100644
--- a/server/app/proposal.go
+++ b/server/app/proposal.go
@@ -1,26 +1,105 @@
package app
import (
+ "context"
"fmt"
+ "log/slog"
+ "time"
"github.com/iomodo/staff/git"
)
func (a *App) ProposalApproval(body []byte, signature string) error {
- // Validate the webhook signature
- if err := git.ValidateSignature(body, signature, a.config.GitHub.WebhookSecret); err != nil {
- return fmt.Errorf("invalid webhook signature: %w", err)
+ // Set reasonable timeout for webhook processing
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Validate required dependencies
+ if a.git == nil {
+ return fmt.Errorf("git interface not initialized")
+ }
+ if a.taskManager == nil {
+ return fmt.Errorf("task manager not initialized")
}
- // Process the webhook payload
+ // Process the webhook payload (includes signature validation)
taskID, err := git.ProcessMergeWebhook(body, signature, a.config.GitHub.WebhookSecret)
if err != nil {
return fmt.Errorf("failed to process webhook: %w", err)
}
- // Log the successful approval
a.logger.Info("Proposal approved via webhook",
- "task_id", taskID,
+ slog.String("task_id", taskID),
+ slog.String("repository", fmt.Sprintf("%s/%s", a.config.GitHub.Owner, a.config.GitHub.Repo)),
)
+
+ // Synchronize repository to get any new tasks that were added
+ a.syncRepository(ctx)
+ a.logger.Info("Webhook processing completed successfully",
+ slog.String("task_id", taskID),
+ )
+
return nil
}
+
+// syncRepository pulls the remote repository to fetch new tasks
+// This is non-critical for webhook success, so failures are logged but don't fail the webhook
+func (a *App) syncRepository(ctx context.Context) {
+ a.logger.Info("Synchronizing repository to fetch new tasks")
+
+ // Get current branch to determine the upstream branch to pull from
+ currentBranch, err := a.git.GetCurrentBranch(ctx)
+ if err != nil {
+ a.logger.Warn("Failed to get current branch, using default pull",
+ slog.String("error", err.Error()),
+ )
+ // Fallback to simple pull without specifying branch
+ if err := a.git.Pull(ctx, "origin", ""); err != nil {
+ a.logger.Warn("Failed to synchronize repository",
+ slog.String("remote", "origin"),
+ slog.String("error", err.Error()),
+ )
+ } else {
+ a.logger.Info("Successfully synchronized repository",
+ slog.String("remote", "origin"),
+ )
+ }
+ return
+ }
+
+ // Get the upstream branch for the current branch
+ upstreamBranch, err := a.git.GetUpstreamBranch(ctx, currentBranch)
+ if err != nil {
+ a.logger.Warn("Failed to get upstream branch, trying simple pull",
+ slog.String("current_branch", currentBranch),
+ slog.String("error", err.Error()),
+ )
+ // Fallback to simple pull without specifying branch
+ if err := a.git.Pull(ctx, "origin", ""); err != nil {
+ a.logger.Warn("Failed to synchronize repository",
+ slog.String("remote", "origin"),
+ slog.String("error", err.Error()),
+ )
+ } else {
+ a.logger.Info("Successfully synchronized repository",
+ slog.String("remote", "origin"),
+ )
+ }
+ return
+ }
+
+ // Use the upstream branch for pulling
+ if err := a.git.Pull(ctx, "origin", upstreamBranch); err != nil {
+ // Don't fail the entire webhook if git pull fails - agents can still work with existing tasks
+ a.logger.Warn("Failed to synchronize repository",
+ slog.String("remote", "origin"),
+ slog.String("branch", upstreamBranch),
+ slog.String("error", err.Error()),
+ )
+ } else {
+ a.logger.Info("Successfully synchronized repository",
+ slog.String("remote", "origin"),
+ slog.String("branch", upstreamBranch),
+ )
+ }
+}