Skip to content

Commit 406d79d

Browse files
authored
Merge pull request #2096 from Adirio/config-chain
✨ Enable the storage of multiple plugins as layout
2 parents 911f342 + 668b999 commit 406d79d

File tree

14 files changed

+162
-128
lines changed

14 files changed

+162
-128
lines changed

pkg/cli/cli.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,7 @@ func (c CLI) getInfoFromConfigFile() (config.Version, []string, error) {
220220
// getInfoFromConfig obtains the project version and plugin keys from the project config.
221221
// It is extracted from getInfoFromConfigFile for testing purposes.
222222
func getInfoFromConfig(projectConfig config.Config) (config.Version, []string, error) {
223-
// Split the comma-separated plugins
224-
var pluginSet []string
225-
if projectConfig.GetLayout() != "" {
226-
for _, p := range strings.Split(projectConfig.GetLayout(), ",") {
227-
pluginSet = append(pluginSet, strings.TrimSpace(p))
228-
}
229-
}
230-
231-
return projectConfig.GetVersion(), pluginSet, nil
223+
return projectConfig.GetVersion(), projectConfig.GetPluginChain(), nil
232224
}
233225

234226
// resolveFlagsAndConfigFileConflicts checks if the provided combined input from flags and

pkg/cli/cli_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ var _ = Describe("CLI", func() {
191191
projectVersion config.Version
192192
plugins []string
193193
err error
194+
195+
pluginChain = []string{"go.kubebuilder.io/v2"}
194196
)
195197

196198
When("not having layout field", func() {
@@ -199,18 +201,18 @@ var _ = Describe("CLI", func() {
199201
projectVersion, plugins, err = getInfoFromConfig(projectConfig)
200202
Expect(err).NotTo(HaveOccurred())
201203
Expect(projectVersion.Compare(projectConfig.GetVersion())).To(Equal(0))
202-
Expect(len(plugins)).To(Equal(0))
204+
Expect(plugins).To(Equal(pluginChain))
203205
})
204206
})
205207

206208
When("having layout field", func() {
207209
It("should succeed", func() {
208210
projectConfig = cfgv3.New()
209-
Expect(projectConfig.SetLayout("go.kubebuilder.io/v2")).To(Succeed())
211+
Expect(projectConfig.SetPluginChain(pluginChain)).To(Succeed())
210212
projectVersion, plugins, err = getInfoFromConfig(projectConfig)
211213
Expect(err).NotTo(HaveOccurred())
212214
Expect(projectVersion.Compare(projectConfig.GetVersion())).To(Equal(0))
213-
Expect(plugins).To(Equal([]string{projectConfig.GetLayout()}))
215+
Expect(plugins).To(Equal(pluginChain))
214216
})
215217
})
216218
})

pkg/config/interface.go

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,78 +20,78 @@ import (
2020
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
2121
)
2222

