From 22d0c17e824ba2d14a604431b8f4206fd652d093 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 11 Nov 2025 11:27:26 +0100 Subject: [PATCH] docshelper: Fix some YAML serialization issues with sites matrix configuration Fixes #14132 --- commands/gen.go | 2 +- hugolib/roles/roles.go | 2 +- .../sitematrix_integration_test.go | 82 +++++++++++++++++++ hugolib/sitesmatrix/vectorstores.go | 4 +- hugolib/versions/versions.go | 2 +- langs/config.go | 2 +- modules/config.go | 7 +- 7 files changed, 92 insertions(+), 9 deletions(-) diff --git a/commands/gen.go b/commands/gen.go index 5579b7554..a9d2fa7a2 100644 --- a/commands/gen.go +++ b/commands/gen.go @@ -249,7 +249,7 @@ url: %s return err } defer f.Close() - yamlEnc := yaml.NewEncoder(f, yaml.AutoInt()) + yamlEnc := yaml.NewEncoder(f, yaml.UseSingleQuote(true), yaml.AutoInt()) if err := yamlEnc.Encode(m); err != nil { return err } diff --git a/hugolib/roles/roles.go b/hugolib/roles/roles.go index f2cf3d633..6b1b5d3f6 100644 --- a/hugolib/roles/roles.go +++ b/hugolib/roles/roles.go @@ -206,7 +206,7 @@ func DecodeConfig(defaultContentRole string, m map[string]any) (*config.ConfigNa if defaultContentRole, err = roles.init(defaultContentRole); err != nil { return roles, nil, err } - return roles, nil, nil + return roles, roles.roleConfigs, nil }) return v, defaultContentRole, err diff --git a/hugolib/sitesmatrix/sitematrix_integration_test.go b/hugolib/sitesmatrix/sitematrix_integration_test.go index bfe234db0..5ab6ebba3 100644 --- a/hugolib/sitesmatrix/sitematrix_integration_test.go +++ b/hugolib/sitesmatrix/sitematrix_integration_test.go @@ -14,6 +14,7 @@ package sitesmatrix_test import ( + "encoding/json" "fmt" "strings" "testing" @@ -1100,6 +1101,87 @@ title: "P%d" return b } +// See #14132. We recently reworked the config structs for languages, versions, and roles, +// which made them incomplete when generating the docshelper YAML file. +// Add a test here to ensure we don't regress. +func TestUnmarshalSitesMatrixConfig(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +defaultContentLanguage = "en" +defaultContentLanguageInSubDir = true +defaultCOntentVersionInSubDir = true +defaultContentVersion = "v1.0.0" +defaultContentRole = "guest" +defaultContentRoleInSubDir = true + +[moule.mounts] +source = 'content' +target = 'content' + + +[languages] +[languages.en] + +[versions] +[versions."v1.0.0"] + +[roles] +[roles.guest] + +` + + b := hugolib.Test(t, files) + + toJSONAndMap := func(v any) map[string]any { + bb, err := json.Marshal(v) + b.Assert(err, qt.IsNil) + var m map[string]any + err = json.Unmarshal(bb, &m) + b.Assert(err, qt.IsNil) + return m + } + + conf := b.H.Configs.Base + + b.Assert(toJSONAndMap(conf.Languages), qt.DeepEquals, + map[string]any{ + "en": map[string]any{ + "Disabled": bool(false), + "LanguageCode": "", + "LanguageDirection": "", + "LanguageName": "", + "Title": "", + "Weight": float64(0), + }, + }) + + b.Assert(toJSONAndMap(conf.Versions), qt.DeepEquals, map[string]any{ + "v1.0.0": map[string]any{ + "Weight": float64(0), + }, + }) + + b.Assert(toJSONAndMap(conf.Roles), qt.DeepEquals, map[string]any{ + "guest": map[string]any{ + "Weight": float64(0), + }, + }) + + firstMount := conf.Module.Mounts[0] + b.Assert(toJSONAndMap(firstMount.Sites.Matrix), qt.DeepEquals, map[string]any{ + "languages": nil, + "versions": nil, + "roles": nil, + }) + b.Assert(toJSONAndMap(firstMount.Sites.Complements), qt.DeepEquals, map[string]any{ + "languages": nil, + "versions": nil, + "roles": nil, + }) +} + func TestSitesMatrixContentBenchmark(t *testing.T) { const numPages = 3 b := newSitesMatrixContentBenchmarkBuilder(t, numPages, false, true) diff --git a/hugolib/sitesmatrix/vectorstores.go b/hugolib/sitesmatrix/vectorstores.go index 6f3858574..4f51be7a3 100644 --- a/hugolib/sitesmatrix/vectorstores.go +++ b/hugolib/sitesmatrix/vectorstores.go @@ -813,9 +813,9 @@ type IntSetsConfig struct { // Sites holds configuration about which sites a file/content/page/resource belongs to. type Sites struct { // Matrix defines what sites to build this content for. - Matrix StringSlices `mapstructure:"matrix" json:"matrix,omitzero"` + Matrix StringSlices `mapstructure:"matrix" json:"matrix"` // Complements defines what sites to complement with this content. - Complements StringSlices `mapstructure:"complements" json:"complements,omitzero"` + Complements StringSlices `mapstructure:"complements" json:"complements"` } func (s *Sites) Equal(other Sites) bool { diff --git a/hugolib/versions/versions.go b/hugolib/versions/versions.go index 142087da9..a2c743d18 100644 --- a/hugolib/versions/versions.go +++ b/hugolib/versions/versions.go @@ -206,6 +206,6 @@ func DecodeConfig(defaultContentVersion string, m map[string]any) (*config.Confi if err := versions.init(defaultContentVersion); err != nil { return versions, nil, err } - return versions, nil, nil + return versions, versions.versionConfigs, nil }) } diff --git a/langs/config.go b/langs/config.go index db708c3ac..b6bc0ffea 100644 --- a/langs/config.go +++ b/langs/config.go @@ -216,7 +216,7 @@ func DecodeConfig(defaultContentLanguage string, disabledLanguages []string, m m if defaultContentLanguage, err = languages.init(defaultContentLanguage, disabledLanguages); err != nil { return languages, nil, err } - return languages, nil, nil + return languages, languages.LanguageConfigs, nil }) return v, defaultContentLanguage, err diff --git a/modules/config.go b/modules/config.go index a3e8256fe..adc330902 100644 --- a/modules/config.go +++ b/modules/config.go @@ -418,7 +418,8 @@ type Mount struct { Target string // Any file in this mount will be associated with this language. - Lang string + // Deprecated, use Sites instead. + Lang string `json:"-"` // Sites defines which sites this mount applies to. Sites sitesmatrix.Sites @@ -429,11 +430,11 @@ type Mount struct { // Include only files matching the given Glob patterns (string or slice). // Deprecated, use Files instead. - IncludeFiles any + IncludeFiles any `json:"-"` // Exclude all files matching the given Glob patterns (string or slice). // Deprecated, use Files instead. - ExcludeFiles any + ExcludeFiles any `json:"-"` // Disable watching in watch mode for this mount. DisableWatch bool -- 2.39.5