diff --git a/.config/1espt/PipelineAutobaseliningConfig.yml b/.config/1espt/PipelineAutobaseliningConfig.yml
new file mode 100644
index 000000000..2425160a4
--- /dev/null
+++ b/.config/1espt/PipelineAutobaseliningConfig.yml
@@ -0,0 +1,15 @@
+## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.
+
+pipelines:
+ 107:
+ usedNonDefaultBranch: true
+ retail:
+ source:
+ credscan:
+ lastModifiedDate: 2024-09-13
+ eslint:
+ lastModifiedDate: 2024-09-13
+ psscriptanalyzer:
+ lastModifiedDate: 2024-09-13
+ armory:
+ lastModifiedDate: 2024-09-13
diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
index 120210fb0..377f67995 100644
--- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
+++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
@@ -9,7 +9,7 @@
enable
hidi
./../../artifacts
- 1.4.9
+ 1.4.10
OpenAPI.NET CLI tool for slicing OpenAPI documents
true
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index 703291eb4..eb0ee6b12 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -3,7 +3,7 @@
netstandard2.0
Latest
true
- 1.6.21
+ 1.6.22
.NET models with JSON and YAML writers for OpenAPI specification
true
diff --git a/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs b/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs
index fcc2af0b2..bd351ce0e 100644
--- a/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs
+++ b/src/Microsoft.OpenApi/Services/OpenApiFilterService.cs
@@ -112,7 +112,10 @@ public static OpenApiDocument CreateFilteredDocument(OpenApiDocument source, Fun
{
foreach (var parameter in result.Parameters)
{
- pathItem.Parameters.Add(parameter);
+ if (!pathItem.Parameters.Contains(parameter))
+ {
+ pathItem.Parameters.Add(parameter);
+ }
}
}
}
diff --git a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs
index 53a79c8a4..e70f129b9 100644
--- a/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs
+++ b/src/Microsoft.OpenApi/Services/OpenApiUrlTreeNode.cs
@@ -150,6 +150,13 @@ public OpenApiUrlTreeNode Attach(string path,
}
var segments = path.Split('/');
+ if (path.EndsWith("/", StringComparison.OrdinalIgnoreCase))
+ {
+ // Remove the last element, which is empty, and append the trailing slash to the new last element
+ // This is to support URLs with trailing slashes
+ Array.Resize(ref segments, segments.Length - 1);
+ segments[segments.Length - 1] += @"\";
+ }
return Attach(segments: segments,
pathItem: pathItem,
diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Microsoft.OpenApi.Hidi.Tests.csproj b/test/Microsoft.OpenApi.Hidi.Tests/Microsoft.OpenApi.Hidi.Tests.csproj
index a0689b473..397831833 100644
--- a/test/Microsoft.OpenApi.Hidi.Tests/Microsoft.OpenApi.Hidi.Tests.csproj
+++ b/test/Microsoft.OpenApi.Hidi.Tests/Microsoft.OpenApi.Hidi.Tests.csproj
@@ -12,10 +12,10 @@
-
-
+
+
-
+
diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs
index f91d0db93..ebb863461 100644
--- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs
+++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Extensions.Logging;
@@ -105,6 +105,57 @@ public void TestPredicateFiltersUsingRelativeRequestUrls()
Assert.False(predicate("/foo", OperationType.Patch, null));
}
+ [Fact]
+ public void CreateFilteredDocumentUsingPredicateFromRequestUrl()
+ {
+ // Arrange
+ var openApiDocument = new OpenApiDocument
+ {
+ Info = new() { Title = "Test", Version = "1.0" },
+ Servers = new List { new() { Url = "https://localhost/" } },
+ Paths = new()
+ {
+ ["/test/{id}"] = new()
+ {
+ Operations = new Dictionary
+ {
+ { OperationType.Get, new() },
+ { OperationType.Patch, new() }
+ },
+ Parameters = new List
+ {
+ new()
+ {
+ Name = "id",
+ In = ParameterLocation.Path,
+ Required = true,
+ Schema = new()
+ {
+ Type = "string"
+ }
+ }
+ }
+ }
+
+
+ }
+ };
+
+ var requestUrls = new Dictionary>
+ {
+ {"/test/{id}", new List {"GET","PATCH"}}
+ };
+
+ // Act
+ var predicate = OpenApiFilterService.CreatePredicate(requestUrls: requestUrls, source: openApiDocument);
+ var subsetDoc = OpenApiFilterService.CreateFilteredDocument(openApiDocument, predicate);
+
+ // Assert that there's only 1 parameter in the subset document
+ Assert.NotNull(subsetDoc);
+ Assert.NotEmpty(subsetDoc.Paths);
+ Assert.Single(subsetDoc.Paths.First().Value.Parameters);
+ }
+
[Fact]
public void ShouldParseNestedPostmanCollection()
{
diff --git a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj
index ebb063101..d0740f052 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj
+++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj
@@ -17,11 +17,11 @@
-
-
+
+
-
+
diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj
index 9c91a65ab..e3a9fd2ad 100644
--- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj
+++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj
@@ -10,13 +10,13 @@
-
-
-
+
+
+
-
-
+
+
diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs
index 8d0bb8cd5..4da7a337f 100644
--- a/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiUrlTreeNodeTests.cs
@@ -466,5 +466,38 @@ public async Task VerifyDiagramFromSampleOpenAPIAsync()
await Verifier.Verify(diagram);
}
+
+ public static TheoryData SupportsTrailingSlashesInPathData => new TheoryData
+ {
+ // Path, children up to second to leaf, last expected leaf node name, expected leaf node path
+ { "/cars/{car-id}/build/", ["cars", "{car-id}"], @"build\", @"\cars\{car-id}\build\" },
+ { "/cars/", [], @"cars\", @"\cars\" },
+ };
+
+ [Theory]
+ [MemberData(nameof(SupportsTrailingSlashesInPathData))]
+ public void SupportsTrailingSlashesInPath(string path, string[] childrenBeforeLastNode, string expectedLeafNodeName, string expectedLeafNodePath)
+ {
+ var openApiDocument = new OpenApiDocument
+ {
+ Paths = new()
+ {
+ [path] = new()
+ }
+ };
+
+ var label = "trailing-slash";
+ var rootNode = OpenApiUrlTreeNode.Create(openApiDocument, label);
+
+ var secondToLeafNode = rootNode;
+ foreach (var childName in childrenBeforeLastNode)
+ {
+ secondToLeafNode = secondToLeafNode.Children[childName];
+ }
+
+ Assert.True(secondToLeafNode.Children.TryGetValue(expectedLeafNodeName, out var leafNode));
+ Assert.Equal(expectedLeafNodePath, leafNode.Path);
+ Assert.Empty(leafNode.Children);
+ }
}
}