fix(pkgcmd): remove packages from registry
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
207a38e236
commit
1242723ac1
2 changed files with 107 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ import (
|
||||||
coreio "forge.lthn.ai/core/go-io"
|
coreio "forge.lthn.ai/core/go-io"
|
||||||
"forge.lthn.ai/core/go-scm/repos"
|
"forge.lthn.ai/core/go-scm/repos"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var removeForce bool
|
var removeForce bool
|
||||||
|
|
@ -87,10 +88,78 @@ func runPkgRemove(name string, force bool) error {
|
||||||
return err
|
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"))
|
fmt.Printf("%s\n", successStyle.Render("ok"))
|
||||||
return nil
|
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.
|
// checkRepoSafety checks a git repo for uncommitted changes and unpushed branches.
|
||||||
func checkRepoSafety(repoPath string) (blocked bool, reasons []string) {
|
func checkRepoSafety(repoPath string) (blocked bool, reasons []string) {
|
||||||
// Check for uncommitted changes (staged, unstaged, untracked)
|
// Check for uncommitted changes (staged, unstaged, untracked)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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)
|
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 {
|
func contains(s, substr string) bool {
|
||||||
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr))
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue