Skip to content

Commit b6c9e17

Browse files
authored
Merge pull request #642 from microsoft/tm/tagFixes
Adds action/function suffix to tag names for action/function operations
2 parents 4db0cbc + 494f302 commit b6c9e17

12 files changed

+238
-140
lines changed

src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
<TargetFrameworks>netstandard2.0</TargetFrameworks>
1616
<PackageId>Microsoft.OpenApi.OData</PackageId>
1717
<SignAssembly>true</SignAssembly>
18-
<Version>1.7.1</Version>
18+
<Version>1.7.2</Version>
1919
<Description>This package contains the codes you need to convert OData CSDL to Open API Document of Model.</Description>
2020
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
2121
<PackageTags>Microsoft OpenApi OData EDM</PackageTags>
2222
<RepositoryUrl>https://github.com/Microsoft/OpenAPI.NET.OData</RepositoryUrl>
2323
<PackageReleaseNotes>
24-
- Further fix for generating unique operation ids for navigation property paths with composable overloaded functions #596
24+
- Adds action/function suffix to tag names for actions/functions operations in #642
2525
</PackageReleaseNotes>
2626
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
2727
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>
@@ -66,4 +66,4 @@
6666
</EmbeddedResource>
6767
</ItemGroup>
6868

69-
</Project>
69+
</Project>

src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,11 @@ protected override void SetBasicInfo(OpenApiOperation operation)
8181
// duplicates in entity vs entityset functions/actions
8282

8383
List<string> identifiers = new();
84-
string pathHash = string.Empty;
8584
foreach (ODataSegment segment in Path.Segments)
8685
{
8786
if (segment is ODataKeySegment keySegment)
8887
{
89-
if (!keySegment.IsAlternateKey)
88+
if (!keySegment.IsAlternateKey)
9089
{
9190
identifiers.Add(segment.EntityType.Name);
9291
continue;
@@ -102,18 +101,6 @@ protected override void SetBasicInfo(OpenApiOperation operation)
102101
identifiers.Add(keySegment.Identifier);
103102
}
104103
}
105-
else if (segment is ODataOperationSegment opSegment)
106-
{
107-
if (opSegment.Operation is IEdmFunction function && Context.Model.IsOperationOverload(function))
108-
{
109-
// Hash the segment to avoid duplicate operationIds
110-
pathHash = string.IsNullOrEmpty(pathHash)
111-
? opSegment.GetPathHash(Context.Settings)
112-
: (pathHash + opSegment.GetPathHash(Context.Settings)).GetHashSHA256().Substring(0, 4);
113-
}
114-
115-
identifiers.Add(segment.Identifier);
116-
}
117104
else
118105
{
119106
identifiers.Add(segment.Identifier);
@@ -122,13 +109,21 @@ protected override void SetBasicInfo(OpenApiOperation operation)
122109

123110
string operationId = string.Join(".", identifiers);
124111

125-
if (!string.IsNullOrEmpty(pathHash))
112+
if (EdmOperation.IsAction())
126113
{
127-
operation.OperationId = operationId + "-" + pathHash;
114+
operation.OperationId = operationId;
128115
}
129116
else
130117
{
131-
operation.OperationId = operationId;
118+
if (Path.LastSegment is ODataOperationSegment operationSegment &&
119+
Context.Model.IsOperationOverload(operationSegment.Operation))
120+
{
121+
operation.OperationId = operationId + "-" + Path.LastSegment.GetPathHash(Context.Settings);
122+
}
123+
else
124+
{
125+
operation.OperationId = operationId;
126+
}
132127
}
133128
}
134129

@@ -152,29 +147,36 @@ protected override void SetTags(OpenApiOperation operation)
152147
}
153148

