Merge pull request '[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/cli/RFC.md fully. Find features des...' (#78) from agent/read---spec-code-core-go-cli-rfc-md-full into dev
All checks were successful
Security Scan / security (push) Successful in 28s

This commit is contained in:
Virgil 2026-04-02 11:11:33 +00:00
commit 3cf13e751e
2 changed files with 83 additions and 38 deletions

View file

@ -10,6 +10,7 @@ package pkgcmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@ -71,11 +72,11 @@ func runPkgRemove(name string, force bool) error {
if !force { if !force {
blocked, reasons := checkRepoSafety(repoPath) blocked, reasons := checkRepoSafety(repoPath)
if blocked { if blocked {
fmt.Printf("%s Cannot remove %s:\n", errorStyle.Render("Blocked:"), repoNameStyle.Render(name)) fmt.Fprintf(os.Stderr, "%s Cannot remove %s:\n", errorStyle.Render("Blocked:"), repoNameStyle.Render(name))
for _, r := range reasons { for _, r := range reasons {
fmt.Printf(" %s %s\n", errorStyle.Render("·"), r) fmt.Fprintf(os.Stderr, " %s %s\n", errorStyle.Render("·"), r)
} }
fmt.Printf("\nResolve the issues above or use --force to override.\n") fmt.Fprintln(os.Stderr, "\nResolve the issues above or use --force to override.")
return errors.New("package has unresolved changes") return errors.New("package has unresolved changes")
} }
} }

View file

@ -1,8 +1,9 @@
package pkgcmd package pkgcmd
import ( import (
"bytes"
"io"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
@ -13,24 +14,52 @@ import (
func setupTestRepo(t *testing.T, dir, name string) string { func setupTestRepo(t *testing.T, dir, name string) string {
t.Helper() t.Helper()
repoPath := filepath.Join(dir, name) repoPath := filepath.Join(dir, name)
require.NoError(t, os.MkdirAll(repoPath, 0755)) require.NoError(t, os.MkdirAll(repoPath, 0755))
cmds := [][]string{ gitCommand(t, repoPath, "init")
{"git", "init"}, gitCommand(t, repoPath, "config", "user.email", "test@test.com")
{"git", "config", "user.email", "test@test.com"}, gitCommand(t, repoPath, "config", "user.name", "Test")
{"git", "config", "user.name", "Test"}, gitCommand(t, repoPath, "commit", "--allow-empty", "-m", "initial")
{"git", "commit", "--allow-empty", "-m", "initial"},
}
for _, c := range cmds {
cmd := exec.Command(c[0], c[1:]...)
cmd.Dir = repoPath
out, err := cmd.CombinedOutput()
require.NoError(t, err, "cmd %v failed: %s", c, string(out))
}
return repoPath return repoPath
} }
func capturePkgStreams(t *testing.T, fn func()) (string, string) {
t.Helper()
oldStdout := os.Stdout
oldStderr := os.Stderr
rOut, wOut, err := os.Pipe()
require.NoError(t, err)
rErr, wErr, err := os.Pipe()
require.NoError(t, err)
os.Stdout = wOut
os.Stderr = wErr
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
}()
fn()
require.NoError(t, wOut.Close())
require.NoError(t, wErr.Close())
var stdout bytes.Buffer
var stderr bytes.Buffer
_, err = io.Copy(&stdout, rOut)
require.NoError(t, err)
_, err = io.Copy(&stderr, rErr)
require.NoError(t, err)
return stdout.String(), stderr.String()
}
func TestCheckRepoSafety_Clean(t *testing.T) { func TestCheckRepoSafety_Clean(t *testing.T) {
tmp := t.TempDir() tmp := t.TempDir()
repoPath := setupTestRepo(t, tmp, "clean-repo") repoPath := setupTestRepo(t, tmp, "clean-repo")
@ -56,26 +85,19 @@ func TestCheckRepoSafety_Stash(t *testing.T) {
tmp := t.TempDir() tmp := t.TempDir()
repoPath := setupTestRepo(t, tmp, "stash-repo") repoPath := setupTestRepo(t, tmp, "stash-repo")
// Create a file, add, stash
require.NoError(t, os.WriteFile(filepath.Join(repoPath, "stash.txt"), []byte("data"), 0644)) require.NoError(t, os.WriteFile(filepath.Join(repoPath, "stash.txt"), []byte("data"), 0644))
cmd := exec.Command("git", "add", ".") gitCommand(t, repoPath, "add", ".")
cmd.Dir = repoPath gitCommand(t, repoPath, "stash")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "stash")
cmd.Dir = repoPath
require.NoError(t, cmd.Run())
blocked, reasons := checkRepoSafety(repoPath) blocked, reasons := checkRepoSafety(repoPath)
assert.True(t, blocked) assert.True(t, blocked)
found := false found := false
for _, r := range reasons { for _, r := range reasons {
if assert.ObjectsAreEqual("stashed", "") || len(r) > 0 { if strings.Contains(r, "stash") {
if contains(r, "stash") {
found = true found = true
} }
} }
}
assert.True(t, found, "expected stash warning in reasons: %v", reasons) assert.True(t, found, "expected stash warning in reasons: %v", reasons)
} }
@ -116,15 +138,37 @@ repos:
assert.Contains(t, string(updated), "core-beta") assert.Contains(t, string(updated), "core-beta")
} }
func contains(s, substr string) bool { func TestRunPkgRemove_Bad_BlockedWarningsGoToStderr(t *testing.T) {
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr)) tmp := t.TempDir()
}
func containsStr(s, substr string) bool { registry := strings.TrimSpace(`
for i := 0; i <= len(s)-len(substr); i++ { org: host-uk
if s[i:i+len(substr)] == substr { base_path: .
return true repos:
} core-alpha:
} type: foundation
return false description: Alpha package
`) + "\n"
require.NoError(t, os.WriteFile(filepath.Join(tmp, "repos.yaml"), []byte(registry), 0644))
repoPath := filepath.Join(tmp, "core-alpha")
require.NoError(t, os.MkdirAll(repoPath, 0755))
gitCommand(t, repoPath, "init")
gitCommand(t, repoPath, "config", "user.email", "test@test.com")
gitCommand(t, repoPath, "config", "user.name", "Test")
commitGitRepo(t, repoPath, "file.txt", "v1\n", "initial")
require.NoError(t, os.WriteFile(filepath.Join(repoPath, "file.txt"), []byte("v2\n"), 0644))
withWorkingDir(t, tmp)
stdout, stderr := capturePkgStreams(t, func() {
err := runPkgRemove("core-alpha", false)
require.Error(t, err)
assert.Contains(t, err.Error(), "unresolved changes")
})
assert.Empty(t, stdout)
assert.Contains(t, stderr, "Cannot remove core-alpha")
assert.Contains(t, stderr, "uncommitted changes")
assert.Contains(t, stderr, "Resolve the issues above or use --force to override.")
} }