[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/cli/RFC.md fully. Find features des... #72
2 changed files with 107 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ import (
|
|||
coreio "forge.lthn.ai/core/go-io"
|
||||
"forge.lthn.ai/core/go-scm/repos"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var removeForce bool
|
||||
|
|
@ -87,10 +88,78 @@ func runPkgRemove(name string, force bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := removeRepoFromRegistry(regPath, name); err != nil {
|
||||
return fmt.Errorf("removed %s from disk, but failed to update registry: %w", name, err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", successStyle.Render("ok"))
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeRepoFromRegistry(regPath, name string) error {
|
||||
content, err := coreio.Local.Read(regPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var doc yaml.Node
|
||||
if err := yaml.Unmarshal([]byte(content), &doc); err != nil {
|
||||
return fmt.Errorf("failed to parse registry file: %w", err)
|
||||
}
|
||||
if len(doc.Content) == 0 {
|
||||
return errors.New("registry file is empty")
|
||||
}
|
||||
|
||||
root := doc.Content[0]
|
||||
reposNode := mappingValue(root, "repos")
|
||||
if reposNode == nil {
|
||||
return errors.New("registry file has no repos section")
|
||||
}
|
||||
if reposNode.Kind != yaml.MappingNode {
|
||||
return errors.New("registry repos section is malformed")
|
||||
}
|
||||
|
||||
if removeMappingEntry(reposNode, name) {
|
||||
out, err := yaml.Marshal(&doc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to format registry file: %w", err)
|
||||
}
|
||||
return coreio.Local.Write(regPath, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mappingValue(node *yaml.Node, key string) *yaml.Node {
|
||||
if node == nil || node.Kind != yaml.MappingNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i+1 < len(node.Content); i += 2 {
|
||||
if node.Content[i].Value == key {
|
||||
return node.Content[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeMappingEntry(node *yaml.Node, key string) bool {
|
||||
if node == nil || node.Kind != yaml.MappingNode {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i+1 < len(node.Content); i += 2 {
|
||||
if node.Content[i].Value != key {
|
||||
continue
|
||||
}
|
||||
node.Content = append(node.Content[:i], node.Content[i+2:]...)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// checkRepoSafety checks a git repo for uncommitted changes and unpushed branches.
|
||||
func checkRepoSafety(repoPath string) (blocked bool, reasons []string) {
|
||||
// Check for uncommitted changes (staged, unstaged, untracked)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -78,6 +79,43 @@ func TestCheckRepoSafety_Stash(t *testing.T) {
|
|||
assert.True(t, found, "expected stash warning in reasons: %v", reasons)
|
||||
}
|
||||
|
||||
func TestRunPkgRemove_RemovesRegistryEntry_Good(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
repoPath := setupTestRepo(t, tmp, "core-alpha")
|
||||
|
||||
registry := strings.TrimSpace(`
|
||||
version: 1
|
||||
org: host-uk
|
||||
base_path: .
|
||||
repos:
|
||||
core-alpha:
|
||||
type: foundation
|
||||
description: Alpha package
|
||||
core-beta:
|
||||
type: module
|
||||
description: Beta package
|
||||
`) + "\n"
|
||||
|
||||
require.NoError(t, os.WriteFile(filepath.Join(tmp, "repos.yaml"), []byte(registry), 0644))
|
||||
|
||||
oldwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, os.Chdir(tmp))
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, os.Chdir(oldwd))
|
||||
})
|
||||
|
||||
require.NoError(t, runPkgRemove("core-alpha", false))
|
||||
|
||||
_, err = os.Stat(repoPath)
|
||||
assert.True(t, os.IsNotExist(err))
|
||||
|
||||
updated, err := os.ReadFile(filepath.Join(tmp, "repos.yaml"))
|
||||
require.NoError(t, err)
|
||||
assert.NotContains(t, string(updated), "core-alpha")
|
||||
assert.Contains(t, string(updated), "core-beta")
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue