Skip to content

Commit a01222b

Browse files
authored
Merge pull request #761 from microsoft/release/1.3.1-preview5
Release/1.3.1 preview5
2 parents f738c20 + cbbf608 commit a01222b

32 files changed

+714
-357
lines changed

.azure-pipelines/ci-build.yml

Lines changed: 339 additions & 120 deletions
Large diffs are not rendered by default.

.github/workflows/ci-cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ jobs:
1414
GITHUB_RUN_NUMBER: ${{ github.run_number }}
1515
steps:
1616
- name: Setup .NET
17-
uses: actions/setup-dotnet@v1
17+
uses: actions/setup-dotnet@v2
1818
with:
19-
dotnet-version: 5.0.x
19+
dotnet-version: 6.0.x
2020

2121
- name: Data gatherer
2222
id: data_gatherer

.github/workflows/codeql-analysis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
uses: actions/checkout@v2
1818

1919
- name: Setup .NET
20-
uses: actions/setup-dotnet@v1
20+
uses: actions/setup-dotnet@v2
2121
with:
22-
dotnet-version: 5.0.x
22+
dotnet-version: 6.0.x
2323

2424
- name: Initialize CodeQL
2525
id: init_codeql

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"request": "launch",
1111
"preLaunchTask": "build",
1212
// If you have changed target frameworks, make sure to update the program path.
13-
"program": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/bin/Debug/netcoreapp3.1/Microsoft.OpenApi.Hidi.dll",
13+
"program": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/bin/Debug/net6.0/Microsoft.OpenApi.Hidi.dll",
1414
"args": [],
1515
"cwd": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi",
1616
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console

