Honor x-ms-client-flatten in Bicep type generator#12001
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the Radius Autorest-based Bicep type generator to honor x-ms-client-flatten, hoisting fields from flattened object properties (notably the ARM properties envelope) onto the parent resource/object shape to remove .properties. from user-authored Bicep.
Changes:
- Implement
x-ms-client-flattenin the generator for both resource bodies and nested object types, with safe fallbacks (discriminator / name-collision) and warnings. - Add/extend integration + functional tests to validate flattening behavior end-to-end and refresh integration baselines.
- Regenerate published Radius Bicep type artifacts (
generated/**/types.jsonandgenerated/index.json) and add a functional RP test + template using the new flat authoring syntax.
Reviewed changes
Copilot reviewed 5 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/functional-portable/corerp/noncloud/resources/testdata/corerp-resources-container-flatten.bicep | New functional-test Bicep template exercising flat (no .properties) authoring syntax. |
| test/functional-portable/corerp/noncloud/resources/container_flatten_test.go | New RP functional test deploying the flat-syntax template and validating RP + K8s outputs. |
| hack/bicep-types-radius/src/autorest.bicep/src/type-generator.ts | Core generator change: implement safe flattening + warnings in resource and object parsing. |
| hack/bicep-types-radius/src/autorest.bicep/test/flatten/flatten.test.ts | New Jest suite running Autorest end-to-end and asserting flatten contract on emitted types.json. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/specs/basic/resource-manager/Test.Rp1/stable/2021-10-31/spec.json | Extends integration spec with flatten happy-path + discriminator/collision fallback cases. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/generated/basic/test.rp1/2021-10-31/types.json | Refreshed baseline types output reflecting flattening and new test resources. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/generated/basic/test.rp1/2021-10-31/types.md | Refreshed markdown baseline reflecting flattened shapes and new resources. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/generated/basic/test.rp1/2021-10-31/docs/testtype1.md | New/updated per-resource docs baseline for flattened TestType1. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/generated/basic/test.rp1/2021-10-31/docs/testtype2.md | New per-resource docs baseline for discriminator fallback TestType2. |
| hack/bicep-types-radius/src/autorest.bicep/test/integration/generated/basic/test.rp1/2021-10-31/docs/testtype3.md | New per-resource docs baseline for collision fallback TestType3. |
| hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.json | Regenerated published types with flattened resource bodies (notably removing wrapper property objects). |
| hack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.json | Regenerated published types with flattened resource bodies. |
| hack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.json | Regenerated published types with flattened resource bodies. |
| hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json | Regenerated published types with flattened resource bodies. |
| hack/bicep-types-radius/generated/index.json | Updates index refs to match regenerated type-array indices. |
| beforeAll(async () => { | ||
| const stagingDir = path.join(__dirname, "temp"); | ||
| types = await generate(stagingDir); | ||
| }, 120000); |
| // Functional test for x-ms-client-flatten support in the Bicep type generator. | ||
| // | ||
| // This test runs autorest end-to-end against the shared "basic" spec (which | ||
| // includes resources exercising the happy-path flatten, the polymorphic-child | ||
| // fallback, and the name-collision fallback) and asserts directly on the | ||
| // generated types.json. Unlike the integration test (which only baseline-diffs | ||
| // the output), this test fails with a focused error message if the flatten | ||
| // contract regresses. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #12001 +/- ##
=======================================
Coverage 52.13% 52.13%
=======================================
Files 734 734
Lines 46704 46704
=======================================
Hits 24350 24350
Misses 20017 20017
Partials 2337 2337 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Implements flattening for properties annotated with x-ms-client-flatten=true in the Radius autorest.bicep type generator, eliminating the .properties. envelope from Bicep authoring for Radius resources. Generator changes (hack/bicep-types-radius/src/autorest.bicep): - Add isFlattenSafe, flagsForFlattenedChild, expandFlattenedInto helpers in type-generator.ts. - Wire flattening into processResourceBody and parseObjectType so the extension is honored on both the resource envelope and on nested objects. - Fall back to the nested representation (with a warning) when flattening would lose information: schemas using a discriminator (polymorphic variants) or schemas whose flattened child names would collide with an existing parent property. - Propagate parent ReadOnly/WriteOnly flags to flattened children; Required/Identifier/DeployTimeConstant are not propagated. Tests: - Extend the autorest.bicep integration spec with TestType1 (happy path), TestType2 (discriminator fallback), TestType3 (name-collision fallback) and refresh checked-in baselines. - Add programmatic functional test test/flatten/flatten.test.ts that asserts the flatten contract end-to-end against the regenerated types.json. - Regenerate Radius Bicep types (applications.core, datastores, messaging, radius.core, generated/index.json) so users get the flat syntax. - Add Radius functional test Test_Container_Flatten under test/functional-portable/corerp/noncloud/resources demonstrating the flat authoring syntax for Applications.Core/applications and Applications.Core/containers. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Extend the functional test template with output statements that read flattened fields back from the deployed resources (app.environment, container.application, container.container.image, container.container.ports.web.containerPort). If the type generator had failed to hoist any of these, Bicep compilation would fail and the deploy step would error out, so the outputs act as a smoke test that the flat syntax works symmetrically for authoring and for cross-resource references. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
…ences Replace the bicep `output` statements with a second container resource (`ctnr2`) that declares its application, image, and listening port by reading flattened fields directly off the first container (`ctnr`). Also rename the first container's bicep symbol from `container` to `ctnr` to disambiguate it from the inner `container` field. This is a closer analogue to how real templates consume flattened fields from other resources. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
52d2c42 to
672cffb
Compare
Preserve the writable properties envelope (so existing Bicep templates compile unchanged and the wire payload still matches the RP's OpenAPI schema) while ALSO hoisting each child of properties onto the parent object as a ReadOnly alias. This gives users a clean reference syntax (e.g. ctnr.container.image) without breaking authoring. - type-generator.ts: flagsForFlattenedChild forces ReadOnly and strips Required; processResourceBody and parseObjectType no longer skip emitting 'properties' after hoisting children. - flatten.test.ts: assert hoisted children are ReadOnly + properties envelope is preserved. - Re-recorded integration baselines; regenerated Radius Bicep types. - Functional test authors via legacy envelope and reads via flat aliases. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Implements response-side flatten in the ARM-RPC layer so Bicep templates can reference flat field names on Radius resources (e.g. ctnr.application instead of ctnr.properties.application). This pairs with the additive ReadOnly aliases emitted by the Bicep type generator so that flat references actually resolve at deploy time via ARM's reference() function. - New helper flattenPropertiesAliases walks a marshaled body, splats each child of 'properties' onto the parent object as an alias, and preserves the original 'properties' envelope unchanged. Reserved envelope keys are never overwritten and existing top-level keys win on collision. - Wired into OKResponse, CreatedResponse, CreatedAsyncResponse and AcceptedAsyncResponse via a shared marshalResourceBody helper. Flatten is best-effort: on error the request still succeeds with the unflattened body. - PaginatedList bodies are recursed; non-resource bodies (async operation status, error envelopes) are pass-through. - 14 new table-driven unit tests + alias-identity test. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Documents the response-side flatten + Bicep type aliases approach, non-goals, reserved-keys list, collision rule, alternatives considered, risks, and test coverage. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Decoding each resource response on the wire and splatting properties to
the top level has no effect on ARM reference() resolution, because the
deployment engine rebuilds the resource shape from its typed model
before evaluating expressions. The wire-level aliases are silently
dropped on the way to the expression engine.
The flat-reference behavior now lives in the companion
deployment-engine change
(azure-octo/deployment-engine#willdavsmith/flatten-properties-aliases),
which flattens the JToken stored in referenceValueLookup so that
reference('r').foo resolves to reference('r').properties.foo.
This commit reverts the RP-side flatten helper and its wiring on the
four success Apply methods, and rewrites the design note to reflect
the deployment-engine approach.
Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Dropping the design note from this PR. The feature is documented in the PR body and the existing in-code commentary in the Bicep type generator (hack/bicep-types-radius/src/autorest.bicep/src/type-generator.ts) and the deployment-engine flatten helper. Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Radius functional test overviewClick here to see the test run details
Test Status⌛ Building Radius and pushing container images for functional tests... |
Description
Implements
x-ms-client-flattenin the Radius Bicep type generator so the ARM.properties.envelope no longer leaks into user-authored Bicep templates.Before:
After:
The annotation is already present on every Radius resource (via
TrackedResourceRequiredintypespec/radius/v1/trackedresource.tsp); the generator just had not been honoring it.Type of change
Fixes: #12000
Contributor checklist
Changes
Generator (
hack/bicep-types-radius/src/autorest.bicep)src/type-generator.tsisFlattenSafe,flagsForFlattenedChild,expandFlattenedInto.processResourceBody(resource envelope) andparseObjectType(nested objects).logWarning) when flattening would lose information:ReadOnly/WriteOnlyflags are OR'd into each flattened child.Required/Identifier/DeployTimeConstantare intentionally not propagated.Tests
test/integration/specs/basic/.../spec.json— extended with:TestType1— happy-path flatten on a resource body.TestType2— polymorphic child, exercises the discriminator fallback.TestType3— child property names collide with the resource envelope, exercises the collision fallback.test/integration/generated/basic/...) refreshed.test/flatten/flatten.test.tsasserts the contract end-to-end: walks the generatedtypes.jsonand verifies hoisting, fallback emission, and warning behavior.Regenerated Bicep types
Ran
make generate-bicep-types. Updated:hack/bicep-types-radius/generated/applications/applications.core/2023-10-01-preview/types.jsonhack/bicep-types-radius/generated/applications/applications.datastores/2023-10-01-preview/types.jsonhack/bicep-types-radius/generated/applications/applications.messaging/2023-10-01-preview/types.jsonhack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.jsonhack/bicep-types-radius/generated/index.jsonSpot-checked: e.g.
Applications.Core/containersnow exposesapplication,container,connections,extensions,environment,identity,restartPolicy,runtimes,resources,provisioningState,statusdirectly on the resource body, with noApplicationProperties/ContainerPropertieswrapper.Functional test
test/functional-portable/corerp/noncloud/resources/container_flatten_test.go+testdata/corerp-resources-container-flatten.bicep—Test_Container_Flattendeploys an Application + Container written entirely in the flat syntax (no.properties.) and validates the RP resources and the rendered pod in the app namespace. The bicep template only compiles against the regenerated types, so the test doubles as a regression guard.Compatibility
.properties.{ ... }continue to compile becausepropertieswas already required and is preserved when fallbacks fire. However, for resources where flattening succeeds (which is the vast majority), the legacyproperties: { ... }syntax will no longer be valid — users must adopt the flat syntax for those resources. This is the intended UX change.Deployment-engine dependency (resolved)
The deploy-time half of this feature shipped in azure-octo/deployment-engine#583 (merged), which flattens the JToken stored in the reference value lookup so flat references like
reference('myCtnr').applicationresolve at deploy time. The:latestghcr.io/radius-project/deployment-engineimage picks up the fix automatically.Validated end-to-end on a local kind cluster prior to merge:
Test_Container_Flattenpasses.