edit: keep YAML top-level strings as strings and unescape single quotes (#431)

This commit is contained in:
Charan Rathore authored and GitHub committed 2026-10-01 22:10:26 +08:00
1 parent 99b1b15d98
commit 563dc83eef
2 files changed
+65 -3

No files matched your search

+8 -3
View File
@@ -5,6 +5,8 @@ import (
"regexp"
"strconv"
"strings"
"gopkg.in/yaml.v3"
)
// Top-level YAML keys are edited line by line. That keeps every comment and
@@ -44,7 +46,9 @@ func SetYAMLTop(path string, kvs ...KV) error {
lines := splitLines(string(raw))
for _, kv := range kvs {
v := toString(kv.Value)
if !yamlPlain.MatchString(v) {
var decoded any
_, isString := kv.Value.(string)
if !yamlPlain.MatchString(v) || (isString && (yaml.Unmarshal([]byte(v), &decoded) != nil || decoded != v)) {
v = strconv.Quote(v)
}
lines = setLine(lines, kv.Path, kv.Path+": "+v, nil, func(line string) (string, bool) {
@@ -139,8 +143,9 @@ func tomlValue(v string) string {
}
func yamlValue(v string) string {
if s, ok := unquote(v); ok {
return s
var n yaml.Node
if err := yaml.Unmarshal([]byte(v), &n); err == nil && len(n.Content) > 0 && n.Content[0].Kind == yaml.ScalarNode {
return n.Content[0].Value
}
if i := strings.Index(v, " #"); i >= 0 {
v = strings.TrimSpace(v[:i])
+57
View File
@@ -0,0 +1,57 @@
package edit
import (
"os"
"path/filepath"
"testing"
"gopkg.in/yaml.v3"
)
func TestYAMLTopStringScalars(t *testing.T) {
for _, v := range []string{"null", "true", "123", "a\t\nb"} {
p := filepath.Join(t.TempDir(), "goose.yaml")
if e := SetYAMLTop(p, KV{"GOOSE_MODEL", v}); e != nil {
t.Fatal(e)
}
b, err := os.ReadFile(p)
if err != nil {
t.Fatal(err)
}
var m map[string]any
if e := yaml.Unmarshal(b, &m); e != nil {
t.Fatal(e)
}
if got, ok := m["GOOSE_MODEL"].(string); !ok || got != v {
t.Errorf("value %q serialized %q reads %T %v", v, b, m["GOOSE_MODEL"], m["GOOSE_MODEL"])
}
}
}
func TestYAMLTopSingleQuotedEscape(t *testing.T) {
p := tmpFile(t, "goose.yaml", "GOOSE_MODEL: 'owner''s/model'\n")
v, ok := GetYAMLTop(p, "GOOSE_MODEL")
if !ok {
t.Fatal("model not found")
}
if v != "owner's/model" {
t.Fatalf("got %q", v)
}
}
func TestYAMLTopTypedValues(t *testing.T) {
p := filepath.Join(t.TempDir(), "config.yaml")
if err := SetYAMLTop(p, KV{"enabled", true}, KV{"count", 123}); err != nil {
t.Fatal(err)
}
b, err := os.ReadFile(p)
if err != nil {
t.Fatal(err)
}
var m map[string]any
if err := yaml.Unmarshal(b, &m); err != nil {
t.Fatal(err)
}
if m["enabled"] != true || m["count"] != 123 {
t.Fatalf("types changed: %#v", m)
}
}