Skip to content

feat(xr): Convert a Claim to XR via crossplane xr generate#13

Open
tampakrap wants to merge 1 commit into
crossplane:mainfrom
tampakrap:theo/feat_claimtoxr_v2
Open

feat(xr): Convert a Claim to XR via crossplane xr generate#13
tampakrap wants to merge 1 commit into
crossplane:mainfrom
tampakrap:theo/feat_claimtoxr_v2

Conversation

@tampakrap
Copy link
Copy Markdown
Collaborator

@tampakrap tampakrap commented May 12, 2026

Description of your changes

Introduce a Claim to XR converter: crossplane xr generate claim.yaml. Similarly to other converter functions/tools, it takes a Claim either on stdin or as file argument and generates an equivalent XR YAML.

The parent crossplane xr is marked as maturity "alpha", which applies to the subtree as well.

This new tool can be used together with the render command as shown in the example below:

crossplane render <(crossplane xr generate claim.yaml) composition.yaml functions.yaml

The library function ConvertClaimToXR can be used by downstream tools (eg crossplane-diff) that rely on Claim to XR conversion.

The tool (and as a result the converter function, via the Options struct) is configurable and provides the following flags:

  • --direct: omit spec.claimRef and the equivalent labels.
  • --name: specify an explicit XR name, skipping either the random suffix in the non-direct mode or the Claim name fallback in direct mode.
  • --kind: override the derived "X" default.
  • --gen-uid: populate metadata.uid with a fresh random UUID.

I didn't create new docs issue/PR, we can use crossplane/docs#1088

I have:

Need help with this checklist? See the cheat sheet.

@tampakrap tampakrap requested review from adamwg and haarchri May 12, 2026 14:33
@tampakrap tampakrap requested review from a team and jcogilvie as code owners May 12, 2026 14:33
@tampakrap tampakrap requested review from jbw976 and removed request for a team May 12, 2026 14:33
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Review Change Stack

Warning

Review limit reached

@tampakrap, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 minute and 51 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d15f248a-4e75-480e-aca9-f12bf7212dbe

📥 Commits

Reviewing files that changed from the base of the PR and between d6f07ac and 0faee7c.

📒 Files selected for processing (5)
  • cmd/crossplane/main.go
  • cmd/crossplane/xr/generate.go
  • cmd/crossplane/xr/generate_test.go
  • cmd/crossplane/xr/help/generate.md
  • cmd/crossplane/xr/xr.go
📝 Walkthrough

Walkthrough

This PR adds a new crossplane xr generate CLI command that converts Crossplane Claims into Composite Resources (XRs), including CLI wiring, a conversion function with validation/name/kind/label/annotation handling and optional UID generation, plus comprehensive unit tests.

Changes

XR Generate Command

Layer / File(s) Summary
XR Command Structure and CLI Registration
cmd/crossplane/xr/xr.go, cmd/crossplane/main.go
The xr package is created with a public Cmd struct that registers a Generate subcommand, then wired into the main CLI as a top-level XR command with maturity:"alpha".
Generate Implementation and Conversion Logic
cmd/crossplane/xr/generate.go
The generateCmd CLI command reads Claim YAML (from file or stdin), converts it to an XR via ConvertClaimToXR, and writes the result as YAML to an output file or stdout. ConvertClaimToXR validates the input Claim, parses apiVersion, derives XR kind from the Claim kind (or override via options), computes metadata name with optional suffix/UID generation, applies label/annotation semantics for direct vs linked modes, copies the Claim spec, and optionally sets a fresh metadata.uid.
Generate Tests and Helpers
cmd/crossplane/xr/generate_test.go
Comprehensive table-driven test suite with helper builders for Claim fixtures, test case modifiers (labels, annotations, complex specs), and expected XR generation logic. Tests cover error paths (nil/empty/missing fields), name derivation with/without direct mode, label/annotation merging, spec field type preservation, kind/name overrides, and UID generation semantics.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • jcogilvie
  • haarchri

