fix: handle Scalar types in getLroMetadata for LRO final results#4089
fix: handle Scalar types in getLroMetadata for LRO final results#4089
Conversation
…RO final results Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c187047b-516b-4607-9d9e-5a5a4faf12ea
… types in LRO metadata consumers Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c187047b-516b-4607-9d9e-5a5a4faf12ea
Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c187047b-516b-4607-9d9e-5a5a4faf12ea
…ests Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c187047b-516b-4607-9d9e-5a5a4faf12ea
markcowl
left a comment
There was a problem hiding this comment.
@copilot please pull the latest from main, and make these changes. In some cases, a few properttiers that did not need to have their type changed were changed, please ensure that when these changes are undone, this is also reflected in consuming libraries and emitters, as appropriate.
Please ensure that all tests pass, and that all files are correctly formatted
| metadata.finalResult !== "void" && | ||
| metadata.finalResult.name.length > 0 | ||
| ) { | ||
| // Scalar types (e.g., string) are emitted inline and don't have a definitions entry |
There was a problem hiding this comment.
This is not an acceptable solution. In this instance, we need to create a schema in definitions specifically for this case that we can reference from the final-state-schema.
There was a problem hiding this comment.
Now creating an actual schema definition entry for scalar types using pendingSchemas.getOrAdd(), same approach as for Model types. The schema will be emitted in the definitions section and referenced from final-state-schema. See commit 445591d.
| export interface PollingSuccessProperty extends LogicalOperationStep { | ||
| kind: "pollingSuccessProperty"; | ||
| responseModel: Model; | ||
| responseModel: Model | Scalar; |
There was a problem hiding this comment.
This should not change - a polling endpoint must still have a Model response.
There was a problem hiding this comment.
Reverted PollingSuccessProperty.responseModel back to Model. When the success type is a Scalar, we now use the containing status monitor model as the responseModel, and get the actual scalar type from target.type in getFinalStateVia. See commit 445591d.
|
|
||
| /** The model representing important data returned on a success - clients will want to return this model */ | ||
| logicalResult: Model; | ||
| logicalResult: Model | Scalar; |
There was a problem hiding this comment.
This value also should not change
There was a problem hiding this comment.
Reverted logicalResult back to Model. When the actual result type is a Scalar, logicalResult now uses context.pollingStep.responseModel (the polling response model). See commit 445591d.
…ate schema for scalar final results - Revert LogicalOperationStep.responseModel to Model | UnknownType | VoidType - Revert PollingSuccessProperty.responseModel to Model - Revert LroMetadata.logicalResult to Model - Revert StatusMonitorLinkData.finalModel to exclude Scalar - Fix createLroMetadata to use polling response model for logicalResult when actual result is Scalar - Fix getFinalStateVia to get scalar type from target.type for pollingSuccessProperty - Fix processStatusMonitorLink/Reference to use monitor type as responseModel for scalar success types - Create actual schema definition in typespec-autorest for scalar final results - Revert SdkLroServiceMetadata.logicalResult, SdkLogicalOperationStep.responseModel, SdkPollingSuccessProperty.responseModel back to SdkModelType Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/261c8e6e-53b6-4d06-aa69-1845ad1b74b1
Pulled latest from main and addressed all review feedback in commit 445591d:
All tests pass (276 azure-core, 1218 TCGC, 455 autorest, 263 ARM), formatting and spell check clean. |
markcowl
left a comment
There was a problem hiding this comment.
Make the changes and add an additional test to typespec-autorest that generates long-running-operation-options.final-state-schema and verifies that a correct, named references is created for a scalar final schema.
As always, pull the latest from main, ensure that all tests pass and that formatting is correct for all changed documents.
| ) { | ||
| // Scalar types (e.g., string) need a schema definition entry | ||
| if (metadata.finalResult.kind === "Scalar") { | ||
| const pending = pendingSchemas.getOrAdd(metadata.finalResult, Visibility.Read, () => ({ |
There was a problem hiding this comment.
Here you need to create a unique name for the schema, based on the scalar name, in Pascal case
There was a problem hiding this comment.
Done in bb77a6d. The scalar schema now gets a PascalCase name (e.g., string → String) via getSchemaNameOverride, producing #/definitions/String with { type: "string" } in the definitions section. Added an autorest test that verifies the named reference for an ARM action returning string.
| @@ -271,10 +271,10 @@ | |||
| /** The model representing important data returned on a success - clients will want to return this model. If undefined, | |||
| * then clients would want to return nothing. | |||
There was a problem hiding this comment.
ResponseModel should also allow a scalar type
There was a problem hiding this comment.
Done in bb77a6d. PollingSuccessProperty.responseModel is now Model | Scalar, and LogicalOperationStep.responseModel is Model | Scalar | UnknownType | VoidType. The success type is assigned directly without falling back to the monitor type.
| resOp?.operation === undefined || | ||
| resOp.operation !== "createOrReplace") | ||
| ) { | ||
| model = context.finalStep.responseModel; |
There was a problem hiding this comment.
context.FinalStep.responseModel should also allow a scalar.
There was a problem hiding this comment.
Done in bb77a6d. Simplified to just model = context.finalStep.responseModel since responseModel now carries the Scalar directly. Also fixed the @finalLocation decorator to store Scalar types and filterSuccessType/resolveOperationLocation to propagate them — this was needed for ARM templates like ArmResourceActionAsync<Widget, void, string> to work correctly.
…ar final results, fix @finalLocation for scalars - LogicalOperationStep.responseModel and PollingSuccessProperty.responseModel now accept Scalar - getFinalStateVia simplified: model = context.finalStep.responseModel directly - processStatusMonitorLink/Reference: assign successType directly as responseModel - @finalLocation decorator: handle Scalar types so ARM templates correctly store scalar final results - filterSuccessType: accept and return Scalar types - resolveOperationLocation: return Scalar types from @finalLocation overrides - getStatusMonitorInfo: skip Scalar status monitor types (must be Model) - getTargetModelInformation: return Scalar from link resolution - StatusMonitorLinkData.finalModel: widened to include Scalar - typespec-autorest: create PascalCase named schema definition for scalar final results - typespec-autorest: add test for scalar final-state-schema with ARM operations - TCGC: SdkLogicalOperationStep.responseModel and SdkPollingSuccessProperty.responseModel accept SdkBuiltInType - TCGC: handle Scalar responseModel in pollingSuccessProperty conversion Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c6ec5b71-c1a0-4c8d-9655-49f32e7f5288
Done in bb77a6d. Key changes:
All tests pass (276 azure-core, 456 autorest, 1218 TCGC, 263 ARM), formatting and spell check clean. |
markcowl
left a comment
There was a problem hiding this comment.
Fix the suggested changes, and also add a test to ensure that if an invalid final result type (for example, an enum) is attempted, an appropriate diagnostic is emitted.
As always, please pull the latest from main, ensure that all tests are passing and ensure that all files are correctly formatted (pnpm format)
| }); | ||
| }); | ||
|
|
||
| it("Creates a named final-state-schema definition for scalar final results", async () => { |
There was a problem hiding this comment.
Please enhance this test or add additional tests to ensure that the generated schema name for a unique schema is unique when the schema is unique. Some things that might create a challenge:
- two custom scalars with the same name but different schemas in different namespaces as the final result schema for two operations should result in 2 schemas)
- two custom scalars based on string with different names as the final result schema (should result in two schemas)
- string as the finalResult schema in two operations uses the same schema.
There was a problem hiding this comment.
Done in 9753973. Added all three test cases:
- "Reuses the same schema when string is the finalResult in two operations" — two
ArmResourceActionAsync<Widget, void, string>operations both reference#/definitions/Stringwith a single schema entry - "Creates separate schemas for two custom scalars with different names" —
widgetId extends stringandwidgetTag extends stringproduce#/definitions/WidgetIdand#/definitions/WidgetTagrespectively - "Creates separate schemas for custom scalars with the same name in different namespaces" —
Ns1.customResult extends stringandNs2.customResult extends int32produce two distinct schema references
Also fixed getSchemaNameOverride to use the getOpenAPITypeName-based name with PascalCase (handles namespace-qualified names like Ns1.CustomResult) instead of just the scalar's simple name.
…schema naming tests - Add diagnostic 'lro-status-monitor-invalid-result-property-type' for @lroResult properties with unsupported types (e.g., enums) — validates that only Model, Scalar, or 'unknown' types are valid - Add azure-core test: 'emits diagnostic for invalid @lroResult property type (enum)' - Fix scalar schema naming to use getOpenAPITypeName-based name with PascalCase instead of just the scalar's simple name (supports namespace-qualified names) - Add autorest test: 'Reuses the same schema when string is the finalResult in two operations' - Add autorest test: 'Creates separate schemas for two custom scalars with different names' - Add autorest test: 'Creates separate schemas for custom scalars with the same name in different namespaces' All tests pass: 277 azure-core, 459 autorest, 1218 TCGC, 263 ARM Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/typespec-azure/sessions/c33a9ff2-ed21-4590-9516-347e7a0a9875
Done in 9753973. Added diagnostic |
getLroMetadatafails to recognize scalar types (e.g.,string) as LRO final results. When a status monitor's@lroResultproperty has a scalar type, the metadata pipeline drops it at multiple points because it only checks forModelandIntrinsicType, causingfinalResult,finalEnvelopeResult, and related fields to be incorrect. Additionally, the@finalLocationdecorator did not store Scalar types, preventing ARM templates likeArmResourceActionAsync<Widget, void, string>from correctly resolving scalar final results.typespec-azure-core
@finalLocationdecorator: Now handlesScalartypes so ARM templates correctly store and resolve scalar final results@lroResultvalidation: Added diagnosticlro-status-monitor-invalid-result-property-typethat warns when an@lroResultproperty has an unsupported type (e.g., enum) — validates that onlyModel,Scalar, orunknowntypes are validfilterSuccessType: Accepts and returnsScalartypes alongsideModelandIntrinsicTyperesolveOperationLocation: ReturnsScalartypes from@finalLocationoverridesgetTargetModelInformation: AddedScalarto the type check alongsideModelandUnknownTypewhen reading@lroResultproperty types; returnsScalardirectly from link resolutiongetStatusMonitorInfo: SkipsScalarstatus monitor types (a status monitor must be aModel)createStatusMonitorPollingData: RenamedgetModel→getModelOrScalar, now returnsScalartypes from success propertiescreateLroMetadata:finalResult/finalEnvelopeResultassignment now acceptsmodel.kind === "Scalar";logicalResultfalls back to the polling response model when the result is a ScalargetFinalStateVia: Usescontext.finalStep.responseModeldirectly sinceresponseModelnow carries the Scalar typeprocessStatusMonitorLink/processStatusMonitorReference: Assigns success type directly asresponseModelforpollingSuccessPropertyLogicalOperationStep.responseModelwidened toModel | Scalar | UnknownType | VoidType;PollingSuccessProperty.responseModelwidened toModel | Scalar;LroMetadata.finalResultandfinalEnvelopeResultwidened to includeScalar;StatusMonitorInfo.successTypeandStatusMonitorLinkData.finalModelwidened to includeScalartypespec-client-generator-core
SdkLroServiceMetadata.finalResultandfinalEnvelopeResultwidened to includeSdkBuiltInTypeSdkLroServiceFinalResponse.envelopeResultandresultwidened to includeSdkBuiltInTypeSdkLogicalOperationStep.responseModelandSdkPollingSuccessProperty.responseModelwidened to includeSdkBuiltInTypeupdateUsageOrAccessForLroComponentacceptsScalarparameter typepollingSuccessPropertyconversion handles scalarresponseModelviagetClientTypeWithDiagnosticstypespec-autorest
getFinalStateSchemacreates a proper named schema definition entry for scalar final results with a PascalCase name derived fromgetOpenAPITypeName(e.g.,string→String,Ns1.customResult→Ns1.CustomResult), producing unique#/definitions/references fromfinal-state-schemafinal-state-schemareferences a correctly named scalar schema definition for ARM operations usingArmResourceActionAsync<Widget, void, string>stringas finalResult in two operations reuses the same#/definitions/Stringschema#/definitions/WidgetId,#/definitions/WidgetTag)Reproducer
Original prompt
string, the final result fromgetLroMetadatais not correct. #4081💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.