.vscode/tasks.json

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,43 @@
55
"tasks": [
66
{
77
"label": "build",
8-
"type": "shell",
9-
"command": "msbuild",
8+
"command": "dotnet",
9+
"type": "process",
10+
"group": "build",
11+
"args": [
12+
"build",
13+
"${workspaceFolder}/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj",
14+
"/property:GenerateFullPaths=true",
15+
"/consoleloggerparameters:NoSummary"
16+
],
17+
"problemMatcher": "$msCompile"
18+
},
19+
{
20+
"label": "test",
21+
"command": "dotnet",
22+
"type": "process",
23+
"group": "test",
1024
"args": [
25+
"test",
26+
"${workspaceFolder}/Microsoft.OpenApi.sln",
1127
"/property:GenerateFullPaths=true",
12-
"/t:build"
28+
"/consoleloggerparameters:NoSummary",
29+
"--collect:\"XPlat Code Coverage\""
1330
],
31+
"problemMatcher": "$msCompile"
32+
},
33+
{
34+
"label": "watch",
35+
"command": "dotnet",
36+
"type": "process",
1437
"group": "build",
15-
"presentation": {
16-
"reveal": "silent"
17-
},
38+
"args": [
39+
"watch",
40+
"run",
41+
"${workspaceFolder}/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj",
42+
"/property:GenerateFullPaths=true",
43+
"/consoleloggerparameters:NoSummary"
44+
],
1845
"problemMatcher": "$msCompile"
1946
},
2047
{

Microsoft.OpenApi.sln

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.29613.14
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.1.32210.238
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi", "src\Microsoft.OpenApi\Microsoft.OpenApi.csproj", "{A8E50143-69B2-472A-9D45-3F9A05D13202}"
77
EndProject
@@ -12,7 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1212
readme.md = readme.md
1313
EndProjectSection
1414
EndProject
15-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Workbench", "src\Microsoft.OpenApi.Workbench\Microsoft.OpenApi.Workbench.csproj", "{6A5E91E5-0441-46EE-AEB9-8334981B7F08}"
15+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Workbench", "src\Microsoft.OpenApi.Workbench\Microsoft.OpenApi.Workbench.csproj", "{6A5E91E5-0441-46EE-AEB9-8334981B7F08}"
1616
EndProject
1717
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Readers", "src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj", "{79933258-0126-4382-8755-D50820ECC483}"
1818
EndProject

src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<TargetFramework>net6.0</TargetFramework>
66
<LangVersion>9.0</LangVersion>
77
<PackAsTool>true</PackAsTool>
8+
<PackageIconUrl>http://go.microsoft.com/fwlink/?LinkID=288890</PackageIconUrl>
89
<PackageProjectUrl>https://github.com/Microsoft/OpenAPI.NET</PackageProjectUrl>
910
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1011
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
@@ -14,12 +15,14 @@
1415
<PackageId>Microsoft.OpenApi.Hidi</PackageId>
1516
<ToolCommandName>hidi</ToolCommandName>
1617
<PackageOutputPath>./../../artifacts</PackageOutputPath>
17-
<Version>0.5.0-preview4</Version>
18+
<Version>0.5.0-preview5</Version>
19+
<Description>OpenAPI.NET CLI tool for slicing OpenAPI documents</Description>
1820
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
1921
<PackageTags>OpenAPI .NET</PackageTags>
2022
<RepositoryUrl>https://github.com/Microsoft/OpenAPI.NET</RepositoryUrl>
2123
<PackageReleaseNotes>
22-
- Publish symbols.
24+
- Upgrades Microsoft.OpenApi.OData to 1.0.10-preview1
25+
- Fixes an issue where hidi would not process async operations
2326
</PackageReleaseNotes>
2427
<AssemblyName>Microsoft.OpenApi.Hidi</AssemblyName>
2528
<RootNamespace>Microsoft.OpenApi.Hidi</RootNamespace>
@@ -34,6 +37,8 @@
3437
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
3538
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
3639
<PackageReference Include="System.CommandLine" Version="2.0.0-beta2.21617.1" />
40+
<PackageReference Include="Microsoft.OData.Edm" Version="7.10.0" />
41+
<PackageReference Include="Microsoft.OpenApi.OData" Version="1.0.10-preview2" />
3742
</ItemGroup>
3843

3944
<ItemGroup>

src/Microsoft.OpenApi.Hidi/OpenApiService.cs

Lines changed: 107 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
using System.Text.Json;
1414
using System.Threading.Tasks;
1515
using Microsoft.Extensions.Logging;
16+
using System.Xml.Linq;
17+
using Microsoft.OData.Edm.Csdl;
1618
using Microsoft.OpenApi.Extensions;
1719
using Microsoft.OpenApi.Models;
20+
using Microsoft.OpenApi.OData;
1821
using Microsoft.OpenApi.Readers;
1922
using Microsoft.OpenApi.Services;
2023
using Microsoft.OpenApi.Validations;
@@ -24,8 +27,9 @@ namespace Microsoft.OpenApi.Hidi
2427
{
2528
public class OpenApiService
2629
{
27-
public static async void ProcessOpenApiDocument(
30+
public static async Task ProcessOpenApiDocument(
2831
string openapi,
32+
string csdl,
2933
FileInfo output,
3034
OpenApiSpecVersion? version,
3135
OpenApiFormat? format,
@@ -41,9 +45,9 @@ string filterbycollection
4145

4246
try
4347
{
44-
if (string.IsNullOrEmpty(openapi))
48+
if (string.IsNullOrEmpty(openapi) && string.IsNullOrEmpty(csdl))
4549
{
46-
throw new ArgumentNullException(nameof(openapi));
50+
throw new ArgumentNullException("Please input a file path");
4751
}
4852
}
4953
catch (ArgumentNullException ex)
@@ -75,36 +79,56 @@ string filterbycollection
7579
logger.LogError(ex.Message);
7680
return;
7781
}
78-
79-
var stream = await GetStream(openapi, logger);
8082

81-
// Parsing OpenAPI file
83+
Stream stream;
84+
OpenApiDocument document;
85+
OpenApiFormat openApiFormat;
8286
var stopwatch = new Stopwatch();
83-
stopwatch.Start();
84-
logger.LogTrace("Parsing OpenApi file");
85-
var result = new OpenApiStreamReader(new OpenApiReaderSettings
86-
{
87-
ReferenceResolution = resolveexternal ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
88-
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
89-
}
90-
).ReadAsync(stream).GetAwaiter().GetResult();
91-
var document = result.OpenApiDocument;
92-
stopwatch.Stop();
9387

94-
var context = result.OpenApiDiagnostic;
95-
if (context.Errors.Count > 0)
88+
if (!string.IsNullOrEmpty(csdl))
9689
{
97-
var errorReport = new StringBuilder();
90+
// Default to yaml and OpenApiVersion 3 during csdl to OpenApi conversion
91+
openApiFormat = format ?? GetOpenApiFormat(csdl, logger);
92+
version ??= OpenApiSpecVersion.OpenApi3_0;
9893

99-
foreach (var error in context.Errors)
100-
{
101-
errorReport.AppendLine(error.ToString());
102-
}
103-
logger.LogError($"{stopwatch.ElapsedMilliseconds}ms: OpenApi Parsing errors {string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray())}");
94+
stream = await GetStream(csdl, logger);
95+
document = await ConvertCsdlToOpenApi(stream);
10496
}
10597
else
10698
{
107-
logger.LogTrace("{timestamp}ms: Parsed OpenApi successfully. {count} paths found.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
99+
stream = await GetStream(openapi, logger);
100+
101+
// Parsing OpenAPI file
102+
stopwatch.Start();
103+
logger.LogTrace("Parsing OpenApi file");
104+
var result = new OpenApiStreamReader(new OpenApiReaderSettings
105+
{
106+
ReferenceResolution = resolveexternal ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
107+
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
108+
}
109+
).ReadAsync(stream).GetAwaiter().GetResult();
110+
111+
document = result.OpenApiDocument;
112+
stopwatch.Stop();
113+
114+
var context = result.OpenApiDiagnostic;
115+
if (context.Errors.Count > 0)
116+
{
117+
var errorReport = new StringBuilder();
118+
119+
foreach (var error in context.Errors)
120+
{
121+
errorReport.AppendLine(error.ToString());
122+
}
123+
logger.LogError($"{stopwatch.ElapsedMilliseconds}ms: OpenApi Parsing errors {string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray())}");
124+
}
125+
else
126+
{
127+
logger.LogTrace("{timestamp}ms: Parsed OpenApi successfully. {count} paths found.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
128+
}
129+
130+
openApiFormat = format ?? GetOpenApiFormat(openapi, logger);
131+
version ??= result.OpenApiDiagnostic.SpecificationVersion;
108132
}
109133

110134
Func<string, OperationType?, OpenApiOperation, bool> predicate;
@@ -151,8 +175,6 @@ string filterbycollection
151175
ReferenceInline = inline ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
152176
};
153177

154-
var openApiFormat = format ?? GetOpenApiFormat(openapi, logger);
155-
var openApiVersion = version ?? result.OpenApiDiagnostic.SpecificationVersion;
156178
IOpenApiWriter writer = openApiFormat switch
157179
{
158180
OpenApiFormat.Json => new OpenApiJsonWriter(textWriter, settings),
@@ -163,14 +185,66 @@ string filterbycollection
163185
logger.LogTrace("Serializing to OpenApi document using the provided spec version and writer");
164186

165187
stopwatch.Start();
166-
document.Serialize(writer, openApiVersion);
188+
document.Serialize(writer, (OpenApiSpecVersion)version);
167189
stopwatch.Stop();
168190

169191
logger.LogTrace($"Finished serializing in {stopwatch.ElapsedMilliseconds}ms");
170192

171193
textWriter.Flush();
172194
}
173195

196+
/// <summary>
197+
/// Converts CSDL to OpenAPI
198+
/// </summary>
199+
/// <param name="csdl">The CSDL stream.</param>
200+
/// <returns>An OpenAPI document.</returns>
201+
public static async Task<OpenApiDocument> ConvertCsdlToOpenApi(Stream csdl)
202+
{
203+
using var reader = new StreamReader(csdl);
204+
var csdlText = await reader.ReadToEndAsync();
205+
var edmModel = CsdlReader.Parse(XElement.Parse(csdlText).CreateReader());
206+
207+
var settings = new OpenApiConvertSettings()
208+
{
209+
AddSingleQuotesForStringParameters = true,
210+
AddEnumDescriptionExtension = true,
211+
DeclarePathParametersOnPathItem = true,
212+
EnableKeyAsSegment = true,
213+
EnableOperationId = true,
214+
ErrorResponsesAsDefault = false,
215+
PrefixEntityTypeNameBeforeKey = true,
216+
TagDepth = 2,
217+
EnablePagination = true,
218+
EnableDiscriminatorValue = false,
219+
EnableDerivedTypesReferencesForRequestBody = false,
220+
EnableDerivedTypesReferencesForResponses = false,
221+
ShowRootPath = true,
222+
ShowLinks = true
223+
};
224+
OpenApiDocument document = edmModel.ConvertToOpenApi(settings);
225+
226+
document = FixReferences(document);
227+
228+
return document;
229+
}
230+
231+
/// <summary>
232+
/// Fixes the references in the resulting OpenApiDocument.
233+
/// </summary>
234+
/// <param name="document"> The converted OpenApiDocument.</param>
235+
/// <returns> A valid OpenApiDocument instance.</returns>
236+
public static OpenApiDocument FixReferences(OpenApiDocument document)
237+
{
238+
// This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
239+
// So we write it out, and read it back in again to fix it up.
240+
241+
var sb = new StringBuilder();
242+
document.SerializeAsV3(new OpenApiYamlWriter(new StringWriter(sb)));
243+
var doc = new OpenApiStringReader().Read(sb.ToString(), out _);
244+
245+
return doc;
246+
}
247+
174248
private static async Task<Stream> GetStream(string input, ILogger logger)
175249
{
176250
var stopwatch = new Stopwatch();
@@ -181,13 +255,13 @@ private static async Task<Stream> GetStream(string input, ILogger logger)
181255
{
182256
try
183257
{
184-
using var httpClientHandler = new HttpClientHandler()
258+
var httpClientHandler = new HttpClientHandler()
185259
{
186260
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
187261
};
188262
using var httpClient = new HttpClient(httpClientHandler)
189263
{
190-
DefaultRequestVersion = HttpVersion.Version20
264+
DefaultRequestVersion = HttpVersion.Version20
191265
};
192266
stream = await httpClient.GetStreamAsync(input);
193267
}
@@ -253,7 +327,7 @@ public static Dictionary<string, List<string>> ParseJsonCollectionFile(Stream st
253327
return requestUrls;
254328
}
255329

256-
internal static async void ValidateOpenApiDocument(string openapi, LogLevel loglevel)
330+
internal static async Task ValidateOpenApiDocument(string openapi, LogLevel loglevel)
257331
{
258332
if (string.IsNullOrEmpty(openapi))
259333
{
@@ -286,10 +360,10 @@ internal static async void ValidateOpenApiDocument(string openapi, LogLevel logl
286360
Console.WriteLine(statsVisitor.GetStatisticsReport());
287361
}
288362

289-
private static OpenApiFormat GetOpenApiFormat(string openapi, ILogger logger)
363+
private static OpenApiFormat GetOpenApiFormat(string input, ILogger logger)
290364
{
291365
logger.LogTrace("Getting the OpenApi format");
292-
return !openapi.StartsWith("http") && Path.GetExtension(openapi) == ".json" ? OpenApiFormat.Json : OpenApiFormat.Yaml;
366+
return !input.StartsWith("http") && Path.GetExtension(input) == ".json" ? OpenApiFormat.Json : OpenApiFormat.Yaml;
293367
}
294368

295369
private static ILogger ConfigureLoggerInstance(LogLevel loglevel)

src/Microsoft.OpenApi.Hidi/Program.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ static async Task<int> Main(string[] args)
1919
var descriptionOption = new Option<string>("--openapi", "Input OpenAPI description file path or URL");
2020
descriptionOption.AddAlias("-d");
2121

22+
var csdlOption = new Option<string>("--csdl", "Input CSDL file path or URL");
23+
csdlOption.AddAlias("-cs");
24+
2225
var outputOption = new Option<FileInfo>("--output", () => new FileInfo("./output"), "The output directory path for the generated file.") { Arity = ArgumentArity.ZeroOrOne };
2326
outputOption.AddAlias("-o");
2427

@@ -57,6 +60,7 @@ static async Task<int> Main(string[] args)
5760
var transformCommand = new Command("transform")
5861
{
5962
descriptionOption,
63+
csdlOption,
6064
outputOption,
6165
versionOption,
6266
formatOption,
@@ -68,8 +72,8 @@ static async Task<int> Main(string[] args)
6872
resolveExternalOption,
6973
};
7074

71-
transformCommand.SetHandler<string, FileInfo, OpenApiSpecVersion?, OpenApiFormat?, LogLevel, bool, bool, string, string, string> (
72-
OpenApiService.ProcessOpenApiDocument, descriptionOption, outputOption, versionOption, formatOption, logLevelOption, inlineOption, resolveExternalOption, filterByOperationIdsOption, filterByTagsOption, filterByCollectionOption);
75+
transformCommand.SetHandler<string, string, FileInfo, OpenApiSpecVersion?, OpenApiFormat?, LogLevel, bool, bool, string, string, string> (
76+
OpenApiService.ProcessOpenApiDocument, descriptionOption, csdlOption, outputOption, versionOption, formatOption, logLevelOption, inlineOption, resolveExternalOption, filterByOperationIdsOption, filterByTagsOption, filterByCollectionOption);
7377

7478
rootCommand.Add(transformCommand);
7579
rootCommand.Add(validateCommand);

0 commit comments

Comments
 (0)