23-
// Config defines the interface that project configuration types must follow
23+
// Config defines the interface that project configuration types must follow.
2424
type Config interface {
2525
/* Version */
2626

27-
// GetVersion returns the current project version
27+
// GetVersion returns the current project version.
2828
GetVersion() Version
2929

3030
/* String fields */
3131

32-
// GetDomain returns the project domain
32+
// GetDomain returns the project domain.
3333
GetDomain() string
34-
// SetDomain sets the project domain
34+
// SetDomain sets the project domain.
3535
SetDomain(domain string) error
3636

3737
// GetRepository returns the project repository.
3838
GetRepository() string
39-
// SetRepository sets the project repository
39+
// SetRepository sets the project repository.
4040
SetRepository(repository string) error
4141

42-
// GetProjectName returns the project name
42+
// GetProjectName returns the project name.
4343
// This method was introduced in project version 3.
4444
GetProjectName() string
45-
// SetProjectName sets the project name
45+
// SetProjectName sets the project name.
4646
// This method was introduced in project version 3.
4747
SetProjectName(name string) error
4848

49-
// GetLayout returns the config layout
49+
// GetPluginChain returns the plugin chain.
5050
// This method was introduced in project version 3.
51-
GetLayout() string
52-
// SetLayout sets the Config layout
51+
GetPluginChain() []string
52+
// SetPluginChain sets the plugin chain.
5353
// This method was introduced in project version 3.
54-
SetLayout(layout string) error
54+
SetPluginChain(pluginChain []string) error
5555

5656
/* Boolean fields */
5757

58-
// IsMultiGroup checks if multi-group is enabled
58+
// IsMultiGroup checks if multi-group is enabled.
5959
IsMultiGroup() bool
60-
// SetMultiGroup enables multi-group
60+
// SetMultiGroup enables multi-group.
6161
SetMultiGroup() error
62-
// ClearMultiGroup disables multi-group
62+
// ClearMultiGroup disables multi-group.
6363
ClearMultiGroup() error
6464

65-
// IsComponentConfig checks if component config is enabled
65+
// IsComponentConfig checks if component config is enabled.
6666
// This method was introduced in project version 3.
6767
IsComponentConfig() bool
68-
// SetComponentConfig enables component config
68+
// SetComponentConfig enables component config.
6969
// This method was introduced in project version 3.
7070
SetComponentConfig() error
71-
// ClearComponentConfig disables component config
71+
// ClearComponentConfig disables component config.
7272
// This method was introduced in project version 3.
7373
ClearComponentConfig() error
7474

7575
/* Resources */
7676

77-
// ResourcesLength returns the number of tracked resources
77+
// ResourcesLength returns the number of tracked resources.
7878
ResourcesLength() int
79-
// HasResource checks if the provided GVK is stored in the Config
79+
// HasResource checks if the provided GVK is stored in the Config.
8080
HasResource(gvk resource.GVK) bool
81-
// GetResource returns the stored resource matching the provided GVK
81+
// GetResource returns the stored resource matching the provided GVK.
8282
GetResource(gvk resource.GVK) (resource.Resource, error)
83-
// GetResources returns all the stored resources
83+
// GetResources returns all the stored resources.
8484
GetResources() ([]resource.Resource, error)
85-
// AddResource adds the provided resource if it was not present, no-op if it was already present
85+
// AddResource adds the provided resource if it was not present, no-op if it was already present.
8686
AddResource(res resource.Resource) error
87-
// UpdateResource adds the provided resource if it was not present, modifies it if it was already present
87+
// UpdateResource adds the provided resource if it was not present, modifies it if it was already present.
8888
UpdateResource(res resource.Resource) error
8989

90-
// HasGroup checks if the provided group is the same as any of the tracked resources
90+
// HasGroup checks if the provided group is the same as any of the tracked resources.
9191
HasGroup(group string) bool
92-
// ListCRDVersions returns a list of the CRD versions in use by the tracked resources
92+
// ListCRDVersions returns a list of the CRD versions in use by the tracked resources.
9393
ListCRDVersions() []string
94-
// ListWebhookVersions returns a list of the webhook versions in use by the tracked resources
94+
// ListWebhookVersions returns a list of the webhook versions in use by the tracked resources.
9595
ListWebhookVersions() []string
9696

9797
/* Plugins */
@@ -105,8 +105,8 @@ type Config interface {
105105

106106
/* Persistence */
107107

108-
// Marshal returns the YAML representation of the Config
109-
Marshal() ([]byte, error)
110-
// Unmarshal loads the Config fields from its YAML representation
111-
Unmarshal([]byte) error
108+
// Marshal returns the YAML representation of the Config.
109+
MarshalYAML() ([]byte, error)
110+
// Unmarshal loads the Config fields from its YAML representation.
111+
UnmarshalYAML([]byte) error
112112
}

pkg/config/store/yaml/store.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (s *yamlStore) LoadFrom(path string) error {
9494
}
9595

9696
// Unmarshal the file content
97-
if err := cfg.Unmarshal(in); err != nil {
97+
if err := cfg.UnmarshalYAML(in); err != nil {
9898
return store.LoadError{Err: fmt.Errorf("unable to unmarshal config at %q: %w", path, err)}
9999
}
100100

@@ -128,7 +128,7 @@ func (s yamlStore) SaveTo(path string) error {
128128
}
129129

130130
// Marshall into YAML
131-
content, err := s.cfg.Marshal()
131+
content, err := s.cfg.MarshalYAML()
132132
if err != nil {
133133
return store.SaveError{Err: fmt.Errorf("unable to marshal to YAML: %w", err)}
134134
}

pkg/config/v2/config.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,16 @@ func (c *cfg) SetProjectName(string) error {
9292
}
9393
}
9494

95-
// GetLayout implements config.Config
96-
func (c cfg) GetLayout() string {
97-
return ""
95+
// GetPluginChain implements config.Config
96+
func (c cfg) GetPluginChain() []string {
97+
return []string{"go.kubebuilder.io/v2"}
9898
}
9999

100-
// SetLayout implements config.Config
101-
func (c *cfg) SetLayout(string) error {
100+
// SetPluginChain implements config.Config
101+
func (c *cfg) SetPluginChain([]string) error {
102102
return config.UnsupportedFieldError{
103103
Version: Version,
104-
Field: "layout",
104+
Field: "plugin chain",
105105
}
106106
}
107107

@@ -247,7 +247,7 @@ func (c cfg) EncodePluginConfig(string, interface{}) error {
247247
}
248248

249249
// Marshal implements config.Config
250-
func (c cfg) Marshal() ([]byte, error) {
250+
func (c cfg) MarshalYAML() ([]byte, error) {
251251
content, err := yaml.Marshal(c)
252252
if err != nil {
253253
return nil, config.MarshalError{Err: err}
@@ -257,7 +257,7 @@ func (c cfg) Marshal() ([]byte, error) {
257257
}
258258

259259
// Unmarshal implements config.Config
260-
func (c *cfg) Unmarshal(b []byte) error {
260+
func (c *cfg) UnmarshalYAML(b []byte) error {
261261
if err := yaml.UnmarshalStrict(b, c); err != nil {
262262
return config.UnmarshalError{Err: err}
263263
}

pkg/config/v2/config_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ var _ = Describe("cfg", func() {
7878
})
7979
})
8080

81-
Context("ProjectName", func() {
81+
Context("Project name", func() {
8282
It("GetProjectName should return an empty name", func() {
8383
Expect(c.GetProjectName()).To(Equal(""))
8484
})
@@ -88,13 +88,13 @@ var _ = Describe("cfg", func() {
8888
})
8989
})
9090

91-
Context("Layout", func() {
92-
It("GetLayout should return an empty layout", func() {
93-
Expect(c.GetLayout()).To(Equal(""))
91+
Context("Plugin chain", func() {
92+
It("GetPluginChain should return the only supported plugin", func() {
93+
Expect(c.GetPluginChain()).To(Equal([]string{"go.kubebuilder.io/v2"}))
9494
})
9595

96-
It("SetLayout should fail to set the layout", func() {
97-
Expect(c.SetLayout("layout")).NotTo(Succeed())
96+
It("SetPluginChain should fail to set the plugin chain", func() {
97+
Expect(c.SetPluginChain([]string{})).NotTo(Succeed())
9898
})
9999
})
100100

@@ -288,28 +288,28 @@ version: "2"
288288
`
289289
)
290290

291-
DescribeTable("Marshal should succeed",
291+
DescribeTable("MarshalYAML should succeed",
292292
func(c cfg, content string) {
293-
b, err := c.Marshal()
293+
b, err := c.MarshalYAML()
294294
Expect(err).NotTo(HaveOccurred())
295295
Expect(string(b)).To(Equal(content))
296296
},
297297
Entry("for a basic configuration", c1, s1),
298298
Entry("for a full configuration", c2, s2),
299299
)
300300

301-
DescribeTable("Marshal should fail",
301+
DescribeTable("MarshalYAML should fail",
302302
func(c cfg) {
303-
_, err := c.Marshal()
303+
_, err := c.MarshalYAML()
304304
Expect(err).To(HaveOccurred())
305305
},
306306
// TODO (coverage): add cases where yaml.Marshal returns an error
307307
)
308308

309-
DescribeTable("Unmarshal should succeed",
309+
DescribeTable("UnmarshalYAML should succeed",
310310
func(content string, c cfg) {
311311
var unmarshalled cfg
312-
Expect(unmarshalled.Unmarshal([]byte(content))).To(Succeed())
312+
Expect(unmarshalled.UnmarshalYAML([]byte(content))).To(Succeed())
313313
Expect(unmarshalled.Version.Compare(c.Version)).To(Equal(0))
314314
Expect(unmarshalled.Domain).To(Equal(c.Domain))
315315
Expect(unmarshalled.Repository).To(Equal(c.Repository))
@@ -320,10 +320,10 @@ version: "2"
320320
Entry("full", s2, c2),
321321
)
322322

323-
DescribeTable("Unmarshal should fail",
323+
DescribeTable("UnmarshalYAML should fail",
324324
func(content string) {
325325
var c cfg
326-
Expect(c.Unmarshal([]byte(content))).NotTo(Succeed())
326+
Expect(c.UnmarshalYAML([]byte(content))).NotTo(Succeed())
327327
},
328328
Entry("for unknown fields", `field: 1
329329
version: "2"`),

pkg/config/v3/config.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,38 @@ import (
2929
// Version is the config.Version for project configuration 3
3030
var Version = config.Version{Number: 3}
3131

32+
// stringSlice is a []string but that can also be unmarshalled from a single string,
33+
// which is introduced as the first and only element of the slice
34+
// It is used to offer backwards compatibility as the field used to be a string.
35+
type stringSlice []string
36+
37+
func (ss *stringSlice) UnmarshalJSON(b []byte) error {
38+
if b[0] == '[' {
39+
var sl []string
40+
if err := yaml.Unmarshal(b, &sl); err != nil {
41+
return err
42+
}
43+
*ss = sl
44+
return nil
45+
}
46+
47+
var st string
48+
if err := yaml.Unmarshal(b, &st); err != nil {
49+
return err
50+
}
51+
*ss = stringSlice{st}
52+
return nil
53+
}
54+
3255
type cfg struct {
3356
// Version
3457
Version config.Version `json:"version"`
3558

3659
// String fields
37-
Domain string `json:"domain,omitempty"`
38-
Repository string `json:"repo,omitempty"`
39-
Name string `json:"projectName,omitempty"`
40-
Layout string `json:"layout,omitempty"`
60+
Domain string `json:"domain,omitempty"`
61+
Repository string `json:"repo,omitempty"`
62+
Name string `json:"projectName,omitempty"`
63+
PluginChain stringSlice `json:"layout,omitempty"`
4164

4265
// Boolean fields
4366
MultiGroup bool `json:"multigroup,omitempty"`
@@ -104,13 +127,13 @@ func (c *cfg) SetProjectName(name string) error {
104127
}
105128

106129
// GetLayout implements config.Config
107-
func (c cfg) GetLayout() string {
108-
return c.Layout
130+
func (c cfg) GetPluginChain() []string {
131+
return c.PluginChain
109132
}
110133

111134
// SetLayout implements config.Config
112-
func (c *cfg) SetLayout(layout string) error {
113-
c.Layout = layout
135+
func (c *cfg) SetPluginChain(pluginChain []string) error {
136+
c.PluginChain = pluginChain
114137
return nil
115138
}
116139

@@ -324,7 +347,7 @@ func (c *cfg) EncodePluginConfig(key string, configObj interface{}) error {
324347
}
325348

326349
// Marshal implements config.Config
327-
func (c cfg) Marshal() ([]byte, error) {
350+
func (c cfg) MarshalYAML() ([]byte, error) {
328351
for i, r := range c.Resources {
329352
// If API is empty, omit it (prevents `api: {}`).
330353
if r.API != nil && r.API.IsEmpty() {
@@ -345,7 +368,7 @@ func (c cfg) Marshal() ([]byte, error) {
345368
}
346369

347370
// Unmarshal implements config.Config
348-
func (c *cfg) Unmarshal(b []byte) error {
371+
func (c *cfg) UnmarshalYAML(b []byte) error {
349372
if err := yaml.UnmarshalStrict(b, c); err != nil {
350373
return config.UnmarshalError{Err: err}
351374
}

0 commit comments

Comments
 (0)