Skip to content

Make generated Go models satisfy client.Object/client.ObjectList - #388

Open
erikmiller-gusto wants to merge 1 commit into
crossplane:mainfrom
erikmiller-gusto:erik.miller--client-object-pr
Open

erikmiller-gusto wants to merge 1 commit into
crossplane:mainfrom
erikmiller-gusto:erik.miller--client-object-pr

Conversation

@erikmiller-gusto

@erikmiller-gusto erikmiller-gusto commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Description of your changes

features.generateGoRuntimeObjects (off by default) makes generated root types implement runtime.Object, but that's not enough to use them with sigs.k8s.io/controller-runtime's client.Client. client.Object also requires metav1.Object, whose method signatures are fixed by apimachinery (types.UID, metav1.Time, []metav1.OwnerReference, ...). The locally-generated ObjectMeta mirror type can't satisfy those signatures no matter what methods get added to the root type.

This PR:

  • Redirects io.k8s.apimachinery.pkg.apis.meta.v1 to the real k8s.io/apimachinery/pkg/apis/meta/v1 package when the flag is on, instead of generating a local mirror. Metadata's Go type becomes the real ObjectMeta/ListMeta.
  • Generates metav1.Object methods on root types and metav1.ListInterface methods on <Kind>List types, delegating to the real Metadata field.
  • Fixes <Kind>List.Items, generated as *[]Kind (pointer-to-slice). k8s.io/apimachinery/pkg/api/meta's GetItemsPtr, used by client.List, the fake client, and the informer cache, requires a literal slice.
  • Registers metav1.AddToGroupVersion so client.List with query options and client.Watch work.
  • Fixes collectStructTypes, which didn't resolve type A = B aliases back to the underlying struct. A <Kind>List's Items element is always a qualified-name alias for the root type (type CoAcmePlatformV1Alpha1Foo = Foo), so it was treated as a scalar and DeepCopy fell back to a shallow copy that shared item pointers with the original.
  • Updates the generated module's go.mod/go.sum. The real k8s.io/apimachinery/pkg/apis/meta/v1 package pulls in transitive dependencies (golang.org/x/net, golang.org/x/text, gopkg.in/inf.v0, k8s.io/utils, sigs.k8s.io/randfill) nothing previously imported, captured from a real go mod tidy run.

Breaking change to generateGoRuntimeObjects's output, documented in cmd/crossplane/config/help/config.md. The flag is off by default and wasn't usable as a client.Object before this, so there's no migration path beyond regenerating models.

Tested with:

  • Unit tests in internal/schemas/generator/runtimeobject_test.go covering the metav1.Object/ListInterface method split, the Items fix, and the alias-resolution fix.
  • A compile-gate test (-tags compilegate) that builds a separate consumer module requiring sigs.k8s.io/controller-runtime via a replace directive at the materialized models directory, so controller-runtime never touches the generated module's own go.mod. It exercises a real fake client (Create/Get/List), a DeepCopy independence check against the real generated XAccountScaffoldList type, and a runtime.NewParameterCodec round-trip proving the AddToGroupVersion registration.

Opened as a draft for early feedback before marking ready for review.

I have:

features.generateGoRuntimeObjects currently only makes generated root
types implement runtime.Object, which isn't enough for
sigs.k8s.io/controller-runtime's client.Client. client.Object also
requires metav1.Object, whose method signatures are fixed by
apimachinery (types.UID, metav1.Time, []metav1.OwnerReference, ...) -
signatures the locally-generated ObjectMeta mirror type can't satisfy.

This redirects io.k8s.apimachinery.pkg.apis.meta.v1 to the real
k8s.io/apimachinery/pkg/apis/meta/v1 package when the flag is on,
instead of generating a local mirror, and generates metav1.Object
methods on root types and metav1.ListInterface methods on <Kind>List
types delegating to the real Metadata field. It also fixes two
pre-existing bugs surfaced along the way:

- <Kind>List.Items was generated as *[]Kind (pointer-to-slice).
  k8s.io/apimachinery/pkg/api/meta's GetItemsPtr, used internally by
  client.List, the fake client, and the informer cache, requires a
  literal slice.
- collectStructTypes didn't resolve `type A = B` aliases back to the
  underlying struct, so a List's Items element (always a qualified-name
  alias for the root type) was treated as a scalar and DeepCopy fell
  back to a shallow copy that shared item pointers with the original.

Also registers metav1.AddToGroupVersion so client.List with query
options and client.Watch work, and updates the generated module's
go.mod/go.sum for the transitive dependencies the real apimachinery
meta/v1 package needs.

Breaking change to generateGoRuntimeObjects's output, documented in
cmd/crossplane/config/help/config.md. The flag is off by default and
wasn't usable as a client.Object before this, so there's no migration
path beyond regenerating models.

Signed-off-by: Erik Miller <erik.miller@gusto.com>
@erikmiller-gusto
erikmiller-gusto force-pushed the erik.miller--client-object-pr branch from 91eefee to 383fbf7 Compare September 25, 2026 15:21
@erikmiller-gusto
erikmiller-gusto marked this pull request as ready for review September 25, 2026 16:10
@erikmiller-gusto
erikmiller-gusto requested review from haarchri and removed request for a team September 25, 2026 16:10
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 47 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: crossplane/cli/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 35c85ad1-9330-4da5-9bdd-b6c2bf376d30

📥 Commits

Reviewing files that changed from the base of the PR and between 3e5d853 and 383fbf7.

📒 Files selected for processing (9)
  • cmd/crossplane/config/help/config.md
  • internal/config/config.go
  • internal/schemas/generator/go.go
  • internal/schemas/generator/go_test.go
  • internal/schemas/generator/interface.go
  • internal/schemas/generator/runtimeobject.go
  • internal/schemas/generator/runtimeobject_compilegate_test.go
  • internal/schemas/generator/runtimeobject_integration_test.go
  • internal/schemas/generator/runtimeobject_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant