Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
07ac89b
feat(render): expose ErrStaleRenderBackend for outdated render backends
jcogilvie Oct 18, 2026
b18b3ae
feat(diff): port renderer, types and testutils from crossplane-diff
jcogilvie Oct 18, 2026
8cd5e3f
build(nix): fetch Crossplane CRDs for diff tests
jcogilvie Oct 18, 2026
1ab035b
build(nix): format apps.nix and refresh vendor hash
jcogilvie Oct 18, 2026
a777efb
feat(diff): port ref, dockerrun and core client from crossplane-diff
jcogilvie Oct 18, 2026
e4fe74f
chore(diff): resync ported packages with crossplane-diff 9fa7d31
jcogilvie Oct 18, 2026
8cda557
feat(diff): port kubernetes client from crossplane-diff
jcogilvie Oct 18, 2026
1f914a1
feat(diff): port crossplane client from crossplane-diff
jcogilvie Oct 18, 2026
49bca29
feat(diff): port diffprocessor from crossplane-diff
jcogilvie Oct 18, 2026
ba1e321
refactor(diff): use render.ErrStaleRenderBackend from the cli
jcogilvie Oct 18, 2026
8f637f7
refactor(diff): use semver v3 for render version checks
jcogilvie Oct 19, 2026
b14c7d2
feat(diff): add client bundle constructor
jcogilvie Oct 19, 2026
47a3cde
refactor(project): export function loading for reuse by simulate
jcogilvie Oct 19, 2026
0c47131
fix(project): match default excludes when APIs path is the project root
jcogilvie Oct 19, 2026
61d2585
feat(project): export composition discovery
jcogilvie Oct 19, 2026
c5fdbd3
feat(diff): add project function overlay provider
jcogilvie Oct 19, 2026
3110a15
feat(project): add alpha project simulate command
jcogilvie Oct 19, 2026
e203e7e
feat(project): exit 3 on changes with project simulate --exit-code
jcogilvie Oct 19, 2026
5936cf0
feat(diff): port crossplane-diff integration tests behind a simulate …
jcogilvie Oct 19, 2026
52fd448
fix(diff): lint the ported integration tests
jcogilvie Oct 19, 2026
7fc39fa
fix(diff): skip integration environment gaps before the cluster starts
jcogilvie Oct 19, 2026
70a5abd
fix(diff): guard the concurrency test's cluster startup like the runner
jcogilvie Oct 19, 2026
d4f66b9
feat(project): add crossplane-diff flag parity to project simulate
jcogilvie Oct 19, 2026
f95734e
test(kube,diff): cover RESTConfig and client.New
jcogilvie Oct 19, 2026
b2056d3
test(diff): enable flag-parity integration cases
jcogilvie Oct 19, 2026
5e47c11
build(nix): provide envtest assets for integration tests
jcogilvie Oct 19, 2026
9b37e70
build(nix): run integration tests in the main test target
jcogilvie Oct 20, 2026
8631543
Revert "build(nix): run integration tests in the main test target"
jcogilvie Oct 20, 2026
cbd9abf
test(diff): put integration tests behind the integration build tag
jcogilvie Oct 20, 2026
51b00fa
build(nix): publish integration test coverage
jcogilvie Oct 20, 2026
7824b49
test(diff): run the XR integration cases through the engine harness
jcogilvie Oct 20, 2026
e08d585
feat(project): add --output-version to project simulate
jcogilvie Oct 20, 2026
38b87dc
feat(project)!: make project simulate's -f a repeatable --input
jcogilvie Oct 20, 2026
57f0ca8
feat(project): simulate Composition and composite resource files
jcogilvie Oct 20, 2026
9497f57
test(diff): run the integration cases through project simulate
jcogilvie Oct 20, 2026
9f6f3b1
fix(project): stop ignoring last-applied-configuration in project sim…
jcogilvie Oct 20, 2026
ab52696
fix(project): reject -f inputs that are not composite resources
jcogilvie Oct 20, 2026
72823e0
feat(project)!: exit 3 when project simulate finds changes
jcogilvie Oct 20, 2026
a74e96b
fix(diff): print errors once, from the command, not inline
jcogilvie Oct 20, 2026
0941a2e
refactor(diff): move object comparison out of the renderer into compare
jcogilvie Oct 20, 2026
83cfc83
feat(plan): carry composite grouping, errors and revision impact in p…
jcogilvie Oct 20, 2026
dee0633
refactor(simulate): move per-resource planning into internal/simulate
jcogilvie Oct 20, 2026
bfc400f
refactor(diff): processors return reports; the command renders them
jcogilvie Oct 21, 2026
d906461
refactor(diff): move the output model into a result package
jcogilvie Oct 21, 2026
b9668f4
refactor(diff): record filtered XRs in both modes; the renderer decides
jcogilvie Oct 21, 2026
2a8b154
feat(simulate): map diff reports to plan.Result
jcogilvie Oct 21, 2026
3811f1b
feat(plan): print revision impact and notes in plan text
jcogilvie Oct 21, 2026
37ba607
test(simulate): drop the unused ref helper
jcogilvie Oct 21, 2026
159cc8a
feat(project)!: default project simulate to -o plan
jcogilvie Oct 21, 2026
3a9d8b7
fix(plan): quote map keys containing dots in field paths
jcogilvie Oct 21, 2026
e60df12
fix(diff): key the function provider cache by pipeline
jcogilvie Oct 21, 2026
b1eb748
feat(diff): let changed functions trigger composition impact analysis
jcogilvie Oct 21, 2026
dc4bdec
feat(plan): name each composite's composition in comp results
jcogilvie Oct 21, 2026
388b773
test(simulate): assert integration JSON output on plan.Result
jcogilvie Oct 21, 2026
6cd6e8d
refactor(simulate)!: drop crossplane-diff's v1/v2 structured output
jcogilvie Oct 21, 2026
d2b10be
feat(diff): opt-in WithKeepEqualDiffs predicate
jcogilvie Oct 21, 2026
1d3665c
feat(simulate): plan engine diffs with provider diff servers
jcogilvie Oct 21, 2026
204acc6
refactor(simulate): share diff server lifecycle; load project provide…
jcogilvie Oct 21, 2026
24936f6
feat(simulate): annotate -o diff with provider plans
jcogilvie Oct 21, 2026
87f139b
feat(project): detect changed embedded functions in project simulate
jcogilvie Oct 21, 2026
36c2eb7
test(diff): keep engine tests free of CLI packages
jcogilvie Oct 21, 2026
bf9adc6
test(simulate): mark the unchanged-field check as reduced coverage
jcogilvie Oct 21, 2026
d2674c0
fix(simulate): tidy provider-plan review nits
jcogilvie Oct 21, 2026
dfaf72a
feat(plan)!: carry before and after objects in plan.Result
jcogilvie Oct 21, 2026
5f4887e
fix(plan): clean before and after in resource simulate
jcogilvie Oct 21, 2026
903db0e
feat(diff): opt-in per-XR timeout and after-XR hook
jcogilvie Oct 21, 2026
04483f9
feat(simulate): plan each composite's resources as the engine renders it
jcogilvie Oct 22, 2026
350c715
feat(simulate): start provider diff servers incrementally
jcogilvie Oct 22, 2026
081dec9
feat(project): add provider plan flags to project simulate
jcogilvie Oct 22, 2026
19809b8
test(simulate): fix and tighten XRPlanner tests
jcogilvie Oct 22, 2026
b7ab0f1
test(simulate): stop shadowing ensureCtx in XRPlanner tests
jcogilvie Oct 22, 2026
9fdf779
style(project): align simulate flag tags
jcogilvie Oct 22, 2026
de3f7b3
feat(project): plan composed resources with provider diff servers
jcogilvie Oct 22, 2026
c1758ee
feat(project): show provider plans in project simulate output
jcogilvie Oct 22, 2026
65975d8
test(diff): run project simulate against a fake provider diff server
jcogilvie Oct 22, 2026
15355f5
fix(project): mark replacements in project simulate -o diff
jcogilvie Oct 22, 2026
59ade08
docs(project): describe provider plans and exit codes in simulate help
jcogilvie Oct 22, 2026
2f9d79c
perf(diff): build cluster lookups lazily instead of listing at startup
jcogilvie Oct 22, 2026
104855d
test(diff): port lazy-lookup integration cases
jcogilvie Oct 22, 2026
dc71e43
fix(simulate): stop mutating the global scheme in NewKubeClient
jcogilvie Oct 22, 2026
1cbed0a
fix(diff): pause the per-XR budget while run-wide work runs
jcogilvie Oct 22, 2026
dd65518
fix(project): note when no diff server served any plan
jcogilvie Oct 22, 2026
43ebcd7
fix(simulate): don't cache ProviderConfig lookups that failed on a co…
jcogilvie Oct 22, 2026
d89e116
fix(project): reject a non-positive --timeout
jcogilvie Oct 22, 2026
d301f72
fix(simulate): degrade when a provider lookup fails in on-demand mode
jcogilvie Oct 22, 2026
a3e0497
fix(simulate): keep the first plan per diff key and document sequenti…
jcogilvie Oct 22, 2026
16994ca
fix(project): allow --cache-dir with planning, select servers in a te…
jcogilvie Oct 22, 2026
4f8b38d
fix(diff): test function start outside the XR budget, close the budge…
jcogilvie Oct 22, 2026
b55b80d
fix(simulate): count routed plans that fail, capitalize the warning, …
jcogilvie Oct 22, 2026
2ea5858
fix(simulate): key incremental server start by name for Development p…
jcogilvie Oct 22, 2026
daf21fa
feat(project): accept repeated and namespace-qualified --name in proj…
jcogilvie Oct 22, 2026
b06d6ca
feat(diff): render pinned XRs against their revision when it calls a …
jcogilvie Oct 22, 2026
4c98f33
feat(simulate): report pinned XRs rendered against their revision
jcogilvie Oct 22, 2026
e49fc9c
fix(simulate): keep cluster-only changes beside a provider plan's
jcogilvie Oct 22, 2026
d7d346a
fix(plan): tolerate empty replace paths and mark pinned composites in…
jcogilvie Oct 22, 2026
bc6ebae
fix(simulate): cache only definite CRD answers, show provider-only re…
jcogilvie Oct 22, 2026
0c6c114
test(simulate): cover dotted Secret keys and CRD fetch caching
jcogilvie Oct 22, 2026
24d4d1b
feat(plan)!: always report deferred, name error refs ref, mark every …
jcogilvie Oct 22, 2026
22305c5
feat(plan)!: report composite reasons as a typed camelCase enum
jcogilvie Oct 22, 2026
2d38e40
build(nix): keep envtest assets Linux-only and out of the unit-test c…
jcogilvie Oct 22, 2026
a87fb15
ci: cache Go modules in the integration-tests job
jcogilvie Oct 22, 2026
ce11095
fix(diff): resolve pinned XRs on changed functions before skipping a …
jcogilvie Oct 22, 2026
b56c115
fix(diff): drop the --resource flag name from the preflight error
jcogilvie Oct 22, 2026
15e05a4
build(nix): provide envtest binaries on macOS
jcogilvie Oct 22, 2026
42e0e3c
build(nix): inherit envtest hash for statix
jcogilvie Oct 22, 2026
2a59fac
fix(load): add a loader constructor that doesn't split paths on commas
jcogilvie Oct 22, 2026
b745376
fix(project): validate simulate's flags before building and keep both…
jcogilvie Oct 22, 2026
73d61ea
test(diff): report parse errors from the simulate harness as main does
jcogilvie Oct 22, 2026
894cc3b
test(simulate): fail plan assertions that would pass vacuously
jcogilvie Oct 22, 2026
1f323ae
test(simulate): unify plan expectations behind one builder
jcogilvie Oct 22, 2026
ec39f5e
test(simulate): merge the downstream and flat resource expectations
jcogilvie Oct 22, 2026
bdcd772
test(simulate): enforce spec and absent-field checks on downstream re…
jcogilvie Oct 22, 2026
aefefd0
test(simulate): call the unified plan expectation builder
jcogilvie Oct 22, 2026
65f353d
test(simulate): drop the pre-unification expectation names
jcogilvie Oct 22, 2026
e01e2ca
test(diff): give integration cases one plan expectation field
jcogilvie Oct 22, 2026
7456234
test(diff): run project simulate on project fixtures
jcogilvie Oct 22, 2026
df3be22
test(diff): simulate a project with an embedded function
jcogilvie Oct 22, 2026
317cea1
build(nix): keep the host PATH for integration tests
jcogilvie Oct 22, 2026
829de80
test(project): let tests replace simulate's diff server set
jcogilvie Oct 22, 2026
a01d955
test(diff): simulate a project with a provider dependency
jcogilvie Oct 22, 2026
669522b
test(diff): prove the project's function wins over the cluster's
jcogilvie Oct 22, 2026
8b52e61
test: address project table review nits
jcogilvie Oct 22, 2026
48f2d6e
test(diff): drop the -short skip from project cases
jcogilvie Oct 23, 2026
b351a05
docs(project): fix vale errors in simulate help
jcogilvie Oct 23, 2026
2365fb3
docs(project): say which errors exit 1 and 80 in simulate help
jcogilvie Oct 23, 2026
7e15b0c
style(project): realign simulate flag tags
jcogilvie Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,45 @@ jobs:
file: result/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}

