Apply PR #76 from dannomayernotabot: - Add golangci exclusions for internal package false positives - Tighten file permissions (0644 -> 0600) for sensitive files - Add ReadHeaderTimeout to HTTP server (slowloris prevention) - Explicit error ignoring with _ = for intentional cases - Add //nolint comments with justifications - Spelling: cancelled -> canceled (US locale) Co-Authored-By: dannomayernotabot <noreply@github.com> 🤖 Generated with Claude Code
148 lines
4.9 KiB
Go
148 lines
4.9 KiB
Go
package protocol
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/steveyegge/gastown/internal/mail"
|
|
"github.com/steveyegge/gastown/internal/mrqueue"
|
|
)
|
|
|
|
// DefaultRefineryHandler provides the default implementation for Refinery protocol handlers.
|
|
// It receives MERGE_READY messages from the Witness and adds work to the merge queue.
|
|
type DefaultRefineryHandler struct {
|
|
// Rig is the name of the rig this refinery processes.
|
|
Rig string
|
|
|
|
// WorkDir is the working directory for operations.
|
|
WorkDir string
|
|
|
|
// Queue is the merge request queue.
|
|
Queue *mrqueue.Queue
|
|
|
|
// Router is used to send mail messages.
|
|
Router *mail.Router
|
|
|
|
// Output is where to write status messages.
|
|
Output io.Writer
|
|
}
|
|
|
|
// NewRefineryHandler creates a new DefaultRefineryHandler.
|
|
func NewRefineryHandler(rig, workDir string) *DefaultRefineryHandler {
|
|
return &DefaultRefineryHandler{
|
|
Rig: rig,
|
|
WorkDir: workDir,
|
|
Queue: mrqueue.New(workDir),
|
|
Router: mail.NewRouter(workDir),
|
|
Output: os.Stdout,
|
|
}
|
|
}
|
|
|
|
// SetOutput sets the output writer for status messages.
|
|
func (h *DefaultRefineryHandler) SetOutput(w io.Writer) {
|
|
h.Output = w
|
|
}
|
|
|
|
// HandleMergeReady handles a MERGE_READY message from Witness.
|
|
// When a polecat's work is verified and ready, the Refinery:
|
|
// 1. Validates the merge request
|
|
// 2. Adds it to the merge queue
|
|
// 3. Acknowledges receipt
|
|
func (h *DefaultRefineryHandler) HandleMergeReady(payload *MergeReadyPayload) error {
|
|
_, _ = fmt.Fprintf(h.Output, "[Refinery] MERGE_READY received for polecat %s\n", payload.Polecat)
|
|
_, _ = fmt.Fprintf(h.Output, " Branch: %s\n", payload.Branch)
|
|
_, _ = fmt.Fprintf(h.Output, " Issue: %s\n", payload.Issue)
|
|
_, _ = fmt.Fprintf(h.Output, " Verified: %s\n", payload.Verified)
|
|
|
|
// Validate required fields
|
|
if payload.Branch == "" {
|
|
return fmt.Errorf("missing branch in MERGE_READY payload")
|
|
}
|
|
if payload.Polecat == "" {
|
|
return fmt.Errorf("missing polecat in MERGE_READY payload")
|
|
}
|
|
|
|
// Create merge request (ID is generated by Submit if empty)
|
|
mr := &mrqueue.MR{
|
|
Branch: payload.Branch,
|
|
Worker: payload.Polecat,
|
|
SourceIssue: payload.Issue,
|
|
Target: "main", // Default target, could be passed in payload
|
|
Rig: payload.Rig,
|
|
Title: fmt.Sprintf("Merge %s work on %s", payload.Polecat, payload.Issue),
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
// Add to queue
|
|
if err := h.Queue.Submit(mr); err != nil {
|
|
_, _ = fmt.Fprintf(h.Output, "[Refinery] Error adding to queue: %v\n", err)
|
|
return fmt.Errorf("failed to add merge request to queue: %w", err)
|
|
}
|
|
|
|
_, _ = fmt.Fprintf(h.Output, "[Refinery] ✓ Added to merge queue: %s\n", mr.ID)
|
|
_, _ = fmt.Fprintf(h.Output, " Queue length: %d\n", h.Queue.Count())
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendMerged sends a MERGED message to the Witness.
|
|
// Called by the Refinery after successfully merging a branch.
|
|
func (h *DefaultRefineryHandler) SendMerged(polecat, branch, issue, targetBranch, mergeCommit string) error {
|
|
msg := NewMergedMessage(h.Rig, polecat, branch, issue, targetBranch, mergeCommit)
|
|
return h.Router.Send(msg)
|
|
}
|
|
|
|
// SendMergeFailed sends a MERGE_FAILED message to the Witness.
|
|
// Called by the Refinery when a merge fails.
|
|
func (h *DefaultRefineryHandler) SendMergeFailed(polecat, branch, issue, targetBranch, failureType, errorMsg string) error {
|
|
msg := NewMergeFailedMessage(h.Rig, polecat, branch, issue, targetBranch, failureType, errorMsg)
|
|
return h.Router.Send(msg)
|
|
}
|
|
|
|
// SendReworkRequest sends a REWORK_REQUEST message to the Witness.
|
|
// Called by the Refinery when a branch has conflicts.
|
|
func (h *DefaultRefineryHandler) SendReworkRequest(polecat, branch, issue, targetBranch string, conflictFiles []string) error {
|
|
msg := NewReworkRequestMessage(h.Rig, polecat, branch, issue, targetBranch, conflictFiles)
|
|
return h.Router.Send(msg)
|
|
}
|
|
|
|
// NotifyMergeOutcome is a convenience method that sends the appropriate message
|
|
// based on the merge result.
|
|
type MergeOutcome struct {
|
|
// Success indicates whether the merge was successful.
|
|
Success bool
|
|
|
|
// Conflict indicates the failure was due to conflicts (needs rebase).
|
|
Conflict bool
|
|
|
|
// FailureType categorizes the failure (e.g., "tests", "build").
|
|
FailureType string
|
|
|
|
// Error is the error message if the merge failed.
|
|
Error string
|
|
|
|
// MergeCommit is the SHA of the merge commit on success.
|
|
MergeCommit string
|
|
|
|
// ConflictFiles lists files with conflicts (if Conflict is true).
|
|
ConflictFiles []string
|
|
}
|
|
|
|
// NotifyMergeOutcome sends the appropriate protocol message based on the outcome.
|
|
func (h *DefaultRefineryHandler) NotifyMergeOutcome(polecat, branch, issue, targetBranch string, outcome MergeOutcome) error {
|
|
if outcome.Success {
|
|
return h.SendMerged(polecat, branch, issue, targetBranch, outcome.MergeCommit)
|
|
}
|
|
|
|
if outcome.Conflict {
|
|
return h.SendReworkRequest(polecat, branch, issue, targetBranch, outcome.ConflictFiles)
|
|
}
|
|
|
|
return h.SendMergeFailed(polecat, branch, issue, targetBranch, outcome.FailureType, outcome.Error)
|
|
}
|
|
|
|
// Ensure DefaultRefineryHandler implements RefineryHandler.
|
|
var _ RefineryHandler = (*DefaultRefineryHandler)(nil)
|