154149
/// <summary>
155-
/// Genrates the tag name for the operation.
150+
/// Genrates the tag name for the operation. Adds Action or Function name to the tag name if the operation is an action or function.
156151
/// </summary>
157152
/// <param name="tagName">The generated tag name.</param>
158153
/// <param name="skip">The number of segments to skip.</param>
159154
private void GenerateTagName(out string tagName, int skip = 1)
160-
{
155+
{
161156
var targetSegment = Path.Segments.Reverse().Skip(skip).FirstOrDefault();
162157

163158
switch (targetSegment)
164159
{
165160
case ODataNavigationPropertySegment:
166161
tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context);
167162
break;
168-
case ODataOperationSegment:
169163
case ODataOperationImportSegment:
170164
// Previous segmment could be a navigation property or a navigation source segment
171165
case ODataKeySegment:
172166
skip += 1;
173167
GenerateTagName(out tagName, skip);
174168
break;
175-
// ODataNavigationSourceSegment
176169
default:
177170
tagName = NavigationSource.Name + "." + NavigationSource.EntityType().Name;
171+
if (EdmOperation.IsAction())
172+
{
173+
tagName += ".Actions";
174+
}
175+
else if (EdmOperation.IsFunction())
176+
{
177+
tagName += ".Functions";
178+
}
179+
178180
break;
179181
}
180182
}
@@ -192,7 +194,7 @@ protected override void SetParameters(OpenApiOperation operation)
192194
}
193195