# The diff integration tests run the render engine's functions as Docker
# containers, so they cannot run in the Nix sandbox like the unit tests.
# The app runs outside the sandbox against the runner's Docker daemon.
integration-tests:
runs-on: ubuntu-24.04

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Install Nix
uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31

- name: Setup Cachix
uses: cachix/cachix-action@38b082610b782e7e93e209c35fd730d399dee866 # v17
with:
name: crossplane
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}

- name: Cache Go modules and build cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-integration-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-integration-

- name: Run Integration Tests
run: nix run .#integration-test --option warn-dirty false

- name: Publish Integration Test Coverage
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7
with:
flags: integration
file: coverage-integration.txt
token: ${{ secrets.CODECOV_TOKEN }}

# Build all artifacts
build-artifacts:
permissions:
Expand Down
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Zone.Identifier
build/

# Nix build output symlinks
result
result-*
/result
/result-*

# Exclude the ko data dir
kodata/
Expand Down Expand Up @@ -45,3 +45,5 @@ AGENTS.md

# Ignore local dev environment variables
.env
/coverage-integration.txt
/coverage-merged.txt
9 changes: 9 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ run:
# runs our unit tests. Lint them anyway, so they don't rot.
build-tags:
- compilegate
# The diff integration tests need Docker and envtest, so they sit behind
# the integration tag and run in their own target, not the unit tests.
# Lint them anyway.
- integration

