fix(tfjson): Reset Computed flag for SchemaNestingModeSingle blocks with required children#593
fix(tfjson): Reset Computed flag for SchemaNestingModeSingle blocks with required children#593rwwiv wants to merge 1 commit intocrossplane:mainfrom
Conversation
📝 WalkthroughWalkthroughtfJSONBlockTypeToV2Schema now differentiates collection nesting modes (Set/List/Map) — inferring Computed when MinItems and MaxItems are both 0 — from Single/Group blocks, which are treated as list-like (TypeList, MinItems=0, MaxItems=1) with Required/Optional derived from whether the block has required children. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 🧪 Unit Test Generation v2 is now available!We have significantly improved our unit test generation capabilities. To enable: Add this to your reviews:
finishing_touches:
unit_tests:
enabled: trueTry it out by using the Have feedback? Share your thoughts on our Discord thread! 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: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/types/conversion/tfjson/tfjson.go (1)
170-179: Add regression test for required-child Single blocks.The behavior introduced around Line 174 should be locked in with a unit test to prevent regressions (Computed must be false when a Single block has required children).
🧪 Suggested test (standard Go testing)
+// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io> +// +// SPDX-License-Identifier: Apache-2.0 + +package tfjson + +import ( + "testing" + + tfjsonsdk "github.com/hashicorp/terraform-json" + "github.com/zclconf/go-cty/cty" +) + +func TestTFJSONBlockTypeToV2Schema_SingleRequiredChildResetsComputed(t *testing.T) { + nb := &tfjsonsdk.SchemaBlockType{ + NestingMode: tfjsonsdk.SchemaNestingModeSingle, + MinItems: 0, + MaxItems: 0, + Block: &tfjsonsdk.SchemaBlock{ + Attributes: map[string]*tfjsonsdk.SchemaAttribute{ + "name": {Required: true, AttributeType: cty.String}, + }, + }, + } + + got := tfJSONBlockTypeToV2Schema(nb) + + if got.Computed { + t.Fatalf("expected Computed=false for required-child single block") + } + if !got.Required || got.Optional { + t.Fatalf("expected Required=true and Optional=false") + } + if got.MinItems != 1 || got.MaxItems != 1 { + t.Fatalf("expected MinItems/MaxItems=1, got %d/%d", got.MinItems, got.MaxItems) + } +} +``` </details> As per coding guidelines, "All Upjet code must be covered by tests; do not use Ginkgo or third-party testing libraries, use only standard Go testing". </blockquote></details> </blockquote></details>
b78ed93 to
ea49ff6
Compare
When converting tfjson block types to SDK v2 schema, the Computed flag was being inferred as true when MinItems==0 && MaxItems==0. This heuristic works for SDK v2 collection types (List/Set/Map) but is incorrect for Plugin Framework resources using SchemaNestingModeSingle. Plugin Framework resources default MinItems/MaxItems to 0 for single blocks even when they contain user-configurable attributes. This caused blocks like 'metadata' and 'spec' to be incorrectly marked as Computed, excluding them from ForProvider/InitProvider parameters and only including them in Observation. This fix moves the Computed=true inference to only apply to collection nesting modes (List/Set/Map), not to SchemaNestingModeSingle. For single blocks, we now rely solely on hasRequiredChild() to determine Required/Optional, leaving Computed=false by default. This allows Plugin Framework resources (e.g., Grafana App Platform resources like AlertruleV0Alpha1) to properly expose their nested blocks in the CRD's forProvider schema. Also adds comprehensive unit tests for tfJSONBlockTypeToV2Schema and hasRequiredChild functions. Signed-off-by: Will Wernert <william.wernert@grafana.com>
ea49ff6 to
5bea688
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/types/conversion/tfjson/tfjson.go (1)
176-191:⚠️ Potential issue | 🟠 MajorThe heuristic
Required = hasRequiredChild(nb)is incorrect for Plugin Framework semantics and will over-constrain the CRD.In Terraform Plugin Framework,
SingleNestedBlockandSingleNestedAttribute(Group) have no built-inRequiredflag on the block itself—blocks are optional by default. Required child attributes do not imply the block is required; they only apply when the block is present. To make a block required in Plugin Framework, you must use validators (e.g.,objectvalidator.IsRequired()).The current code marks a block as
Requiredwhenever it contains required children, which incorrectly forces optional blocks to be required in the generated schema. This breaks configurations where the block is legitimately optional.Fix: Determine block Required/Optional status from the tfjson schema itself (if available), not from child attribute requirements. If tfjson does not encode block-level Required, consider whether the absence of a
Requiredindicator in the Plugin Framework schema should default toOptional = true.
This PR temporarily replaces upjet with the version from this PR: crossplane/upjet#593 to generate these resources properly.
This PR temporarily replaces upjet with the version from this PR: crossplane/upjet#593 to generate these resources properly.
Summary
Fixes an issue where
SchemaNestingModeSingleblocks from Plugin Framework resources were incorrectly marked asComputed=true, causing them to be excluded fromForProvider/InitProviderparameters and only appear inObservation.Problem
In
tfJSONBlockTypeToV2Schema(), whenMinItems==0 && MaxItems==0, the block was being marked asComputed=true:This heuristic works for SDK v2 collection types (List/Set/Map) where
MinItems=0, MaxItems=0typically indicates a computed-only collection. However, Plugin Framework resources usingSchemaNestingModeSingledefault toMinItems=0, MaxItems=0even for user-configurable blocks.This caused blocks like
metadataandspecto be markedComputed=true, which makesIsObservation()returntrue, excluding them from the generated Parameters struct.Solution
Move the
Computed=trueinference to only apply to collection nesting modes (Set/List/Map), not toSchemaNestingModeSingle. For single blocks, we now rely solely onhasRequiredChild()to determine Required/Optional, leaving Computed=false by default.Testing
Added comprehensive unit tests for
tfJSONBlockTypeToV2SchemaandhasRequiredChild:SchemaNestingModeSinglewith required children →Computed=false,Required=trueSchemaNestingModeSinglewith only optional children →Computed=false,Optional=trueSchemaNestingModeSinglewith empty/nil blockSchemaNestingModeSinglewith nested blocks containing required childrenSchemaNestingModeList/Set/MapwithMinItems=0, MaxItems=0→Computed=true(preserves existing behavior)SchemaNestingModeListwithMinItems=1→Computed=falseImpact
This fix is particularly important for Terraform Plugin Framework resources. For example, the Grafana provider's App Platform resources (
grafana_apps_rules_alertrule_v0alpha1,grafana_apps_rules_recordingrule_v0alpha1, etc.) havemetadataandspecblocks that were incorrectly excluded fromforProviderin the generated CRDs.Before this fix:
After this fix:
SDK v2-based resources are unaffected because they typically use
MinItems=1, MaxItems=1for required single blocks, so they never hit theMinItems == 0 && MaxItems == 0path.Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.