194196
/// <inheritdoc/>
195-
protected override void SetResponses(OpenApiOperation operation)
197+
protected override void SetResponses(OpenApiOperation operation)
196198
{
197199
operation.Responses = Context.CreateResponses(EdmOperation);
198200
base.SetResponses(operation);
@@ -292,10 +294,10 @@ protected override void SetCustomLinkRelType()
292294
{
293295
LinkRelKey key = EdmOperation.IsAction() ? LinkRelKey.Action : LinkRelKey.Function;
294296
Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out string linkRelValue);
295-
CustomLinkRel = linkRelValue;
297+
CustomLinkRel = linkRelValue;
296298
}
297299
}
298-
300+
299301
/// <inheritdoc/>
300302
protected override void SetExternalDocs(OpenApiOperation operation)
301303
{

test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void CreateOperationForEdmActionReturnsCorrectOperation()
4040
Assert.Equal("Details of the shared trip.", operation.Description);
4141
Assert.NotNull(operation.Tags);
4242
var tag = Assert.Single(operation.Tags);
43-
Assert.Equal("People.Person", tag.Name);
43+
Assert.Equal("People.Person.Actions", tag.Name);
4444

4545
Assert.NotNull(operation.Parameters);
4646
Assert.Single(operation.Parameters);
@@ -79,7 +79,7 @@ public void CreateOperationForEdmActionReturnsCorrectOperationHierarchicalClass(
7979
Assert.Equal($"Invoke action {actionName}", operation.Summary);
8080
Assert.NotNull(operation.Tags);
8181
var tag = Assert.Single(operation.Tags);
82-
Assert.Equal($"{entitySetName}.AccountApiModel", tag.Name);
82+
Assert.Equal($"{entitySetName}.AccountApiModel.Actions", tag.Name);
8383

8484
Assert.NotNull(operation.Parameters);
8585
Assert.Single(operation.Parameters);

test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionOperationHandlerTests.cs

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public void CreateOperationForEdmFunctionReturnsCorrectOperation(bool useHTTPSta
100100
Assert.Equal("Invoke function GetFavoriteAirline", operation.Summary);
101101
Assert.NotNull(operation.Tags);
102102
var tag = Assert.Single(operation.Tags);
103-
Assert.Equal("People.Person", tag.Name);
103+
Assert.Equal("People.Person.Functions", tag.Name);
104104

105105
Assert.NotNull(operation.Parameters);
106106
Assert.Single(operation.Parameters);
@@ -138,7 +138,7 @@ public void CreateOperationForEdmFunctionReturnsCorrectOperationHierarchicalClas
138138
Assert.Equal("Collection of contract attachments.", operation.Description);
139139
Assert.NotNull(operation.Tags);
140140
var tag = Assert.Single(operation.Tags);
141-
Assert.Equal($"{entitySetName}.AccountApiModel", tag.Name);
141+
Assert.Equal($"{entitySetName}.AccountApiModel.Functions", tag.Name);
142142

143143
Assert.NotNull(operation.Parameters);
144144
Assert.Equal(6, operation.Parameters.Count); // id, top, skip, count, search, filter
@@ -378,10 +378,10 @@ public void CreateOperationForComposableOverloadEdmFunctionReturnsCorrectOperati
378378

379379
if (enableOperationId)
380380
{
381-
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-c53d", operation1.OperationId);
382-
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-4d93", operation2.OperationId);
383-
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-a2b2", operation3.OperationId);
384-
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-7bea", operation4.OperationId);
381+
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-6b6d", operation1.OperationId);
382+
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-2636", operation2.OperationId);
383+
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-6b6d", operation3.OperationId);
384+
Assert.Equal("Customers.Customer.MyFunction1.MyFunction2-2636", operation4.OperationId);
385385
}
386386
else
387387
{
@@ -575,35 +575,35 @@ public void CreateOperationForFunctionWithDateTimeParametersReturnsCorrectPathIt
575575
}
576576

577577
[Fact]
578-
public void CreateFunctionOperationWithAlternateKeyReturnsCorrectOperationId()
579-
{
580-
// Arrange
578+
public void CreateFunctionOperationWithAlternateKeyReturnsCorrectOperationId()
579+
{
580+
// Arrange
581581
IEdmModel model = EdmModelHelper.GraphBetaModel;
582-
ODataContext context = new(model, new OpenApiConvertSettings()
582+
ODataContext context = new(model, new OpenApiConvertSettings()
583583
{
584-
EnableOperationId = true
584+
EnableOperationId = true
585585
});
586586

587-
IEdmSingleton singleton = model.EntityContainer.FindSingleton("communications");
588-
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "cloudCommunications");
589-
IEdmNavigationProperty navProp = entityType.DeclaredNavigationProperties().First(c => c.Name == "onlineMeetings");
590-
IEdmOperation action = model.SchemaElements.OfType<IEdmOperation>().First(f => f.Name == "sendVirtualAppointmentReminderSms");
591-
IDictionary<string, string> keyMappings = new Dictionary<string, string> { { "joinWebUrl", "joinWebUrl" } };
592-
593-
ODataPath path = new(new ODataNavigationSourceSegment(singleton),
594-
new ODataNavigationPropertySegment(navProp),
595-
new ODataKeySegment(entityType, keyMappings)
596-
{
597-
IsAlternateKey = true
598-
},
599-
new ODataOperationSegment(action));
600-
587+
IEdmSingleton singleton = model.EntityContainer.FindSingleton("communications");
588+
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "cloudCommunications");
589+
IEdmNavigationProperty navProp = entityType.DeclaredNavigationProperties().First(c => c.Name == "onlineMeetings");
590+
IEdmOperation action = model.SchemaElements.OfType<IEdmOperation>().First(f => f.Name == "sendVirtualAppointmentReminderSms");
591+
IDictionary<string, string> keyMappings = new Dictionary<string, string> { { "joinWebUrl", "joinWebUrl" } };
592+
593+
ODataPath path = new(new ODataNavigationSourceSegment(singleton),
594+
new ODataNavigationPropertySegment(navProp),
595+
new ODataKeySegment(entityType, keyMappings)
596+
{
597+
IsAlternateKey = true
598+
},
599+
new ODataOperationSegment(action));
600+
601601
// Act
602-
var operation = _operationHandler.CreateOperation(context, path);
603-
604-
// Assert
605-
Assert.NotNull(operation);
606-
Assert.Equal("communications.onlineMeetings.joinWebUrl.sendVirtualAppointmentReminderSms", operation.OperationId);
602+
var operation = _operationHandler.CreateOperation(context, path);
603+
604+
// Assert
605+
Assert.NotNull(operation);
606+
Assert.Equal("communications.onlineMeetings.joinWebUrl.sendVirtualAppointmentReminderSms", operation.OperationId);
607607
}
608608
}
609-
}
609+
}

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@
591591
"/Documents({Id})/Default.Upload": {
592592
"post": {
593593
"tags": [
594-
"Documents.DocumentDto"
594+
"Documents.DocumentDto.Actions"
595595
],
596596
"summary": "Invoke action Upload",
597597
"operationId": "Documents.DocumentDto.Upload",
@@ -3519,7 +3519,7 @@
35193519
"/Tasks({Id})/Default.Upload": {
35203520
"post": {
35213521
"tags": [
3522-
"Tasks.DocumentDto"
3522+
"Tasks.DocumentDto.Actions"
35233523
],
35243524
"summary": "Invoke action Upload",
35253525
"operationId": "Tasks.DocumentDto.Upload",
@@ -6275,6 +6275,10 @@
62756275
"name": "Documents.DocumentDto",
62766276
"x-ms-docs-toc-type": "page"
62776277
},
6278+
{
6279+
"name": "Documents.DocumentDto.Actions",
6280+
"x-ms-docs-toc-type": "container"
6281+
},
62786282
{
62796283
"name": "Documents.RevisionDto",
62806284
"x-ms-docs-toc-type": "page"
@@ -6315,6 +6319,10 @@
63156319
"name": "Tasks.DocumentDto",
63166320
"x-ms-docs-toc-type": "page"
63176321
},
6322+
{
6323+
"name": "Tasks.DocumentDto.Actions",
6324+
"x-ms-docs-toc-type": "container"
6325+
},
63186326
{
63196327
"name": "Tasks.RevisionDto",
63206328
"x-ms-docs-toc-type": "page"

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ paths:
413413
'/Documents({Id})/Default.Upload':
414414
post:
415415
tags:
416-
- Documents.DocumentDto
416+
- Documents.DocumentDto.Actions
417417
summary: Invoke action Upload
418418
operationId: Documents.DocumentDto.Upload
419419
parameters:
@@ -2495,7 +2495,7 @@ paths:
24952495
'/Tasks({Id})/Default.Upload':
24962496
post:
24972497
tags:
2498-
- Tasks.DocumentDto
2498+
- Tasks.DocumentDto.Actions
24992499
summary: Invoke action Upload
25002500
operationId: Tasks.DocumentDto.Upload
25012501
parameters:
@@ -4545,6 +4545,8 @@ tags:
45454545
x-ms-docs-toc-type: page
45464546
- name: Documents.DocumentDto
45474547
x-ms-docs-toc-type: page
4548+
- name: Documents.DocumentDto.Actions
4549+
x-ms-docs-toc-type: container
45484550
- name: Documents.RevisionDto
45494551
x-ms-docs-toc-type: page
45504552
- name: Documents.DocumentTagRelDto
@@ -4565,6 +4567,8 @@ tags:
45654567
x-ms-docs-toc-type: page
45664568
- name: Tasks.DocumentDto
45674569
x-ms-docs-toc-type: page
4570+
- name: Tasks.DocumentDto.Actions
4571+
x-ms-docs-toc-type: container
45684572
- name: Tasks.RevisionDto
45694573
x-ms-docs-toc-type: page
45704574
- name: Tasks.DocumentTagRelDto

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@
663663
"description": "Provides operations to call the Upload method.",
664664
"post": {
665665
"tags": [
666-
"Documents.DocumentDto"
666+
"Documents.DocumentDto.Actions"
667667
],
668668
"summary": "Invoke action Upload",
669669
"operationId": "Documents.DocumentDto.Upload",
@@ -3940,7 +3940,7 @@
39403940
"description": "Provides operations to call the Upload method.",
39413941
"post": {
39423942
"tags": [
3943-
"Tasks.DocumentDto"
3943+
"Tasks.DocumentDto.Actions"
39443944
],
39453945
"summary": "Invoke action Upload",
39463946
"operationId": "Tasks.DocumentDto.Upload",
@@ -7481,6 +7481,10 @@
74817481
"name": "Documents.DocumentDto",
74827482
"x-ms-docs-toc-type": "page"
74837483
},
7484+
{
7485+
"name": "Documents.DocumentDto.Actions",
7486+
"x-ms-docs-toc-type": "container"
7487+
},
74847488
{
74857489
"name": "Documents.RevisionDto",
74867490
"x-ms-docs-toc-type": "page"
@@ -7521,6 +7525,10 @@
75217525
"name": "Tasks.DocumentDto",
75227526
"x-ms-docs-toc-type": "page"
75237527
},
7528+
{
7529+
"name": "Tasks.DocumentDto.Actions",
7530+
"x-ms-docs-toc-type": "container"
7531+
},
75247532
{
75257533
"name": "Tasks.RevisionDto",
75267534
"x-ms-docs-toc-type": "page"

0 commit comments

Comments
 (0)