output:
formats:
Expand Down Expand Up @@ -107,6 +111,11 @@ linters:
# Deprecated and replaced by a new version, but still on by default.
- gomodguard
settings:
exhaustive:
# Only check switches marked //exhaustive:enforce, and don't let a
# default case satisfy them.
explicit-exhaustive-switch: true
default-signifies-exhaustive: false
depguard:
rules:
no_third_party_test_libraries:
Expand Down
26 changes: 26 additions & 0 deletions cmd/crossplane/common/exit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright 2026 The Crossplane Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package common

// ExitStatus is the exit status of a command that returns no error. main
// binds a pointer to one, so a command's Run can take it as a parameter and
// set a non-zero status for a result that is not an error, such as changes
// found. An error the command returns takes precedence over the status.
type ExitStatus struct {
// Code is the status to exit with. Zero unless the command sets it.
Code int
}
12 changes: 11 additions & 1 deletion cmd/crossplane/common/load/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ type CompositeLoader struct {
// Sources can be files, directories, or "-" for stdin.
// If sources is empty, stdin is used by default.
func NewCompositeLoader(sources []string) (Loader, error) {
return newCompositeLoader(sources, NewLoader)
}

// NewExactCompositeLoader is NewCompositeLoader, except each source is exactly
// one path or "-": commas are part of the path, not separators.
func NewExactCompositeLoader(sources []string) (Loader, error) {
return newCompositeLoader(sources, newLoader)
}

func newCompositeLoader(sources []string, newSource func(string) (Loader, error)) (Loader, error) {
if len(sources) == 0 {
// In unit tests, this will cause an error when Load() is called
// which is the expected behavior for NoSources test case
Expand All @@ -280,7 +290,7 @@ func NewCompositeLoader(sources []string) (Loader, error) {
stdinUsed = true
}

loader, err := NewLoader(source)
loader, err := newSource(source)
if err != nil {
return nil, errors.Wrapf(err, "cannot create loader for %q", source)
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/crossplane/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
runtimexpkg "github.com/crossplane/crossplane-runtime/v2/pkg/xpkg"

"github.com/crossplane/cli/v2/cmd/crossplane/cluster"
"github.com/crossplane/cli/v2/cmd/crossplane/common"
"github.com/crossplane/cli/v2/cmd/crossplane/completion"
"github.com/crossplane/cli/v2/cmd/crossplane/composition"
configcmd "github.com/crossplane/cli/v2/cmd/crossplane/config"
Expand Down Expand Up @@ -131,6 +132,7 @@ func main() {
os.Exit(1)
}

status := &common.ExitStatus{}
parser := kong.Must(&cli{},
kong.Name("crossplane"),
// Binding a variable to kong context makes it available to all commands
Expand All @@ -139,6 +141,8 @@ func main() {
kong.BindTo(configcmd.ConfigPath(cfgPath), (*configcmd.ConfigPath)(nil)),
// Bind the loaded config so commands can read feature flags at runtime.
kong.Bind(cfg),
// Commands set the exit status of a run that returns no error.
kong.Bind(status),
kongVars,
kong.Help(helpPrinter),
kong.UsageOnError())
Expand Down Expand Up @@ -185,7 +189,12 @@ func main() {
}
os.Exit(130)
}
// An error is printed and exits 1, or with its ExitCoder's code;
// otherwise the run exits with the status its command set.
ctx.FatalIfErrorf(err)
if status.Code != 0 {
os.Exit(status.Code)
}
}

// exitOnSignal waits for SIGINT or SIGTERM, then exits with status 130
Expand Down
201 changes: 201 additions & 0 deletions cmd/crossplane/project/help/simulate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
The `project simulate` command previews how applying a project's Compositions,
or changed Composition or composite resource files, would change the composite
resources in a cluster. It renders each affected composite resource and shows
the difference from what's in the cluster. It doesn't change the cluster.

The `-f` flag picks what to simulate. Repeat it to pass more than one file or
directory, or pass `-` to read from standard input:

- A project file, the default, simulates the project. The command builds the
project's embedded functions and loads them into the local Docker daemon,
resolves its function dependencies, and collects the Compositions under its
APIs path. It renders each composite resource that uses one of those
Compositions with the project's version of the Composition, using the
project's functions in place of the cluster's functions of the same name.
- Composition files simulate those Compositions without a project. The command
renders each composite resource in the cluster that uses one of them, with
the functions installed in the cluster.
- Composite resource or claim files simulate those resources. The command
renders each one with the Composition the cluster selects for it and the
functions installed in the cluster.

A project file must be the only `-f` input, and one run can't mix Compositions
with composite resources. Any other resource, such as package metadata, a
Provider or a ConfigMap, is rejected: each one must be a kind an XRD in the
cluster defines as a composite resource or claim.

The command connects to the cluster in your current Kubernetes context, or the
one `--context` names.

The command needs Docker, to build and run functions, and read access to the
cluster's Crossplane resources. It verifies the rendered resources with
server-side dry-run requests, so it also needs the `create` and `patch` verbs on
them. Use `--as`, `--as-group`, and `--as-uid` to simulate as another user.

By default, `simulate` skips composite resources with a `Manual` composition
update policy, because they don't adopt a new Composition revision on their
own. A pinned composite whose revision calls a function the project changes is
still simulated, rendered against the revision it's pinned to. Pass
`--include-pinned` to render every pinned composite against the new Composition
instead.

Some flags apply only to some inputs. `--namespace`, `--name`,
`--include-pinned`, `--analyze-on`, and `--minimize-composition` choose which
composite resources a Composition change reaches, so composite resource files
don't take them. `--max-concurrency` configures the project's function builds,
so only a project file takes it. `--cache-dir` caches function builds and
provider packages, so Composition and composite resource files take it unless
`--skip-plan` is set.

The `-o` flag picks the output format:

- `plan`, the default, prints each change as a field-level plan, grouped under
the composite resource it belongs to. A changed Composition prints first,
with whether applying it creates a new Composition revision.
- `json` and `yaml` print the same plan as a structured result, for CI and
other tools. Each plan carries the objects it compares, as `before` (the
live object, absent for a create) and `after` (the rendered object, absent
for a delete), with ignored paths, status and server-managed metadata
removed and Secret values redacted. A provider-planned resource's `after`
is the manifest sent to the provider, not the provider's view.
- `diff` prints the line diff `crossplane-diff` prints.

For example, a changed Composition run with `--skip-plan` prints a plan like this:

```
[~] Composition.apiextensions.crossplane.io xnetworks.example.org (update)
Applying this creates a new CompositionRevision, which 1 composite would adopt.
spec:
pipeline[0]:
input:
~ region: "us-west-1" -> "us-east-1"

XR: XNetwork.example.org team-a/prod-network
[~] VPC.ec2.aws.upbound.io prod-network (update)
spec:
forProvider:
~ region: "us-west-1" -> "us-east-1"

Plan: 0 to add, 2 to change, 0 to destroy.

Note: Cloud-layer plan skipped (--skip-plan).
```

The `--timeout` flag, 2m by default, bounds the time to simulate one composite
resource: its render and its resources' provider plans. Function and provider
image pulls don't count, but the render image pull counts against the first
composite resource's budget.

By default `simulate` also runs provider plans: it asks each provider's diff
server to plan the managed resources, so the plan shows changes the cluster
can't see. The diff servers come from `--providers` when set, otherwise from
the project's provider dependencies in project mode, otherwise from the
providers installed on the cluster that own the rendered resources, started on
demand. A resource no diff server serves keeps its cluster-layer diff. In `json`
and `yaml` output, `approximate: true` on a plan means it was computed
client-side, without a provider diff, because the provider couldn't diff that
resource. The result's `notes` say when provider plans were skipped or no diff
server served the resources.

Provider plans are controlled by these flags:

- `--skip-plan` doesn't run provider diff servers and shows only the
cluster-layer diff. It can't be combined with the three flags below.
- `--providers` takes a YAML file or directory of Provider manifests to run as
diff servers, instead of discovering providers from the cluster.
- `--image-configs` takes a YAML file of ImageConfig manifests that rewrite
provider image paths for local pulls. It defaults to the project's
imageConfigs when `-f` names a project file; in Composition and XR modes it
falls back, best effort, to the project file in the current directory.
- `--session-id` sets the `simulate.crossplane.io/session` label on diff server
containers. It defaults to a random per-process ID.

The command accepts the same diff-tuning flags as `crossplane-diff`:

- `--ignore-paths` leaves paths out of the diff.
- `--function-credentials` and `--function-registry-override` configure the
functions the render runs.
- `--max-nested-depth` limits nested composite resource recursion.
- `--dry-run-on` picks which resources the server-side dry run verifies:
`existing` or `all`, the default.
- `--analyze-on` sets the smallest Composition change that triggers impact
analysis: `spec-change`, `any-change`, or `always`.
- `--minimize-composition` collapses each changed Composition to one line in
`-o diff` output.
- `--eventual-state` shows the state after all reconciliation cycles complete.
- `--max-recv-message-size` raises the function gRPC message limit, in MB.
- `--no-color` and `--compact` change how `-o diff` prints.

The command exits with one of these statuses, so a CI pipeline can gate on
the result:

- 0: the simulation succeeded and found no changes.
- 1: the simulation failed, including when the -f inputs can't be read or
can't be simulated together. If a provider plan fails, so does its whole
composite resource, which then reports an error entry and none of its
resources' plans.
- 2: only schema validation failed.
- 3: the simulation succeeded and found changes, including drift a provider
plan found that the cluster diff didn't.
- 80: the flags were invalid, so nothing was simulated.
- 130: the simulation was interrupted.

When more than one applies, the lowest of 1, 2 and 3 wins.

## Examples

Simulate the project in the current directory against the current context:

```shell
crossplane project simulate
```

Simulate against another context, only for composite resources in one
namespace:

```shell
crossplane project simulate --context=staging -n team-a
```

Simulate a single namespaced composite resource:

```shell
crossplane project simulate -n team-a --name=my-database
```

`--name` takes `[namespace/]name` and is repeatable or comma-separated. Simulate
two composite resources in different namespaces:

```shell
crossplane project simulate --name=team-a/my-database --name=team-b/my-database
```

Print the plan as JSON:

```shell
crossplane project simulate -o json
```

Print the line diff `crossplane-diff` prints:

```shell
crossplane project simulate -o diff
```

Simulate a changed Composition without a project:

```shell
crossplane project simulate -f composition.yaml
```

Simulate changed composite resources:

```shell
crossplane project simulate -f xr.yaml -f claim.yaml
```

Simulate composite resources read from standard input:

```shell
cat xr.yaml | crossplane project simulate -f -
```
11 changes: 6 additions & 5 deletions cmd/crossplane/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ package project

// Cmd contains project subcommands.
type Cmd struct {
Init initCmd `cmd:"" help:"Initialize a new project."`
Build buildCmd `cmd:"" help:"Build a project into Crossplane packages."`
Push pushCmd `cmd:"" help:"Push a built project to an OCI registry."`
Run runCmd `cmd:"" help:"Build and run a project in a local dev control plane." novale:"Google.WordList[\"admin\"]"`
Stop stopCmd `cmd:"" help:"Tear down a local dev control plane."`
Init initCmd `cmd:"" help:"Initialize a new project."`
Build buildCmd `cmd:"" help:"Build a project into Crossplane packages."`
Push pushCmd `cmd:"" help:"Push a built project to an OCI registry."`
Run runCmd `cmd:"" help:"Build and run a project in a local dev control plane." novale:"Google.WordList[\"admin\"]"`
Simulate simulateCmd `cmd:"" help:"Preview how a project's Compositions would change a cluster's composite resources." maturity:"alpha"`
Stop stopCmd `cmd:"" help:"Tear down a local dev control plane."`
}
Loading
Loading