Skip to content

Conversation

@ArcturusZhang
Copy link
Member

@ArcturusZhang ArcturusZhang commented Dec 1, 2025

Fixes #3595
Fixes #3623

Previously the segment default was hard-coded in a function checking if a segment in path is a variable.
This PR modifies it to accept an optional extra singletonResourceName parameter - if match, we will return true as variable segment.

This PR also updates the ResolvedResource API to add a new property singletonResourceNames

@microsoft-github-policy-service microsoft-github-policy-service bot added the lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library label Dec 1, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 1, 2025

Open in StackBlitz

npm i https://pkg.pr.new/Azure/typespec-azure/@azure-tools/typespec-azure-resource-manager@3594

commit: 956cd97

@azure-sdk
Copy link
Collaborator

azure-sdk commented Dec 1, 2025

All changed packages have been documented.

  • @azure-tools/typespec-azure-resource-manager
Show changes

@azure-tools/typespec-azure-resource-manager - fix ✏️

Fix issues in resolveArmResources when we have singleton resource with a customized name

@azure-sdk
Copy link
Collaborator

azure-sdk commented Dec 1, 2025

You can try these changes here

🛝 Playground 🌐 Website

instanceSegments.push(segments[i]);
instanceSegments.push(segments[i + 1]);
} else if (i + 1 === segments.length) {
if (i + 1 === segments.length) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is safe. We should look for the model being marked as a singleton.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made some updates around this part, please take a look again.

Comment on lines 662 to 665
if (i + 1 === segments.length - 1 && isVariableSegment(segments[i + 1], singletonResourceName)) {
typeSegments.push(segments[i]);
instanceSegments.push(segments[i]);
instanceSegments.push(segments[i + 1]);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we only consider the singletonResourceName when the current segment is the last segement.

Comment on lines 259 to +268
path: "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{providerName}/{resourceType}/{resourceName}/{childResourceType}/{childResourceName}/providers/Microsoft.Bar/bars/{barName}/basses/default/actionName/doSomething/doSomethingElse/andAnotherThing",
kind: "read",
singletonResourceName: "default",
expected: {
resourceType: {
provider: "Microsoft.Bar",
types: ["bars", "basses"],
types: ["bars"],
},
resourceInstancePath:
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{providerName}/{resourceType}/{resourceName}/{childResourceType}/{childResourceName}/providers/Microsoft.Bar/bars/{barName}/basses/default",
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{providerName}/{resourceType}/{resourceName}/{childResourceType}/{childResourceName}/providers/Microsoft.Bar/bars/{barName}",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the result changed because of the change above.
In this path, we have a default but it is not at the end.

Also I have concerns: why would we try to rebuild the resourceInstancePath from the path any way? Should we just use the READ request path as the resource instance path? I think ARM did this in their logic, and resource type is then built out of this path.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think if this makes sense that I changed the result? Or we should just remove this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created this issue to track this: #3620

@ArcturusZhang ArcturusZhang marked this pull request as ready for review December 5, 2025 07:21
@markcowl markcowl changed the base branch from main to release/december-2025 December 11, 2025 18:02
@markcowl markcowl changed the base branch from release/december-2025 to main December 11, 2025 18:03
Copy link
Member

@markcowl markcowl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, we need to target this PR at release/december-2025,

scond I have a couple of minor comments, and a slight algorithmic change:

  • We should check for 'default' as well as the resourceInstance Name from the resource type
  • We should check against the resourceInstanceName (and default) whwnever we are looking to see that an enven-numbered segment is a variable segment

I think this will give us better results in legacy scenarios


function isVariableSegment(segment: string): boolean {
return (segment.startsWith("{") && segment.endsWith("}")) || segment === "default";
function isVariableSegment(segment: string, singletonResourceName?: string): boolean {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to do a lowercase transform over both the segment and the name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think we could do this over an array of singleton resource names, but this isn't required for this PR, we cna add it when we add singleton recognition for union and enum resource name types

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also continue to use 'default' as a singleton resource name, in addition to the singleton resource name from getSingletonKey


if (i + 1 < segments.length && isVariableSegment(segments[i + 1])) {
// if the next segment is the last segment
if (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we change this logic, we will fix the issues below - it makes sense that the singleton resource name should just always be checked when looking for a variable segment.

I think there is still a case to think about, when multiple resources in the resource type are singletons

expect(employee).toMatchObject({
kind: "Tracked",
providerNamespace: "Microsoft.ContosoProviderHub",
type: expect.anything(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should check the resourceInstance path and the singleton names here as well

expect(employee).toMatchObject({
kind: "Tracked",
providerNamespace: "Microsoft.ContosoProviderHub",
type: expect.anything(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should check singleton resource names and resourceInstancePath

providerNamespace: "Microsoft.ContosoProviderHub",
type: expect.anything(),
resourceType: {
provider: "Microsoft.ContosoProviderHub",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should add in resourceInstancePath and singletonNames checks

@ArcturusZhang ArcturusZhang force-pushed the introduce-tests-for-bug branch from 956cd97 to 155ce30 Compare December 12, 2025 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[resource-manager] needs singleton resource information in each resource [Bug]: SingletonResource is not properly resolved in resolveArmResources

3 participants