Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 60 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,42 +31,88 @@ 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 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 [<files> ...] [flags]
crossplane-diff xr [<files> ...] [flags]

Arguments:
[<files> ...] 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.
```

**Note**: XR namespaces are read directly from the YAML files being diffed, not from command-line flags.

#### `comp` - Diff Composition Impact

```
crossplane-diff comp [<files> ...] [flags]

Arguments:
[<files> ...] 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
Expand Down
7 changes: 2 additions & 5 deletions cmd/diff/diff_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 7 additions & 15 deletions cmd/diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ func TestCmd_Run(t *testing.T) {
type fields struct {
CommonCmdFields

Namespace string
Files []string
Files []string
}

type args struct {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -147,8 +145,7 @@ metadata:
},
"ClientInitializeError": {
fields: fields{
Namespace: "default",
Files: []string{},
Files: []string{},
},
args: args{
appContext: AppContext{
Expand Down Expand Up @@ -176,8 +173,7 @@ metadata:
},
"ProcessorInitializeError": {
fields: fields{
Namespace: "default",
Files: []string{},
Files: []string{},
},
args: args{
appContext: appCtx,
Expand All @@ -196,8 +192,7 @@ metadata:
},
"LoaderError": {
fields: fields{
Namespace: "default",
Files: []string{},
Files: []string{},
},
args: args{
appContext: appCtx,
Expand All @@ -216,8 +211,7 @@ metadata:
},
"ProcessResourcesError": {
fields: fields{
Namespace: "default",
Files: []string{},
Files: []string{},
},
args: args{
appContext: appCtx,
Expand Down Expand Up @@ -260,7 +254,6 @@ metadata:
files := tc.setupFiles()

c := &XRCmd{
Namespace: tc.fields.Namespace,
Files: files,
CommonCmdFields: tc.fields.CommonCmdFields,
}
Expand Down Expand Up @@ -903,7 +896,6 @@ spec:

// Create our command
cmd := &XRCmd{
Namespace: "default",
CommonCmdFields: CommonCmdFields{
Timeout: time.Second * 30,
},
Expand All @@ -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
}

Expand Down
21 changes: 9 additions & 12 deletions cmd/diff/xr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Loading