Skip to content

render: unwind multi-composition workaround in EngineRenderFn once upstream Engine API supports it #338

@jcogilvie

Description

@jcogilvie

What problem are you facing?

PR #326 introduces a self-contained workaround in cmd/diff/diffprocessor/render_engine.go to support multi-composition rendering in a single xr invocation (e.g. diffing a GitOps directory whose XRs resolve to different Composition objects with overlapping-but-not-identical function pipelines).

The workaround:

  1. Calls engine.Setup exactly once on the first render. Upstream's dockerRenderEngine.Setup creates a fresh Docker network and stamps the first batch of functions with the render.AnnotationKeyRuntimeDockerNetwork annotation.
  2. Captures the network name back off the annotated functions into an EngineRenderFn.networkName field.
  3. On every subsequent render, manually applies the captured network annotation to any function we haven't already started (mimicking upstream's unexported injectNetworkAnnotation) before calling StartFunctionRuntimes.
  4. Tracks started function names in a startedNames set and accumulates returned *FunctionAddresses in fnAddrsList so Cleanup can stop them all.

This works but couples us to internal state of dockerRenderEngine (the network name) via an annotation side-channel. The fix belongs upstream — we're carrying the workaround as a stop-gap until then.

How could Crossplane help solve your problem?

Wait for upstream crossplane/cli#96 to land a clean API (either an idempotent Setup or a new Engine.AnnotateFunctions), then delete the workaround.

Dependency map / ordering

crossplane/cli#96 (this issue's upstream peer)
    │
    ├── lands in a release (e.g. v2.4.x)
    │
    └── crossplane-diff: bump go.mod to that release
        │
        └── crossplane-diff: this issue — delete the workaround

crossplane/cli#65 (don't-overwrite + pre-set network) and crossplane-contrib/crossplane-diff#255 (CROSSPLANE_DIFF_DOCKER_NETWORK env var) are independent of this work and don't need to land first; they coexist with our current workaround.

What to delete when unwinding

In cmd/diff/diffprocessor/render_engine.go:

  • EngineRenderFn.networkName field
  • EngineRenderFn.startedNames field (potentially — if upstream gives us a way to dedup naturally, e.g. idempotent StartFunctionRuntimes)
  • EngineRenderFn.fnAddrsList slice (if upstream lets us merge into a single accumulating *FunctionAddresses, otherwise keep)
  • firstNetworkAnnotation helper
  • applyNetworkAnnotation helper
  • The "Multi-composition note" docstring on EngineRenderFn
  • The annotate-on-subsequent-render branch in Render

Replace with whichever shape upstream lands:

  • If Option A (idempotent Setup): just call engine.Setup(ctx, newFns) every render. Keep fnAddrsList accumulation if StartFunctionRuntimes still returns separate *FunctionAddresses per call.
  • If Option B (Engine.AnnotateFunctions): call engine.Setup(ctx, fns) once, engine.AnnotateFunctions(newFns) thereafter, then StartFunctionRuntimes.

In cmd/diff/diffprocessor/render_engine_test.go:

  • Keep TestEngineRenderFn_MultiCompositionFunctionSet, TestEngineRenderFn_PreservesExistingNetworkAnnotation, and TestEngineRenderFn_CleanupStopsAllFunctionAddresses — their assertions are about caller-visible behavior and should hold against the new implementation. Update mocks if the upstream MockEngine shape changes.

Acceptance

  • EngineRenderFn no longer carries the captured-network workaround state or helpers.
  • All multi-composition unit tests still pass against the new implementation.
  • No behaviour regression in single-composition integration tests.
  • .requirements/20260609T220505Z_multi_composition_render/REQUIREMENTS.md archived or updated to reflect the unwind.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions