Skip to content

Commit ee34c52

Browse files
Copilotcamilamacedo86
authored andcommitted
(fix): Fix plugin configuration tracking when wrapped in bundles with custom domains
Assisted-by: Cursor
1 parent c580bca commit ee34c52

File tree

22 files changed

+690
-81
lines changed

22 files changed

+690
-81
lines changed

pkg/cli/alpha/internal/generate.go

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,41 @@ func kubebuilderCreate(s store.Store) error {
240240
// Migrates the Grafana plugin.
241241
func migrateGrafanaPlugin(s store.Store, src, des string) error {
242242
var grafanaPlugin struct{}
243-
err := s.Config().DecodePluginConfig(plugin.KeyFor(grafanav1alpha.Plugin{}), grafanaPlugin)
244-
if errors.As(err, &config.PluginKeyNotFoundError{}) {
243+
key := plugin.GetPluginKeyForConfig(s.Config().GetPluginChain(), grafanav1alpha.Plugin{})
244+
canonicalKey := plugin.KeyFor(grafanav1alpha.Plugin{})
245+
found := true
246+
var err error
247+
248+
if err = s.Config().DecodePluginConfig(key, grafanaPlugin); err != nil {
249+
switch {
250+
case errors.As(err, &config.PluginKeyNotFoundError{}):
251+
found = false
252+
if key != canonicalKey {
253+
if err = s.Config().DecodePluginConfig(canonicalKey, grafanaPlugin); err != nil {
254+
switch {
255+
case errors.As(err, &config.PluginKeyNotFoundError{}):
256+
// still not found
257+
case errors.As(err, &config.UnsupportedFieldError{}):
258+
slog.Info("Project config version does not support plugin metadata, skipping Grafana migration")
259+
return nil
260+
default:
261+
return fmt.Errorf("failed to decode grafana plugin config: %w", err)
262+
}
263+
} else {
264+
found = true
265+
}
266+
}
267+
case errors.As(err, &config.UnsupportedFieldError{}):
268+
slog.Info("Project config version does not support plugin metadata, skipping Grafana migration")
269+
return nil
270+
default:
271+
return fmt.Errorf("failed to decode grafana plugin config: %w", err)
272+
}
273+
}
274+
275+
if !found {
245276
slog.Info("Grafana plugin not found, skipping migration")
246277
return nil
247-
} else if err != nil {
248-
return fmt.Errorf("failed to decode grafana plugin config: %w", err)
249278
}
250279

251280
if err = kubebuilderGrafanaEdit(); err != nil {
@@ -261,30 +290,89 @@ func migrateGrafanaPlugin(s store.Store, src, des string) error {
261290

262291
func migrateAutoUpdatePlugin(s store.Store) error {
263292
var autoUpdatePlugin struct{}
264-
err := s.Config().DecodePluginConfig(plugin.KeyFor(autoupdatev1alpha.Plugin{}), autoUpdatePlugin)
265-
if errors.As(err, &config.PluginKeyNotFoundError{}) {
293+
key := plugin.GetPluginKeyForConfig(s.Config().GetPluginChain(), autoupdatev1alpha.Plugin{})
294+
canonicalKey := plugin.KeyFor(autoupdatev1alpha.Plugin{})
295+
found := true
296+
var err error
297+
298+
if err = s.Config().DecodePluginConfig(key, autoUpdatePlugin); err != nil {
299+
switch {
300+
case errors.As(err, &config.PluginKeyNotFoundError{}):
301+
found = false
302+
if key != canonicalKey {
303+
if err = s.Config().DecodePluginConfig(canonicalKey, autoUpdatePlugin); err != nil {
304+
switch {
305+
case errors.As(err, &config.PluginKeyNotFoundError{}):
306+
// still not found
307+
case errors.As(err, &config.UnsupportedFieldError{}):
308+
slog.Info("Project config version does not support plugin metadata, skipping Auto Update migration")
309+
return nil
310+
default:
311+
return fmt.Errorf("failed to decode autoupdate plugin config: %w", err)
312+
}
313+
} else {
314+
found = true
315+
}
316+
}
317+
case errors.As(err, &config.UnsupportedFieldError{}):
318+
slog.Info("Project config version does not support plugin metadata, skipping Auto Update migration")
319+
return nil
320+
default:
321+
return fmt.Errorf("failed to decode autoupdate plugin config: %w", err)
322+
}
323+
}
324+
325+
if !found {
266326
slog.Info("Auto Update plugin not found, skipping migration")
267327
return nil
268-
} else if err != nil {
269-
return fmt.Errorf("failed to decode autoupdate plugin config: %w", err)
270328
}
271329

272330
args := []string{"edit", "--plugins", plugin.KeyFor(autoupdatev1alpha.Plugin{})}
273-
if err := util.RunCmd("kubebuilder edit", "kubebuilder", args...); err != nil {
331+
if err = util.RunCmd("kubebuilder edit", "kubebuilder", args...); err != nil {
274332
return fmt.Errorf("failed to run edit subcommand for Auto plugin: %w", err)
275333
}
276334
return nil
277335
}
278336

279337
// Migrates the Deploy Image plugin.
280338
func migrateDeployImagePlugin(s store.Store) error {
339+
key := plugin.GetPluginKeyForConfig(s.Config().GetPluginChain(), deployimagev1alpha1.Plugin{})
340+
canonicalKey := plugin.KeyFor(deployimagev1alpha1.Plugin{})
281341
var deployImagePlugin deployimagev1alpha1.PluginConfig
282-
err := s.Config().DecodePluginConfig(plugin.KeyFor(deployimagev1alpha1.Plugin{}), &deployImagePlugin)
283-
if errors.As(err, &config.PluginKeyNotFoundError{}) {
342+
found := true
343+
344+
var err error
345+
err = s.Config().DecodePluginConfig(key, &deployImagePlugin)
346+
if err != nil {
347+
switch {
348+
case errors.As(err, &config.PluginKeyNotFoundError{}):
349+
found = false
350+
if key != canonicalKey {
351+
if err = s.Config().DecodePluginConfig(canonicalKey, &deployImagePlugin); err != nil {
352+
switch {
353+
case errors.As(err, &config.PluginKeyNotFoundError{}):
354+
// still not found
355+
case errors.As(err, &config.UnsupportedFieldError{}):
356+
slog.Info("Project config version does not support plugin metadata, skipping Deploy Image migration")
357+
return nil
358+
default:
359+
return fmt.Errorf("failed to decode deploy-image plugin config: %w", err)
360+
}
361+
} else {
362+
found = true
363+
}
364+
}
365+
case errors.As(err, &config.UnsupportedFieldError{}):
366+
slog.Info("Project config version does not support plugin metadata, skipping Deploy Image migration")
367+
return nil
368+
default:
369+
return fmt.Errorf("failed to decode deploy-image plugin config: %w", err)
370+
}
371+
}
372+
373+
if !found {
284374
slog.Info("Deploy-image plugin not found, skipping migration")
285375
return nil
286-
} else if err != nil {
287-
return fmt.Errorf("failed to decode deploy-image plugin config: %w", err)
288376
}
289377

290378
for _, r := range deployImagePlugin.Resources {

pkg/cli/cli_test.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"sigs.k8s.io/kubebuilder/v4/pkg/config"
3131
cfgv3 "sigs.k8s.io/kubebuilder/v4/pkg/config/v3"
3232
"sigs.k8s.io/kubebuilder/v4/pkg/machinery"
33+
"sigs.k8s.io/kubebuilder/v4/pkg/model/resource"
3334
"sigs.k8s.io/kubebuilder/v4/pkg/model/stage"
3435
"sigs.k8s.io/kubebuilder/v4/pkg/plugin"
3536
golangv4 "sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4"
@@ -77,6 +78,56 @@ func hasSubCommand(cmd *cobra.Command, name string) bool {
7778
return false
7879
}
7980

81+
type testCreateAPIPlugin struct {
82+
name string
83+
version plugin.Version
84+
subcommand *testCreateAPISubcommand
85+
projectVers []config.Version
86+
}
87+
88+
func newTestCreateAPIPlugin(name string, version plugin.Version) testCreateAPIPlugin {
89+
return testCreateAPIPlugin{
90+
name: name,
91+
version: version,
92+
subcommand: &testCreateAPISubcommand{},
93+
projectVers: []config.Version{{Number: 3}},
94+
}
95+
}
96+
97+
func (p testCreateAPIPlugin) Name() string { return p.name }
98+
func (p testCreateAPIPlugin) Version() plugin.Version { return p.version }
99+
func (p testCreateAPIPlugin) SupportedProjectVersions() []config.Version { return p.projectVers }
100+
func (p testCreateAPIPlugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand {
101+
return p.subcommand
102+
}
103+
104+
type testCreateAPISubcommand struct{}
105+
106+
func (s *testCreateAPISubcommand) InjectResource(*resource.Resource) error {
107+
return nil
108+
}
109+
110+
func (s *testCreateAPISubcommand) Scaffold(machinery.Filesystem) error {
111+
return nil
112+
}
113+
114+
type fakeStore struct {
115+
cfg config.Config
116+
}
117+
118+
func (f *fakeStore) New(config.Version) error { return nil }
119+
func (f *fakeStore) Load() error { return nil }
120+
func (f *fakeStore) LoadFrom(string) error { return nil }
121+
func (f *fakeStore) Save() error { return nil }
122+
func (f *fakeStore) SaveTo(string) error { return nil }
123+
func (f *fakeStore) Config() config.Config { return f.cfg }
124+
125+
type captureSubcommand struct {
126+
lastChain []string
127+
}
128+
129+
func (c *captureSubcommand) Scaffold(machinery.Filesystem) error { return nil }
130+
80131
var _ = Describe("CLI", func() {
81132
var (
82133
c *CLI
@@ -91,6 +142,83 @@ var _ = Describe("CLI", func() {
91142
projectVersion = config.Version{Number: 3}
92143
})
93144

145+
Describe("filterSubcommands", func() {
146+
It("propagates bundle keys to wrapped subcommands", func() {
147+
bundleVersion := plugin.Version{Number: 1, Stage: stage.Alpha}
148+
149+
fooPlugin := newTestCreateAPIPlugin("deploy-image.go.kubebuilder.io", plugin.Version{Number: 1, Stage: stage.Alpha})
150+
barPlugin := newTestCreateAPIPlugin("deploy-image.go.kubebuilder.io", plugin.Version{Number: 1, Stage: stage.Alpha})
151+
152+
fooBundle, err := plugin.NewBundleWithOptions(
153+
plugin.WithName("deploy-image.foo.example.com"),
154+
plugin.WithVersion(bundleVersion),
155+
plugin.WithPlugins(fooPlugin),
156+
)
157+
Expect(err).NotTo(HaveOccurred())
158+
159+
barBundle, err := plugin.NewBundleWithOptions(
160+
plugin.WithName("deploy-image.bar.example.com"),
161+
plugin.WithVersion(bundleVersion),
162+
plugin.WithPlugins(barPlugin),
163+
)
164+
Expect(err).NotTo(HaveOccurred())
165+
166+
c.resolvedPlugins = []plugin.Plugin{fooBundle, barBundle}
167+
168+
tuples := c.filterSubcommands(
169+
func(p plugin.Plugin) bool {
170+
_, isCreateAPI := p.(plugin.CreateAPI)
171+
return isCreateAPI
172+
},
173+
func(p plugin.Plugin) plugin.Subcommand {
174+
return p.(plugin.CreateAPI).GetCreateAPISubcommand()
175+
},
176+
)
177+
178+
Expect(tuples).To(HaveLen(2))
179+
Expect(tuples[0].key).To(Equal("deploy-image.go.kubebuilder.io/v1-alpha"))
180+
Expect(tuples[0].configKey).To(Equal("deploy-image.foo.example.com/v1-alpha"))
181+
Expect(tuples[1].key).To(Equal("deploy-image.go.kubebuilder.io/v1-alpha"))
182+
Expect(tuples[1].configKey).To(Equal("deploy-image.bar.example.com/v1-alpha"))
183+
})
184+
})
185+
186+
Describe("executionHooksFactory", func() {
187+
It("temporarily reorders the plugin chain while invoking bundled subcommands", func() {
188+
cfg := cfgv3.New()
189+
Expect(cfg.SetPluginChain([]string{
190+
"deploy-image.foo.example.com/v1-alpha",
191+
"deploy-image.bar.example.com/v1-alpha",
192+
})).To(Succeed())
193+
194+
store := &fakeStore{cfg: cfg}
195+
first := &captureSubcommand{}
196+
second := &captureSubcommand{}
197+
198+
factory := executionHooksFactory{
199+
store: store,
200+
subcommands: []keySubcommandTuple{
201+
{configKey: "deploy-image.foo.example.com/v1-alpha", subcommand: first},
202+
{configKey: "deploy-image.bar.example.com/v1-alpha", subcommand: second},
203+
},
204+
errorMessage: "test",
205+
}
206+
207+
callErr := factory.forEach(func(sub plugin.Subcommand) error {
208+
cs := sub.(*captureSubcommand)
209+
cs.lastChain = append([]string(nil), store.Config().GetPluginChain()...)
210+
return nil
211+
}, "scaffold")
212+
Expect(callErr).NotTo(HaveOccurred())
213+
Expect(first.lastChain[0]).To(Equal("deploy-image.foo.example.com/v1-alpha"))
214+
Expect(second.lastChain[0]).To(Equal("deploy-image.bar.example.com/v1-alpha"))
215+
Expect(store.Config().GetPluginChain()).To(Equal([]string{
216+
"deploy-image.foo.example.com/v1-alpha",
217+
"deploy-image.bar.example.com/v1-alpha",
218+
}))
219+
})
220+
})
221+
94222
Context("buildCmd", func() {
95223
var projectFile string
96224

0 commit comments

Comments
 (0)