refactor: extract ExecWithOutput utility for command execution (gt-vurfr)

Create util.ExecWithOutput and util.ExecRun to consolidate repeated
exec.Command patterns across witness/handlers.go and refinery/manager.go.

Changes:
- Add internal/util/exec.go with ExecWithOutput (returns stdout) and
  ExecRun (runs command without output)
- Refactor witness/handlers.go to use utility functions (7 call sites)
- Refactor refinery/manager.go, removing unused gitRun/gitOutput methods
- Add comprehensive tests in exec_test.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
wraith
2026-01-05 00:18:47 -08:00
committed by Steve Yegge
parent 18578b3030
commit ef248a1824
4 changed files with 134 additions and 140 deletions

49
internal/util/exec.go Normal file
View File

@@ -0,0 +1,49 @@
package util
import (
"bytes"
"fmt"
"os/exec"
"strings"
)
// ExecWithOutput runs a command in the specified directory and returns stdout.
// If the command fails, stderr content is included in the error message.
func ExecWithOutput(workDir, cmd string, args ...string) (string, error) {
c := exec.Command(cmd, args...) //nolint:gosec // G204: callers validate args
c.Dir = workDir
var stdout, stderr bytes.Buffer
c.Stdout = &stdout
c.Stderr = &stderr
if err := c.Run(); err != nil {
errMsg := strings.TrimSpace(stderr.String())
if errMsg != "" {
return "", fmt.Errorf("%s", errMsg)
}
return "", err
}
return strings.TrimSpace(stdout.String()), nil
}
// ExecRun runs a command in the specified directory.
// If the command fails, stderr content is included in the error message.
func ExecRun(workDir, cmd string, args ...string) error {
c := exec.Command(cmd, args...) //nolint:gosec // G204: callers validate args
c.Dir = workDir
var stderr bytes.Buffer
c.Stderr = &stderr
if err := c.Run(); err != nil {
errMsg := strings.TrimSpace(stderr.String())
if errMsg != "" {
return fmt.Errorf("%s", errMsg)
}
return err
}
return nil
}

View File

@@ -0,0 +1,67 @@
package util
import (
"os"
"strings"
"testing"
)
func TestExecWithOutput(t *testing.T) {
// Test successful command
output, err := ExecWithOutput(".", "echo", "hello")
if err != nil {
t.Fatalf("ExecWithOutput failed: %v", err)
}
if output != "hello" {
t.Errorf("expected 'hello', got %q", output)
}
// Test command that fails
_, err = ExecWithOutput(".", "false")
if err == nil {
t.Error("expected error for failing command")
}
}
func TestExecRun(t *testing.T) {
// Test successful command
err := ExecRun(".", "true")
if err != nil {
t.Fatalf("ExecRun failed: %v", err)
}
// Test command that fails
err = ExecRun(".", "false")
if err == nil {
t.Error("expected error for failing command")
}
}
func TestExecWithOutput_WorkDir(t *testing.T) {
// Create a temp directory
tmpDir, err := os.MkdirTemp("", "exec-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Test that workDir is respected
output, err := ExecWithOutput(tmpDir, "pwd")
if err != nil {
t.Fatalf("ExecWithOutput failed: %v", err)
}
if !strings.Contains(output, tmpDir) && !strings.Contains(tmpDir, output) {
t.Errorf("expected output to contain %q, got %q", tmpDir, output)
}
}
func TestExecWithOutput_StderrInError(t *testing.T) {
// Test that stderr is captured in error
_, err := ExecWithOutput(".", "sh", "-c", "echo 'error message' >&2; exit 1")
if err == nil {
t.Error("expected error")
}
if !strings.Contains(err.Error(), "error message") {
t.Errorf("expected error to contain stderr, got %q", err.Error())
}
}