Skip to content

Commit 6922d61

Browse files
authored
Merge pull request #639 from microsoft/mk/add-filter-by-tags
Adds --filterByTags Command option
2 parents 9f46c00 + 6acf634 commit 6922d61

File tree

5 files changed

+58
-16
lines changed

5 files changed

+58
-16
lines changed

src/Microsoft.OpenApi.Tool/OpenApiService.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public static void ProcessOpenApiDocument(
2424
OpenApiSpecVersion version,
2525
OpenApiFormat format,
2626
string filterByOperationIds,
27+
string filterByTags,
2728
bool inline,
2829
bool resolveExternal)
2930
{
@@ -52,9 +53,19 @@ public static void ProcessOpenApiDocument(
5253
document = result.OpenApiDocument;
5354

5455
// Check if filter options are provided, then execute
56+
if (!string.IsNullOrEmpty(filterByOperationIds) && !string.IsNullOrEmpty(filterByTags))
57+
{
58+
throw new InvalidOperationException("Cannot filter by operationIds and tags at the same time.");
59+
}
60+
5561
if (!string.IsNullOrEmpty(filterByOperationIds))
5662
{
57-
var predicate = OpenApiFilterService.CreatePredicate(filterByOperationIds);
63+
var predicate = OpenApiFilterService.CreatePredicate(operationIds: filterByOperationIds);
64+
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
65+
}
66+
if (!string.IsNullOrEmpty(filterByTags))
67+
{
68+
var predicate = OpenApiFilterService.CreatePredicate(tags: filterByTags);
5869
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
5970
}
6071

src/Microsoft.OpenApi.Tool/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ static async Task<int> Main(string[] args)
2929
new Option("--format", "File format",typeof(OpenApiFormat) ),
3030
new Option("--inline", "Inline $ref instances", typeof(bool) ),
3131
new Option("--resolveExternal","Resolve external $refs", typeof(bool)),
32-
new Option("--filterByOperationIds", "Filters by OperationId provided", typeof(string))
32+
new Option("--filterByOperationIds", "Filters OpenApiDocument by OperationId(s) provided", typeof(string)),
33+
new Option("--filterByTags", "Filters OpenApiDocument by Tag(s) provided", typeof(string))
3334
};
34-
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, string, bool, bool>(
35+
transformCommand.Handler = CommandHandler.Create<string, FileInfo, OpenApiSpecVersion, OpenApiFormat, string, string, bool, bool>(
3536
OpenApiService.ProcessOpenApiDocument);
3637

3738
rootCommand.Add(transformCommand);

src/Microsoft.OpenApi/Services/OpenApiFilterService.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Linq;
7+
using System.Text.RegularExpressions;
78
using Microsoft.OpenApi.Models;
89

910
namespace Microsoft.OpenApi.Services
@@ -17,10 +18,15 @@ public static class OpenApiFilterService
1718
/// Create predicate function based on passed query parameters
1819
/// </summary>
1920
/// <param name="operationIds">Comma delimited list of operationIds or * for all operations.</param>
21+
/// <param name="tags">Comma delimited list of tags or a single regex.</param>
2022
/// <returns>A predicate.</returns>
21-
public static Func<OpenApiOperation, bool> CreatePredicate(string operationIds)
23+
public static Func<OpenApiOperation, bool> CreatePredicate(string operationIds = null, string tags = null)
2224
{
2325
Func<OpenApiOperation, bool> predicate;
26+
if (!string.IsNullOrEmpty(operationIds) && !string.IsNullOrEmpty(tags))
27+
{
28+
throw new InvalidOperationException("Cannot specify both operationIds and tags at the same time.");
29+
}
2430
if (operationIds != null)
2531
{
2632
if (operationIds == "*")
@@ -33,10 +39,23 @@ public static Func<OpenApiOperation, bool> CreatePredicate(string operationIds)
3339
predicate = (o) => operationIdsArray.Contains(o.OperationId);
3440
}
3541
}
42+
else if (tags != null)
43+
{
44+
var tagsArray = tags.Split(',');
45+
if (tagsArray.Length == 1)
46+
{
47+
var regex = new Regex(tagsArray[0]);
3648

49+
predicate = (o) => o.Tags.Any(t => regex.IsMatch(t.Name));
50+
}
51+
else
52+
{
53+
predicate = (o) => o.Tags.Any(t => tagsArray.Contains(t.Name));
54+
}
55+
}
3756
else
3857
{
39-
throw new InvalidOperationException("OperationId needs to be specified.");
58+
throw new InvalidOperationException("Either operationId(s) or tag(s) need to be specified.");
4059
}
4160

4261
return predicate;

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ namespace Microsoft.OpenApi.Services
957957
public static class OpenApiFilterService
958958
{
959959
public static Microsoft.OpenApi.Models.OpenApiDocument CreateFilteredDocument(Microsoft.OpenApi.Models.OpenApiDocument source, System.Func<Microsoft.OpenApi.Models.OpenApiOperation, bool> predicate) { }
960-
public static System.Func<Microsoft.OpenApi.Models.OpenApiOperation, bool> CreatePredicate(string operationIds) { }
960+
public static System.Func<Microsoft.OpenApi.Models.OpenApiOperation, bool> CreatePredicate(string operationIds = null, string tags = null) { }
961961
}
962962
public class OpenApiReferenceError : Microsoft.OpenApi.Models.OpenApiError
963963
{

test/Microsoft.OpenApi.Tests/Services/OpenApiFilterServiceTests.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,38 @@ public OpenApiFilterServiceTests()
1919
}
2020

2121
[Theory]
22-
[InlineData("users.user.ListUser")]
23-
[InlineData("users.user.GetUser")]
24-
[InlineData("administrativeUnits.restore")]
25-
[InlineData("graphService.GetGraphService")]
26-
public void ReturnFilteredOpenApiDocumentBasedOnOperationIds(string operationId)
22+
[InlineData("users.user.ListUser", null, 1)]
23+
[InlineData("users.user.GetUser", null, 1)]
24+
[InlineData("users.user.ListUser,users.user.GetUser", null, 2)]
25+
[InlineData("*", null, 12)]
26+
[InlineData("administrativeUnits.restore", null, 1)]
27+
[InlineData("graphService.GetGraphService", null, 1)]
28+
[InlineData(null, "users.user,applications.application", 3)]
29+
[InlineData(null, "^users\\.", 3)]
30+
[InlineData(null, "users.user", 2)]
31+
[InlineData(null, "applications.application", 1)]
32+
[InlineData(null, "reports.Functions", 2)]
33+
public void ReturnFilteredOpenApiDocumentBasedOnOperationIdsAndTags(string operationIds, string tags, int expectedPathCount)
2734
{
2835
// Act
29-
var predicate = OpenApiFilterService.CreatePredicate(operationId);
36+
var predicate = OpenApiFilterService.CreatePredicate(operationIds, tags);
3037
var subsetOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(_openApiDocumentMock, predicate);
3138

3239
// Assert
3340
Assert.NotNull(subsetOpenApiDocument);
34-
Assert.Single(subsetOpenApiDocument.Paths);
41+
Assert.NotEmpty(subsetOpenApiDocument.Paths);
42+
Assert.Equal(expectedPathCount, subsetOpenApiDocument.Paths.Count);
3543
}
3644

3745
[Fact]
38-
public void ThrowsInvalidOperationExceptionInCreatePredicateWhenInvalidOperationIdIsSpecified()
46+
public void ThrowsInvalidOperationExceptionInCreatePredicateWhenInvalidArgumentsArePassed()
3947
{
4048
// Act and Assert
41-
var message = Assert.Throws<InvalidOperationException>(() =>OpenApiFilterService.CreatePredicate(null)).Message;
42-
Assert.Equal("OperationId needs to be specified.", message);
49+
var message1 = Assert.Throws<InvalidOperationException>(() => OpenApiFilterService.CreatePredicate(null, null)).Message;
50+
Assert.Equal("Either operationId(s) or tag(s) need to be specified.", message1);
51+
52+
var message2 = Assert.Throws<InvalidOperationException>(() => OpenApiFilterService.CreatePredicate("users.user.ListUser", "users.user")).Message;
53+
Assert.Equal("Cannot specify both operationIds and tags at the same time.", message2);
4354
}
4455
}
4556
}

0 commit comments

Comments
 (0)