fix(render): annotate functions when reusing an existing network#159
Conversation
dockerRenderEngine.Setup short-circuits when e.network is already set — either pre-configured via --crossplane-docker-network or set by a prior Setup call on the same engine. Until now that short-circuit skipped injectNetworkAnnotation, leaving the supplied fns un-annotated and their containers unreachable from the render container. Annotate fns in that branch too. injectNetworkAnnotation already declines to overwrite a fn that carries its own runtime-docker-network annotation, so users who pin fns to a specific network are unaffected. This makes Setup idempotent for in-process multi-batch rendering: a tool like crossplane-contrib/crossplane-diff that calls Render across many compositions in a single process can call Setup once per composition, and every batch's fns end up on the same network. The first call returns the real cleanup; subsequent calls return no-ops, so defer cleanup() per batch is safe in LIFO order. Fixes crossplane#96 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <679297+jcogilvie@users.noreply.github.com>
|
Caution Review failedAn error occurred during the review process. Please try again later. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughUpdates ChangesDocker render setup reuse
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
cmd/crossplane/render/engine_docker_test.go (1)
302-351: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCould we fold this scenario into the table-driven
Setupcases?This test looks good functionally, but it breaks the
_test.goconvention used just above. Keeping the multi-batch scenario in the same args/want/reason table would make the coverage easier to extend and keep the file aligned with local test patterns. As per path instructions,**/*_test.go: "Enforce table-driven test structure: PascalCase test names (no underscores), args/want pattern, use cmp.Diff with cmpopts.EquateErrors() for error testing. Check for proper test case naming and reason fields."🤖 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/render/engine_docker_test.go` around lines 302 - 351, The multi-batch Setup scenario in dockerRenderEngine should be folded into the existing table-driven test pattern instead of living as a standalone test. Move this coverage into the Setup cases alongside the other args/want/reason entries, and keep using the same Setup helper patterns and cmp.Diff-based assertions so the test structure stays consistent with the surrounding engine_docker_test coverage.Source: Path instructions
cmd/crossplane/render/engine.go (1)
44-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPlease clarify the preconfigured-network exception in the contract.
Thanks for documenting the multi-call behavior. One edge case still reads a little too strongly here: with the Docker engine, the first
Setup()call can still return a no-op cleanup when the network was pre-seeded via--crossplane-docker-network. Could you call that out explicitly so the interface comment stays aligned withcmd/crossplane/render/engine_docker.goand its preset-network tests?🤖 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/render/engine.go` around lines 44 - 50, The Setup contract comment needs to explicitly mention the preconfigured Docker network exception. Update the interface documentation on Setup in engine.go to state that although the first call normally creates the environment and returns the real cleanup, the Docker implementation may return a no-op cleanup on that first call when a network was already provided via the preset network path. Keep the wording aligned with the behavior in engine_docker.go and the preset-network tests so callers understand this special case.
🤖 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/render/engine_docker_test.go`:
- Around line 267-274: The current `EmptyFunctionsList` test case only covers a
nil `fns` slice, not an actual empty slice, so it does not match the boundary
case described. Update `TestDockerRenderEngine_Setup` in `dockerRenderEngine`
test coverage by either adding a separate case with `fns: []pkgv1.Function{}` or
renaming this case to clearly indicate it tests nil only, so the distinction
between nil and empty is explicit.
---
Nitpick comments:
In `@cmd/crossplane/render/engine_docker_test.go`:
- Around line 302-351: The multi-batch Setup scenario in dockerRenderEngine
should be folded into the existing table-driven test pattern instead of living
as a standalone test. Move this coverage into the Setup cases alongside the
other args/want/reason entries, and keep using the same Setup helper patterns
and cmp.Diff-based assertions so the test structure stays consistent with the
surrounding engine_docker_test coverage.
In `@cmd/crossplane/render/engine.go`:
- Around line 44-50: The Setup contract comment needs to explicitly mention the
preconfigured Docker network exception. Update the interface documentation on
Setup in engine.go to state that although the first call normally creates the
environment and returns the real cleanup, the Docker implementation may return a
no-op cleanup on that first call when a network was already provided via the
preset network path. Keep the wording aligned with the behavior in
engine_docker.go and the preset-network tests so callers understand this special
case.
🪄 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: 9d864580-e182-43fc-a2bb-6f19140a3c40
📒 Files selected for processing (3)
cmd/crossplane/render/engine.gocmd/crossplane/render/engine_docker.gocmd/crossplane/render/engine_docker_test.go
adamwg
left a comment
There was a problem hiding this comment.
LGTM. Agreed this is the right change - no need to expand the Engine interface.
- Fold the multi-batch idempotency test into the existing table-driven Setup cases (per coderabbit.yaml path instructions for *_test.go), and add an explicit empty-slice boundary case alongside the nil one. - Tighten the Engine.Setup interface docstring so it doesn't overstate "first call returns a real cleanup": the cleanup is real only when a call creates a new environment, which excludes calls on engines that are pre-configured to use an externally-managed environment (e.g. the Docker engine constructed with --crossplane-docker-network) and engines that have no environment to clean up (e.g. the local engine). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Ogilvie <679297+jcogilvie@users.noreply.github.com>
|
@coderabbitai addressed your two nitpicks plus the inline finding in ad83077:
|
|
Tip For best results, initiate chat on the files or code changes.
|
…li#159 Upstream PR crossplane/cli#159 — the idempotent-Setup fix this branch relies on — merged to crossplane/cli main at 86f5f7a0. Drop the fork replace directive and pin directly to that commit via the v2.5.0-rc.0.0.20260626181113-86f5f7a0c4bf pseudo-version so this PR can land without waiting for a tagged cli release. The transitive bumps in go.sum (go-openapi/swag/* 0.25.5 → 0.26.0, docker/cli 29.5.3 → 29.6.0, klog/v2 2.130.1 → 2.140.0) come from upstream cli main's newer indirect deps; nothing in crossplane-diff touches those modules directly. Once a tagged cli release containing cli#159 ships (likely v2.4.1 or v2.5.0), a follow-up should bump the pseudo-version to that tag. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
crossplane/cli#159 makes dockerRenderEngine.Setup idempotent in the network-already-set branch by calling injectNetworkAnnotation there too. That removes the need for EngineRenderFn to capture the docker network name off the first batch's annotations and re-stamp it on later batches itself. EngineRenderFn now calls engine.Setup(ctx, newFns) on every render and accumulates the returned cleanups in a slice that Cleanup walks in LIFO order. The first cleanup is the real one; the rest are no-ops, so the order keeps network teardown last without any first-vs-subsequent bookkeeping. The applyNetworkAnnotation helper was also used by function_provider's CROSSPLANE_DIFF_DOCKER_NETWORK env-var path. That's an independent use case (pre-stamping fns so dockerRenderEngine.Setup's don't-overwrite clause picks up the user's network), so the 6-line loop is inlined into applyDockerNetworkAnnotation, its only remaining caller. The go.mod replace directive points at the PR #159 head while it's in review. Drop it once that PR merges and a crossplane/cli release ships with the fix. Fixes #338 Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…li#159 Upstream PR crossplane/cli#159 — the idempotent-Setup fix this branch relies on — merged to crossplane/cli main at 86f5f7a0. Drop the fork replace directive and pin directly to that commit via the v2.5.0-rc.0.0.20260626181113-86f5f7a0c4bf pseudo-version so this PR can land without waiting for a tagged cli release. The transitive bumps in go.sum (go-openapi/swag/* 0.25.5 → 0.26.0, docker/cli 29.5.3 → 29.6.0, klog/v2 2.130.1 → 2.140.0) come from upstream cli main's newer indirect deps; nothing in crossplane-diff touches those modules directly. Once a tagged cli release containing cli#159 ships (likely v2.4.1 or v2.5.0), a follow-up should bump the pseudo-version to that tag. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
…359) * refactor(render): unwind multi-composition workaround using cli#159 crossplane/cli#159 makes dockerRenderEngine.Setup idempotent in the network-already-set branch by calling injectNetworkAnnotation there too. That removes the need for EngineRenderFn to capture the docker network name off the first batch's annotations and re-stamp it on later batches itself. EngineRenderFn now calls engine.Setup(ctx, newFns) on every render and accumulates the returned cleanups in a slice that Cleanup walks in LIFO order. The first cleanup is the real one; the rest are no-ops, so the order keeps network teardown last without any first-vs-subsequent bookkeeping. The applyNetworkAnnotation helper was also used by function_provider's CROSSPLANE_DIFF_DOCKER_NETWORK env-var path. That's an independent use case (pre-stamping fns so dockerRenderEngine.Setup's don't-overwrite clause picks up the user's network), so the 6-line loop is inlined into applyDockerNetworkAnnotation, its only remaining caller. The go.mod replace directive points at the PR #159 head while it's in review. Drop it once that PR merges and a crossplane/cli release ships with the fix. Fixes #338 Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> * build(deps): repin crossplane/cli/v2 to upstream main post-merge of cli#159 Upstream PR crossplane/cli#159 — the idempotent-Setup fix this branch relies on — merged to crossplane/cli main at 86f5f7a0. Drop the fork replace directive and pin directly to that commit via the v2.5.0-rc.0.0.20260626181113-86f5f7a0c4bf pseudo-version so this PR can land without waiting for a tagged cli release. The transitive bumps in go.sum (go-openapi/swag/* 0.25.5 → 0.26.0, docker/cli 29.5.3 → 29.6.0, klog/v2 2.130.1 → 2.140.0) come from upstream cli main's newer indirect deps; nothing in crossplane-diff touches those modules directly. Once a tagged cli release containing cli#159 ships (likely v2.4.1 or v2.5.0), a follow-up should bump the pseudo-version to that tag. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> * chore(lint): apply earthly +reviewable autofixes - render_engine.go: rewrite Cleanup's reverse loop as slices.Backward (Go 1.23+ idiom, suggested by intrange/copyloopvar lint). - function_provider_test.go: regroup the render import added in the workaround unwind alongside the other third-party imports. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> * refactor(render): route docker network env var through upstream EngineFlags Now that we no longer manage the docker network ourselves, the CROSSPLANE_DIFF_DOCKER_NETWORK env var doesn't need its own stamping pass over fetched functions. NewEngineRenderFn reads it once and threads the value through render.EngineFlags.CrossplaneDockerNetwork (crossplane/cli#65). The docker engine then: - runs the crossplane-render container on that network (which fixes the other half of crossplane/cli#75 — our prior implementation only placed function containers on the network, leaving the render container unreachable from inside-a-container deployments); - annotates each fn at Setup time so its container joins it too, honouring the don't-overwrite contract for fns the caller has already pinned. What's deleted: - applyDockerNetworkAnnotation helper. - The DefaultFunctionProvider/CachedFunctionProvider calls into it. - The CachedFunctionProvider cache-hit re-stamp dance and its accompanying TestCachedFunctionProvider_DockerNetworkAnnotation_CacheHit test (cache entries no longer need to track env state). - TestApplyDockerNetworkAnnotation (the helper's gone; engine.Setup owns this behaviour now and has its own coverage upstream). Also tightens the EngineRenderFn / Render docstrings and the startRuntimes-error rollback comment to match the merged upstream Engine.Setup contract (cli#159 + follow-up commit ad8307749). The new phrasing acknowledges that no Setup call may ever return a real cleanup (--crossplane-docker-network preset, or local engine), and frames the rollback as "if this call created the environment" rather than "if this was the very first call". Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> * refactor(render): only call engine.Setup when there are new fns to integrate Per Copilot review feedback on PR #359: we were calling engine.Setup and appending its returned cleanup to e.cleanups on every Render, even when newFns was empty (all fns already started by a prior render). The slice would grow without bound across long-running engines and the Setup call itself was wasted work. Gate the whole Setup+startRuntimes+bookkeeping block on len(newFns) > 0. Renders where every fn is already running now skip straight to building the render request, leaving e.cleanups bounded by the number of distinct fn batches the engine has actually integrated. No behavioural change for the renders that DO integrate new fns: Setup, startRuntimes, the rollback-on-startRuntimes-error path, and the LIFO cleanup ordering all work the same. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> * docs(render): align Render/Cleanup doc comments with current behaviour Two Copilot review comments on PR #359, both valid drift introduced by the prior commit that gated Setup on len(newFns) > 0: - Render's doc said "Setup runs on every invocation" — it doesn't anymore. Rewrite to "Setup runs only on invocations that introduce previously-unseen functions; renders whose fns are all already running skip straight to building the request." - Cleanup's doc said it "releases the docker network" — that's only one possible effect now. The cleanups slice is engine-agnostic, so rewrite to "runs the cleanups accumulated from each engine.Setup call in LIFO order. The effect of those cleanups is engine-specific — docker creates and releases a network; local and pre-configured docker accumulate only no-op cleanups." No code change. Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com> --------- Signed-off-by: Jonathan Ogilvie <jonathan.ogilvie@sumologic.com>
Description of your changes
dockerRenderEngine.Setupshort-circuits whene.networkis already set — either pre-configured via--crossplane-docker-networkor set by a priorSetupcall on the same engine. Until now that short-circuit skippedinjectNetworkAnnotation, leaving the supplied fns un-annotated and their containers unreachable from the render container.This PR annotates fns in that branch too.
injectNetworkAnnotationalready declines to overwrite a fn that carries its ownruntime-docker-networkannotation (PR #65), so users who pin fns to a specific network are unaffected.The result is that
Setupis idempotent for in-process multi-batch rendering: a downstream tool like crossplane-contrib/crossplane-diff that callsRenderacross many compositions in a single process can callSetuponce per composition, and every batch's fns end up on the same network. The first call returns the real cleanup; subsequent calls return no-ops, sodefer cleanup()per batch is safe in LIFO order. Discussion of the alternative (a newAddFunctionsinterface method) is in the issue #96 thread; the short version is that the uniform-per-batch caller shape Option A provides is what callers actually want, and Option B's interface delta doesn't earn its keep.Production change is one line of new behavior in the early-return branch of
dockerRenderEngine.Setup, plus a small variable-declaration tidy. TheEngineinterface signature is unchanged;localRenderEngine,MockEngine, and all callers inxr/opare untouched.Tests are additive:
TestDockerRenderEngineSetupcovers the early-return branch directly (annotates on preset network, preserves user-set annotation, empty-fns boundary), andTestDockerRenderEngineSetupMultiBatchexercises the in-process multi-batch scenario from #96. The create-new-network branch is unchanged and continues to be exercised by the existing integration-style command tests.Docstrings on both
Engine.Setup(interface) anddockerRenderEngine.Setup(impl) are updated to describe the multi-call semantics so callers can rely on them.Fixes #96
I have:
./nix.sh flake checkto ensure this PR is ready for review.Linked a PR or a docs tracking issue to document this change.Addedbackport release-x.ylabels to auto-backport this PR.Need help with this checklist? See the cheat sheet.