Skip to content

Commit 75d816f

Browse files
generator: make generated Go types implement runtime.Object (#143)
Add opt-in generation of controller-gen-style DeepCopy methods, runtime.Object and schema.ObjectKind methods on root types, and a per-package groupversion_info.go (GroupVersion/SchemeBuilder/AddToScheme), so generated Go models can be registered in a runtime.Scheme and used with k8s ecosystem libraries. This lets users register types instead of setting apiVersion/kind by hand. Gated behind a new features.generateGoRuntimeObjects config flag (off by default), threaded from config through the project build/run and function generate commands. When enabled, the generated models module additionally depends on k8s.io/apimachinery (v0.33.0, matching the function go template so a generated function that consumes the models still builds). Root types are detected structurally (APIVersion+Kind+Metadata fields). The runtime.Object pass runs after the k8s type-name fixups so it sees final type names, and copies known stdlib-backed alias types (Time, MicroTime, FieldsV1, RawExtension) by value rather than calling DeepCopyInto. Verified by compile gates that build the generated module (CRD and OpenAPI paths) plus a behavioral test asserting deep-copy independence for scalar, slice-of-struct and map fields and AddToScheme GVK round-tripping.
1 parent d0fecff commit 75d816f

13 files changed

Lines changed: 1139 additions & 27 deletions

File tree

cmd/crossplane/config/help/config.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ Enable alpha commands:
1818
```shell
1919
crossplane config set features.enableAlpha true
2020
```
21+
22+
Generate runtime.Object methods and per-package AddToScheme helpers on generated
23+
Go models (off by default), so generated types can be registered in a
24+
runtime.Scheme:
25+
26+
```shell
27+
crossplane config set features.generateGoRuntimeObjects true
28+
```

cmd/crossplane/config/set.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ type boolSetter func(c *config.Config, v bool)
4242
//
4343
//nolint:gochecknoglobals // This is a constant.
4444
var boolKeys = map[string]boolSetter{
45-
"features.enableAlpha": func(c *config.Config, v bool) { c.Features.EnableAlpha = v },
46-
"features.disableBeta": func(c *config.Config, v bool) { c.Features.DisableBeta = v },
45+
"features.enableAlpha": func(c *config.Config, v bool) { c.Features.EnableAlpha = v },
46+
"features.disableBeta": func(c *config.Config, v bool) { c.Features.DisableBeta = v },
47+
"features.generateGoRuntimeObjects": func(c *config.Config, v bool) { c.Features.GenerateGoRuntimeObjects = v },
4748
}
4849

4950
func (c *setCmd) AfterApply() error {

cmd/crossplane/function/generate.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/crossplane/crossplane-runtime/v2/pkg/xpkg"
4040

4141
v1alpha1 "github.com/crossplane/cli/v2/apis/dev/v1alpha1"
42+
"github.com/crossplane/cli/v2/internal/config"
4243
"github.com/crossplane/cli/v2/internal/filesystem"
4344
"github.com/crossplane/cli/v2/internal/kcl"
4445
"github.com/crossplane/cli/v2/internal/project/projectfile"
@@ -144,7 +145,7 @@ func functionSchemaLanguage(functionLang string) string {
144145
}
145146

146147
// Run generates a function scaffold.
147-
func (c *generateCmd) Run(sp terminal.SpinnerPrinter) error {
148+
func (c *generateCmd) Run(sp terminal.SpinnerPrinter, cfg *config.Config) error {
148149
if err := c.validatePaths(); err != nil {
149150
return err
150151
}

cmd/crossplane/function/generate_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
apiextv1 "github.com/crossplane/crossplane/apis/v2/apiextensions/v1"
3131

3232
v1alpha1 "github.com/crossplane/cli/v2/apis/dev/v1alpha1"
33+
"github.com/crossplane/cli/v2/internal/config"
3334
"github.com/crossplane/cli/v2/internal/terminal"
3435
)
3536

@@ -324,7 +325,7 @@ func TestRunErrors(t *testing.T) {
324325
case "afterApply":
325326
err = c.AfterApply()
326327
case "run":
327-
err = c.Run(terminal.NewSpinnerPrinter(io.Discard, false))
328+
err = c.Run(terminal.NewSpinnerPrinter(io.Discard, false), &config.Config{})
328329
}
329330
if err == nil {
330331
t.Fatalf("expected error containing %q, got nil", tc.wantErrSubstring)

cmd/crossplane/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ func main() {
126126
// at runtime.
127127
kong.BindTo(logger, (*logging.Logger)(nil)),
128128
kong.BindTo(configcmd.ConfigPath(cfgPath), (*configcmd.ConfigPath)(nil)),
129+
// Bind the loaded config so commands can read feature flags at runtime.
130+
kong.Bind(cfg),
129131
kong.Help(helpPrinter),
130132
kong.UsageOnError())
131133

cmd/crossplane/project/build.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131

3232
devv1alpha1 "github.com/crossplane/cli/v2/apis/dev/v1alpha1"
3333
"github.com/crossplane/cli/v2/internal/async"
34+
"github.com/crossplane/cli/v2/internal/config"
3435
"github.com/crossplane/cli/v2/internal/dependency"
3536
"github.com/crossplane/cli/v2/internal/project"
3637
"github.com/crossplane/cli/v2/internal/project/functions"
@@ -83,7 +84,7 @@ func (c *buildCmd) AfterApply() error {
8384
}
8485

8586
// Run executes the build command.
86-
func (c *buildCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter) error {
87+
func (c *buildCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *config.Config) error {
8788
ctx := context.Background()
8889

8990
if c.Repository != "" {
@@ -97,7 +98,7 @@ func (c *buildCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter) error
9798
concurrency := max(1, c.MaxConcurrency)
9899

99100
schemasFS := afero.NewBasePathFs(c.projFS, c.proj.Spec.Paths.Schemas)
100-
generators := generator.Filter(generator.AllLanguages(), c.proj.Spec.Schemas.GetLanguages())
101+
generators := generator.Filter(generator.AllLanguages(generator.WithGoRuntimeObjects(cfg.Features.GenerateGoRuntimeObjects)), c.proj.Spec.Schemas.GetLanguages())
101102
schemaRunner := runner.NewRealSchemaRunner(runner.WithImageConfig(c.proj.Spec.ImageConfigs))
102103
schemaMgr := manager.New(schemasFS, generators, schemaRunner)
103104
cacheDir := c.CacheDir

cmd/crossplane/project/run.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
devv1alpha1 "github.com/crossplane/cli/v2/apis/dev/v1alpha1"
4343
"github.com/crossplane/cli/v2/cmd/crossplane/render"
4444
"github.com/crossplane/cli/v2/internal/async"
45+
"github.com/crossplane/cli/v2/internal/config"
4546
"github.com/crossplane/cli/v2/internal/dependency"
4647
"github.com/crossplane/cli/v2/internal/project"
4748
"github.com/crossplane/cli/v2/internal/project/controlplane"
@@ -132,7 +133,7 @@ func (c *runCmd) AfterApply() error {
132133
}
133134

134135
// Run executes the run command.
135-
func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter) error { //nolint:gocyclo // Main command orchestration.
136+
func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *config.Config) error { //nolint:gocyclo // Main command orchestration.
136137
ctx := context.Background()
137138

138139
if c.Repository != "" {
@@ -150,7 +151,7 @@ func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter) error {
150151
concurrency := max(1, c.MaxConcurrency)
151152

152153
schemasFS := afero.NewBasePathFs(c.projFS, c.proj.Spec.Paths.Schemas)
153-
generators := generator.Filter(generator.AllLanguages(), c.proj.Spec.Schemas.GetLanguages())
154+
generators := generator.Filter(generator.AllLanguages(generator.WithGoRuntimeObjects(cfg.Features.GenerateGoRuntimeObjects)), c.proj.Spec.Schemas.GetLanguages())
154155
schemaRunner := runner.NewRealSchemaRunner(runner.WithImageConfig(c.proj.Spec.ImageConfigs))
155156
schemaMgr := manager.New(schemasFS, generators, schemaRunner)
156157
cacheDir := c.CacheDir

internal/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ type Config struct {
4242
type Features struct {
4343
EnableAlpha bool `json:"enableAlpha,omitempty"`
4444
DisableBeta bool `json:"disableBeta,omitempty"`
45+
46+
// GenerateGoRuntimeObjects enables generation of runtime.Object methods and
47+
// per-package AddToScheme helpers on generated Go models. Disabled by
48+
// default; opt in to register generated types with a runtime.Scheme.
49+
GenerateGoRuntimeObjects bool `json:"generateGoRuntimeObjects,omitempty"`
4550
}
4651

4752
// Load reads a Config from path. A missing file is not an error; the zero

0 commit comments

Comments
 (0)