From f8f466679056af5b99226128d20e80a872a56666 Mon Sep 17 00:00:00 2001 From: Jonathan Ogilvie Date: Wed, 15 Oct 2025 16:24:51 -0400 Subject: [PATCH 1/4] Update readme Signed-off-by: Jonathan Ogilvie --- README.md | 76 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2caab87..58890b0 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ The `crossplane-diff` tool helps you: - **Preview changes** before applying Crossplane resources to a cluster - **Visualize differences** at multiple levels: both the XR itself and all downstream composed resources +- **Analyze composition impact** showing how composition changes affect existing XRs in the cluster - **Support complex compositions** including functions, requirements, and environment configurations - **Handle both Crossplane v1 and v2** resource definitions, including namespaced composite resources - **Detect resources that would be removed** by your changes @@ -30,42 +31,91 @@ go build -o crossplane-diff ./cmd/diff ## Usage -### Basic Usage +### XR Diff - Preview Changes to Composite Resources ```bash # Show changes that would result from applying an XR from a file -crossplane-diff diff xr.yaml +crossplane-diff xr xr.yaml # Show changes from stdin -cat xr.yaml | crossplane-diff diff - +cat xr.yaml | crossplane-diff xr - # Process multiple files -crossplane-diff diff xr1.yaml xr2.yaml xr3.yaml +crossplane-diff xr xr1.yaml xr2.yaml xr3.yaml + +# Show changes in a specific namespace +crossplane-diff xr xr.yaml -n production # Show changes in a compact format with minimal context -crossplane-diff diff --compact xr.yaml +crossplane-diff xr xr.yaml --compact # Disable color output -crossplane-diff diff --no-color xr.yaml +crossplane-diff xr xr.yaml --no-color +``` + +### Composition Diff - Analyze Impact of Composition Changes + +```bash +# Show impact of updated composition on all XRs using it +crossplane-diff comp updated-composition.yaml + +# Show impact of multiple composition changes +crossplane-diff comp comp1.yaml comp2.yaml comp3.yaml + +# Show impact only on XRs in a specific namespace +crossplane-diff comp updated-composition.yaml -n production + +# Include XRs with Manual update policy (pinned revisions) +crossplane-diff comp updated-composition.yaml --include-manual ``` ### Command Options +#### `xr` - Diff Composite Resources + ``` -crossplane-diff diff [ ...] [flags] +crossplane-diff xr [ ...] [flags] Arguments: [ ...] YAML files containing Crossplane resources to diff. Flags: - --no-color Disable colorized output. - --compact Show compact diffs with minimal context. - --timeout=1m How long to run before timing out. - --qps=0 Maximum QPS to the API server. - --burst=0 Maximum burst for throttle. - --verbose Print verbose logging statements. + -h, --help Show context-sensitive help. + --verbose Print verbose logging statements. + --no-color Disable colorized output. + --compact Show compact diffs with minimal context. + --max-nested-depth=10 Maximum depth for nested XR recursion. + --timeout=1m How long to run before timing out. + --qps=0 Maximum QPS to the API server. + --burst=0 Maximum burst for throttle. + -n, --namespace="crossplane-system" + Namespace to compare resources against. ``` +#### `comp` - Diff Composition Impact + +``` +crossplane-diff comp [ ...] [flags] + +Arguments: + [ ...] YAML files containing updated Composition(s). + +Flags: + -h, --help Show context-sensitive help. + --verbose Print verbose logging statements. + --no-color Disable colorized output. + --compact Show compact diffs with minimal context. + --max-nested-depth=10 Maximum depth for nested XR recursion. + --timeout=1m How long to run before timing out. + --qps=0 Maximum QPS to the API server. + --burst=0 Maximum burst for throttle. + -n, --namespace="" Namespace to find XRs (empty = all namespaces). + --include-manual Include XRs with Manual update policy (default: + only Automatic policy XRs) +``` + +**Note**: The `diff` subcommand is deprecated. Use `xr` instead. + ### Prerequisites - A running Kubernetes cluster with Crossplane installed From 624c9a95731fc82603770cc65f0a11f2e24a62b0 Mon Sep 17 00:00:00 2001 From: Jonathan Ogilvie Date: Wed, 15 Oct 2025 16:32:57 -0400 Subject: [PATCH 2/4] Update flags in xr diff Signed-off-by: Jonathan Ogilvie --- README.md | 7 ++----- cmd/diff/xr.go | 21 +++++++++------------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 58890b0..9026d78 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,6 @@ cat xr.yaml | crossplane-diff xr - # Process multiple files crossplane-diff xr xr1.yaml xr2.yaml xr3.yaml -# Show changes in a specific namespace -crossplane-diff xr xr.yaml -n production - # Show changes in a compact format with minimal context crossplane-diff xr xr.yaml --compact @@ -88,10 +85,10 @@ Flags: --timeout=1m How long to run before timing out. --qps=0 Maximum QPS to the API server. --burst=0 Maximum burst for throttle. - -n, --namespace="crossplane-system" - Namespace to compare resources against. ``` +**Note**: XR namespaces are read directly from the YAML files being diffed, not from command-line flags. + #### `comp` - Diff Composition Impact ``` diff --git a/cmd/diff/xr.go b/cmd/diff/xr.go index 6119edb..d662f73 100644 --- a/cmd/diff/xr.go +++ b/cmd/diff/xr.go @@ -34,8 +34,7 @@ type XRCmd struct { // Embed common fields CommonCmdFields - Namespace string `default:"crossplane-system" help:"Namespace to compare resources against." name:"namespace" short:"n"` - Files []string `arg:"" help:"YAML files containing Crossplane resources to diff." optional:""` + Files []string `arg:"" help:"YAML files containing Crossplane resources to diff." optional:""` } // Help returns help instructions for the XR diff command. @@ -46,17 +45,18 @@ This command returns a diff of the in-cluster resources that would be modified i Similar to kubectl diff, it requires Crossplane to be operating in the live cluster found in your kubeconfig. Examples: - # Show the changes that would result from applying xr.yaml (via file) in the default 'crossplane-system' namespace. + # Show the changes that would result from applying xr.yaml (via file). crossplane-diff xr xr.yaml - # Show the changes that would result from applying xr.yaml (via stdin) in the default 'crossplane-system' namespace. + # Show the changes that would result from applying xr.yaml (via stdin). cat xr.yaml | crossplane-diff xr -- - # Show the changes that would result from applying xr.yaml, xr1.yaml, and xr2.yaml in the default 'crossplane-system' namespace. + # Show the changes that would result from applying multiple files. + crossplane-diff xr xr1.yaml xr2.yaml cat xr.yaml | crossplane-diff xr xr1.yaml xr2.yaml -- - # Show the changes that would result from applying xr.yaml (via file) in the 'foobar' namespace with no color output. - crossplane-diff xr xr.yaml -n foobar --no-color + # Show the changes with no color output. + crossplane-diff xr xr.yaml --no-color # Show the changes in a compact format with minimal context. crossplane-diff xr xr.yaml --compact @@ -88,11 +88,8 @@ func (c *XRCmd) initializeDependencies(ctx *kong.Context, log logging.Logger, co } func makeDefaultXRProc(c *XRCmd, ctx *AppContext, log logging.Logger) dp.DiffProcessor { - // Use provided namespace or default to "default" - namespace := c.Namespace - if namespace == "" { - namespace = "default" - } + // Use default namespace for processor options (not actually used for XR diffs) + namespace := "default" opts := defaultProcessorOptions(c.CommonCmdFields, namespace) opts = append(opts, From e943d6d2b2aa9715615206e105837fde2e214e22 Mon Sep 17 00:00:00 2001 From: Jonathan Ogilvie Date: Wed, 15 Oct 2025 16:46:21 -0400 Subject: [PATCH 3/4] Fix unit tests Signed-off-by: Jonathan Ogilvie --- cmd/diff/diff_test.go | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/cmd/diff/diff_test.go b/cmd/diff/diff_test.go index f1aa5ad..f7bdb41 100644 --- a/cmd/diff/diff_test.go +++ b/cmd/diff/diff_test.go @@ -69,8 +69,7 @@ func TestCmd_Run(t *testing.T) { type fields struct { CommonCmdFields - Namespace string - Files []string + Files []string } type args struct { @@ -108,8 +107,7 @@ func TestCmd_Run(t *testing.T) { }{ "SuccessfulRun": { fields: fields{ - Namespace: "default", - Files: []string{}, + Files: []string{}, CommonCmdFields: CommonCmdFields{ NoColor: false, Compact: false, @@ -147,8 +145,7 @@ metadata: }, "ClientInitializeError": { fields: fields{ - Namespace: "default", - Files: []string{}, + Files: []string{}, }, args: args{ appContext: AppContext{ @@ -176,8 +173,7 @@ metadata: }, "ProcessorInitializeError": { fields: fields{ - Namespace: "default", - Files: []string{}, + Files: []string{}, }, args: args{ appContext: appCtx, @@ -196,8 +192,7 @@ metadata: }, "LoaderError": { fields: fields{ - Namespace: "default", - Files: []string{}, + Files: []string{}, }, args: args{ appContext: appCtx, @@ -216,8 +211,7 @@ metadata: }, "ProcessResourcesError": { fields: fields{ - Namespace: "default", - Files: []string{}, + Files: []string{}, }, args: args{ appContext: appCtx, @@ -260,7 +254,6 @@ metadata: files := tc.setupFiles() c := &XRCmd{ - Namespace: tc.fields.Namespace, Files: files, CommonCmdFields: tc.fields.CommonCmdFields, } @@ -903,7 +896,6 @@ spec: // Create our command cmd := &XRCmd{ - Namespace: "default", CommonCmdFields: CommonCmdFields{ Timeout: time.Second * 30, }, @@ -928,7 +920,7 @@ spec: // Create options for the DiffProcessor options := []dp.ProcessorOption{ dp.WithLogger(logger), - dp.WithNamespace(cmd.Namespace), + dp.WithNamespace("default"), // Add other options as needed } From 10fba6b8a60f9afd6c8caf4e9f343189e942b904 Mon Sep 17 00:00:00 2001 From: Jonathan Ogilvie Date: Wed, 15 Oct 2025 16:59:29 -0400 Subject: [PATCH 4/4] Remove flag from ITs Signed-off-by: Jonathan Ogilvie --- cmd/diff/diff_integration_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cmd/diff/diff_integration_test.go b/cmd/diff/diff_integration_test.go index 3e6818d..8db7cd9 100644 --- a/cmd/diff/diff_integration_test.go +++ b/cmd/diff/diff_integration_test.go @@ -173,12 +173,9 @@ func runIntegrationTest(t *testing.T, testType DiffTestType, scheme *runtime.Sch fmt.Sprintf("--timeout=%s", timeout.String()), } - // Add namespace if specified (for composition tests) - if tt.namespace != "" { + // Add namespace if specified (for composition tests only) + if tt.namespace != "" && testType == CompositionDiffTest { args = append(args, fmt.Sprintf("--namespace=%s", tt.namespace)) - } else if testType == XRDiffTest { - // For XR tests, always add default namespace - args = append(args, "--namespace=default") } // Add no-color flag if true