Add relative destinations to import declarations

This commit is contained in:
2026-10-14 17:24:57 +00:00
parent 49c0c6d908
commit 4635ef08d5
5 changed files with 285 additions and 12 deletions

View File

@@ -155,6 +155,122 @@ func TestFacadeImportedSourcesRetainInputDestination(t *testing.T) {
}
}
func TestFacadeRelativeImportDestinationsForRootAndMountedLoads(t *testing.T) {
directory := t.TempDir()
write := func(relative, contents string) string {
t.Helper()
filename := filepath.Join(directory, filepath.FromSlash(relative))
if err := os.MkdirAll(filepath.Dir(filename), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filename, []byte(contents), 0o600); err != nil {
t.Fatal(err)
}
return filename
}
mainPath := write("main.yml", `configkit:
imports:
- path: metadata.yml
destination: [metadata]
- glob: prompts/*.yml
destination: [prompts]
- path: entries/main.yml
destination: [profiles]
- path: sibling.yml
destination: [sibling]
root: main
`)
write("metadata.yml", "name: imported\n")
write("prompts/a.yml", "a: {name: alpha}\n")
write("prompts/b.yml", "b: {name: beta}\n")
write("entries/main.yml", `configkit:
imports:
- path: nested/details.yml
destination: [details]
name: profile
`)
write("entries/nested/details.yml", "summary: nested\n")
write("sibling.yml", "name: separate\n")
root, err := configkit.Load(
configkit.File(mainPath), configkit.Options[map[string]any]{Imports: true},
)
if err != nil {
if loadError, ok := err.(*configkit.LoadError); ok {
t.Fatalf("ordinary root Load: %v, diagnostics %#v", err, loadError.Diagnostics())
}
t.Fatalf("ordinary root Load: %v", err)
}
mountedDestination := configkit.Keys("collections", "weatherreporter")
mounted, err := configkit.LoadLayered[map[string]any](configkit.Input{
Source: configkit.File(mainPath), Imports: true, Destination: mountedDestination,
})
if err != nil {
t.Fatalf("mounted layered Load: %v", err)
}
for _, test := range []struct {
name string
result *configkit.Result[map[string]any]
prefix []string
}{
{name: "ordinary root", result: root},
{name: "mounted entry", result: mounted, prefix: []string{"collections", "weatherreporter"}},
} {
t.Run(test.name, func(t *testing.T) {
at := func(keys ...string) []string {
return append(append([]string(nil), test.prefix...), keys...)
}
if got := facadeDestinationValue(t, test.result.Config, at("root")...); got != "main" {
t.Fatalf("root value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("metadata", "name")...); got != "imported" {
t.Fatalf("metadata value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("prompts", "a", "name")...); got != "alpha" {
t.Fatalf("first glob value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("prompts", "b", "name")...); got != "beta" {
t.Fatalf("second glob value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("profiles", "name")...); got != "profile" {
t.Fatalf("entry value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("profiles", "details", "summary")...); got != "nested" {
t.Fatalf("nested import value = %#v", got)
}
if got := facadeDestinationValue(t, test.result.Config, at("sibling", "name")...); got != "separate" {
t.Fatalf("subsequent sibling value = %#v", got)
}
wantPaths := []string{
"main.yml", "metadata.yml", "a.yml", "b.yml", "main.yml", "details.yml", "sibling.yml",
}
wantDestinations := []configkit.Path{configkit.Keys(test.prefix...)}
for _, suffix := range [][]string{{"metadata"}, {"prompts"}, {"prompts"}, {"profiles"}, {"profiles", "details"}, {"sibling"}} {
destination := append([]string(nil), test.prefix...)
for _, segment := range suffix {
destination = append(destination, segment)
}
wantDestinations = append(wantDestinations, configkit.Keys(destination...))
}
sources := test.result.Sources()
if len(sources) != len(wantPaths) {
t.Fatalf("sources = %#v, want %d", sources, len(wantPaths))
}
for index, source := range sources {
if filepath.Base(source.Path) != wantPaths[index] || source.Destination.String() != wantDestinations[index].String() {
t.Errorf("source %d path/destination = (%q, %q), want base path %q and destination %q", index, source.Path, source.Destination.String(), wantPaths[index], wantDestinations[index].String())
}
if index > 0 && source.ImportedFrom == nil {
t.Errorf("imported source %d has no physical declaration location", index)
}
}
})
}
}
func TestFacadeSameFragmentMountsAtSeparateCollectionDestinations(t *testing.T) {
weatherDestination := configkit.Keys("collections", "weather", "prompts")
homeDestination := configkit.Keys("collections", "homewatch", "prompts")