Thanks for this contribution — would you like me to flag any specific areas to focus on during review (naming, label handling, or UID behavior)?

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main feature being added: a new Claim-to-XR converter command within the xr package, meeting the requirement to be descriptive.
Description check ✅ Passed The description is directly related to the changeset, providing detailed context about the new crossplane xr generate command, its functionality, configuration flags, and usage examples.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Breaking Changes ✅ Passed PR adds new public APIs (Options struct, ConvertClaimToXR function, Cmd struct) and CLI flags without removing, renaming, or changing any existing public fields/flags in cmd/ or apis/.
Feature Gate Requirement ✅ Passed Feature properly gated with maturity="alpha" tag on XR command; maturity system enforces gating via config settings; not in apis/**, only new CLI functionality added.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
cmd/crossplane/xr/generate.go (1)

116-116: 💤 Low value

Make error message consistent with codebase style.

For consistency with other error messages in the codebase (which use lowercase and "cannot"), consider changing "Unable to marshal back to yaml" to "cannot marshal XR to YAML".

♻️ Suggested change
-	if err != nil {
-		return errors.Wrap(err, "Unable to marshal back to yaml")
-	}
+	if err != nil {
+		return errors.Wrap(err, "cannot marshal XR to YAML")
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/crossplane/xr/generate.go` at line 116, Change the error string passed to
errors.Wrap in the return statement that currently reads errors.Wrap(err,
"Unable to marshal back to yaml") so it follows project style; replace the
message with "cannot marshal XR to YAML" (i.e., use errors.Wrap(err, "cannot
marshal XR to YAML")) in the function in generate.go where the XR marshaling
failure is handled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/crossplane/xr/generate.go`:
- Around line 136-143: Update the user-facing error message constants
(errNoAPIVersion, errNoKind, errNoSpecSection and optionally errEmptyClaimYAML
and errNilInput) to be user-friendly and actionable: replace terse developer
phrases with full-sentence guidance that names the missing field and suggests a
next step (for example: indicate the Claim YAML must include an
apiVersion/kind/spec and ask the user to check their Claim definition or
validate their YAML). Locate these constants by name in the file
(errNoAPIVersion, errNoKind, errNoSpecSection, errEmptyClaimYAML, errNilInput)
and update their string values accordingly so CLI output gives clear, helpful
instructions to the user.
- Around line 244-257: When building the XR in non-Direct mode (the block
guarded by if !opts.Direct), validate that claim.GetNamespace() is non-empty
before setting labels[labelClaimNamespace] or calling
xrPaved.SetValue("spec.claimRef", ...); if the namespace is empty return a
wrapped error (e.g. "claim namespace required in non-Direct mode") so we don't
create an XR with an empty claimRef namespace; perform this check early in the
if !opts.Direct block (before using claim.GetNamespace()) and only proceed to
set labels and call xrPaved.SetValue when the namespace is present.
- Line 100: Replace the generic errors.Wrap(err, "Unmarshalling Error") call
with a user-friendly, specific CLI message such as errors.Wrap(err, "cannot
parse Claim YAML") or errors.Wrap(err, "invalid Claim YAML format"); update the
string in the existing errors.Wrap(err, "...") expression so the returned error
refers to the Claim YAML parsing problem (keep the wrapped internal err for
diagnostics but avoid exposing raw internal details in the top-level message).

---

Nitpick comments:
In `@cmd/crossplane/xr/generate.go`:
- Line 116: Change the error string passed to errors.Wrap in the return
statement that currently reads errors.Wrap(err, "Unable to marshal back to
yaml") so it follows project style; replace the message with "cannot marshal XR
to YAML" (i.e., use errors.Wrap(err, "cannot marshal XR to YAML")) in the
function in generate.go where the XR marshaling failure is handled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c84bb47-bee6-4223-abcf-f9d69ec8d963

📥 Commits

Reviewing files that changed from the base of the PR and between 6e3542b and 1b30eaf.

📒 Files selected for processing (4)
  • cmd/crossplane/main.go
  • cmd/crossplane/xr/generate.go
  • cmd/crossplane/xr/generate_test.go
  • cmd/crossplane/xr/xr.go

Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go
Copy link
Copy Markdown
Member

@adamwg adamwg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall - left a few small comments.

Thinking to the future, it would be nice to also be able to generate a scaffold/minimal XR from an XRD (we have this in up as up example generate). Maybe we could add a --from=<claim|xrd> flag to this command, similar to how we have --from=<xr|simpleschema> on crossplane xrd generate. No need to add it now - just thinking of whether we can add in the future without breaking the current functionality.

Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go Outdated
Comment thread cmd/crossplane/xr/generate.go
@tampakrap tampakrap force-pushed the theo/feat_claimtoxr_v2 branch from d6f07ac to 9ad92f0 Compare May 31, 2026 18:25
Introduce a Claim to XR converter: `crossplane xr generate claim.yaml`.
Similarly to other converter functions/tools, it takes a Claim either on
stdin or as file argument and generates an equivalent XR YAML.

The parent `crossplane xr` is marked as maturity "alpha", which applies
to the subtree as well.

This new tool can be used together with the render command as shown in
the example below:

```bash
crossplane render <(crossplane xr generate claim.yaml) composition.yaml functions.yaml
```

The library function ConvertClaimToXR can be used by downstream tools
(eg crossplane-diff) that rely on Claim to XR conversion.

The tool (and as a result the converter function, via the Options
struct) is configurable and provides the following flags:
- `--direct`: omit spec.claimRef and the equivalent labels.
- `--name`: specify an explicit XR name, skipping either the random
  suffix in the non-direct mode or the Claim name fallback in direct
  mode.
- `--kind`: override the derived "X<Kind>" default.
- `--gen-uid`: populate metadata.uid with a fresh random UUID.

Signed-off-by: Theo Chatzimichos <tampakrap@gmail.com>
@tampakrap tampakrap force-pushed the theo/feat_claimtoxr_v2 branch from 9ad92f0 to 0faee7c Compare May 31, 2026 18:46
@tampakrap
Copy link
Copy Markdown
Collaborator Author

I chose to force-pushed to resolve the conflict, the changes that I did:

  • added the markdown file with the help
  • got rid of the constants with the error messages
  • lowercase start for error messages
  • fixed the vale issues

@adamwg @haarchri give me another review please

Copy link
Copy Markdown
Member

@adamwg adamwg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with the follow-up plans we've already discussed in previous comments.

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.

2 participants