Skip to content

Commit 1d986d1

Browse files
committed
Resolve merge conflicts
2 parents 761088f + 5c01fbe commit 1d986d1

File tree

8 files changed

+205
-75
lines changed

8 files changed

+205
-75
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
<LangVersion>9.0</LangVersion>
67
<PackAsTool>true</PackAsTool>
78
<ToolCommandName>hidi</ToolCommandName>
89
<PackageOutputPath>./../../artifacts</PackageOutputPath>
9-
<Version>0.5.0-preview2</Version>
10+
<Version>0.5.0-preview3</Version>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
14+
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
15+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
16+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
17+
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
18+
<PackageReference Include="System.CommandLine" Version="2.0.0-beta2.21617.1" />
1319
<PackageReference Include="Microsoft.OData.Edm" Version="7.9.4" />
1420
<PackageReference Include="Microsoft.OpenApi.OData" Version="1.0.8" />
15-
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21216.1" />
1621
</ItemGroup>
1722

1823
<ItemGroup>

src/Microsoft.OpenApi.Hidi/OpenApiService.cs

Lines changed: 147 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics;
67
using System.IO;
78
using System.Linq;
89
using System.Net;
910
using System.Net.Http;
11+
using System.Security;
1012
using System.Text;
1113
using System.Text.Json;
14+
using System.Threading.Tasks;
15+
using Microsoft.Extensions.Logging;
1216
using System.Xml.Linq;
1317
using Microsoft.OData.Edm.Csdl;
1418
using Microsoft.OpenApi.Extensions;
@@ -21,31 +25,59 @@
2125

2226
namespace Microsoft.OpenApi.Hidi
2327
{
24-
public static class OpenApiService
28+
public class OpenApiService
2529
{
26-
public static void ProcessOpenApiDocument(
30+
public static async void ProcessOpenApiDocument(
2731
string openapi,
2832
string csdl,
2933
FileInfo output,
3034
OpenApiSpecVersion? version,
3135
OpenApiFormat? format,
36+
LogLevel loglevel,
37+
bool inline,
38+
bool resolveexternal,
3239
string filterbyoperationids,
3340
string filterbytags,
34-
string filterbycollection,
35-
bool inline,
36-
bool resolveexternal)
41+
string filterbycollection
42+
)
3743
{
38-
if (string.IsNullOrEmpty(openapi) && string.IsNullOrEmpty(csdl))
44+
var logger = ConfigureLoggerInstance(loglevel);
45+
46+
try
47+
{
48+
if (string.IsNullOrEmpty(openapi) && string.IsNullOrEmpty(csdl))
49+
{
50+
throw new ArgumentNullException("Please input a file path");
51+
}
52+
}
53+
catch (ArgumentNullException ex)
3954
{
40-
throw new ArgumentNullException("Please input a file path");
55+
logger.LogError(ex.Message);
56+
return;
4157
}
42-
if(output == null)
58+
try
4359
{
44-
throw new ArgumentException(nameof(output));
60+
if(output == null)
61+
{
62+
throw new ArgumentException(nameof(output));
63+
}
4564
}
46-
if (output.Exists)
65+
catch (ArgumentException ex)
4766
{
48-
throw new IOException("The file you're writing to already exists. Please input a new output path.");
67+
logger.LogError(ex.Message);
68+
return;
69+
}
70+
try
71+
{
72+
if (output.Exists)
73+
{
74+
throw new IOException("The file you're writing to already exists. Please input a new file path.");
75+
}
76+
}
77+
catch (IOException ex)
78+
{
79+
logger.LogError(ex.Message);
80+
return;
4981
}
5082

5183
Stream stream;
@@ -56,14 +88,18 @@ public static void ProcessOpenApiDocument(
5688
{
5789
// Default to yaml during csdl to OpenApi conversion
5890
openApiFormat = format ?? GetOpenApiFormat(csdl);
59-
60-
stream = GetStream(csdl);
61-
document = ConvertCsdlToOpenApi(stream);
91+
92+
stream = GetStream(csdl);
93+
document = ConvertCsdlToOpenApi(stream);
6294
}
6395
else
6496
{
65-
stream = GetStream(openapi);
97+
stream = GetStream(openapi, logger);
6698

99+
// Parsing OpenAPI file
100+
var stopwatch = new Stopwatch();
101+
stopwatch.Start();
102+
logger.LogTrace("Parsing OpenApi file");
67103
var result = new OpenApiStreamReader(new OpenApiReaderSettings
68104
{
69105
ReferenceResolution = resolveexternal ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences,
@@ -72,9 +108,9 @@ public static void ProcessOpenApiDocument(
72108
).ReadAsync(stream).GetAwaiter().GetResult();
73109

74110
document = result.OpenApiDocument;
111+
stopwatch.Stop();
75112

76113
var context = result.OpenApiDiagnostic;
77-
78114
if (context.Errors.Count > 0)
79115
{
80116
var errorReport = new StringBuilder();
@@ -83,8 +119,11 @@ public static void ProcessOpenApiDocument(
83119
{
84120
errorReport.AppendLine(error.ToString());
85121
}
86-
87-
throw new ArgumentException(string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray()));
122+
logger.LogError($"{stopwatch.ElapsedMilliseconds}ms: OpenApi Parsing errors {string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray())}");
123+
}
124+
else
125+
{
126+
logger.LogTrace("{timestamp}ms: Parsed OpenApi successfully. {count} paths found.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
88127
}
89128

90129
openApiFormat = format ?? GetOpenApiFormat(openapi);
@@ -93,32 +132,42 @@ public static void ProcessOpenApiDocument(
93132

94133
Func<string, OperationType?, OpenApiOperation, bool> predicate;
95134

96-
// Check if filter options are provided, then execute
135+
// Check if filter options are provided, then slice the OpenAPI document
97136
if (!string.IsNullOrEmpty(filterbyoperationids) && !string.IsNullOrEmpty(filterbytags))
98137
{
99138
throw new InvalidOperationException("Cannot filter by operationIds and tags at the same time.");
100139
}
101140
if (!string.IsNullOrEmpty(filterbyoperationids))
102141
{
142+
logger.LogTrace("Creating predicate based on the operationIds supplied.");
103143
predicate = OpenApiFilterService.CreatePredicate(operationIds: filterbyoperationids);
144+
145+
logger.LogTrace("Creating subset OpenApi document.");
104146
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
105147
}
106148
if (!string.IsNullOrEmpty(filterbytags))
107149
{
150+
logger.LogTrace("Creating predicate based on the tags supplied.");
108151
predicate = OpenApiFilterService.CreatePredicate(tags: filterbytags);
152+
153+
logger.LogTrace("Creating subset OpenApi document.");
109154
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
110155
}
111156
if (!string.IsNullOrEmpty(filterbycollection))
112157
{
113-
var fileStream = GetStream(filterbycollection);
114-
var requestUrls = ParseJsonCollectionFile(fileStream);
158+
var fileStream = await GetStream(filterbycollection, logger);
159+
var requestUrls = ParseJsonCollectionFile(fileStream, logger);
160+
161+
logger.LogTrace("Creating predicate based on the paths and Http methods defined in the Postman collection.");
115162
predicate = OpenApiFilterService.CreatePredicate(requestUrls: requestUrls, source:document);
163+
164+
logger.LogTrace("Creating subset OpenApi document.");
116165
document = OpenApiFilterService.CreateFilteredDocument(document, predicate);
117166
}
118167

168+
logger.LogTrace("Creating a new file");
119169
using var outputStream = output?.Create();
120-
121-
var textWriter = outputStream != null ? new StreamWriter(outputStream) : Console.Out;
170+
var textWriter = outputStream != null ? new StreamWriter(outputStream) : Console.Out;
122171

123172
var settings = new OpenApiWriterSettings()
124173
{
@@ -131,7 +180,14 @@ public static void ProcessOpenApiDocument(
131180
OpenApiFormat.Yaml => new OpenApiYamlWriter(textWriter, settings),
132181
_ => throw new ArgumentException("Unknown format"),
133182
};
183+
184+
logger.LogTrace("Serializing to OpenApi document using the provided spec version and writer");
185+
186+
stopwatch.Start();
134187
document.Serialize(writer, (OpenApiSpecVersion)version);
188+
stopwatch.Stop();
189+
190+
logger.LogTrace($"Finished serializing in {stopwatch.ElapsedMilliseconds}ms");
135191

136192
textWriter.Flush();
137193
}
@@ -184,26 +240,53 @@ public static OpenApiDocument FixReferences(OpenApiDocument document)
184240
return doc;
185241
}
186242

187-
private static Stream GetStream(string input)
243+
private static async Task<Stream> GetStream(string input, ILogger logger)
188244
{
245+
var stopwatch = new Stopwatch();
246+
stopwatch.Start();
247+
189248
Stream stream;
190249
if (input.StartsWith("http"))
191250
{
192-
var httpClient = new HttpClient(new HttpClientHandler()
251+
try
193252
{
194-
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
195-
})
253+
using var httpClientHandler = new HttpClientHandler()
254+
{
255+
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
256+
};
257+
using var httpClient = new HttpClient(httpClientHandler)
258+
{
259+
DefaultRequestVersion = HttpVersion.Version20
260+
};
261+
stream = await httpClient.GetStreamAsync(input);
262+
}
263+
catch (HttpRequestException ex)
196264
{
197-
DefaultRequestVersion = HttpVersion.Version20
198-
};
199-
stream = httpClient.GetStreamAsync(input).Result;
265+
logger.LogError($"Could not download the file at {input}, reason{ex}");
266+
return null;
267+
}
200268
}
201269
else
202270
{
203-
var fileInput = new FileInfo(input);
204-
stream = fileInput.OpenRead();
271+
try
272+
{
273+
var fileInput = new FileInfo(input);
274+
stream = fileInput.OpenRead();
275+
}
276+
catch (Exception ex) when (ex is FileNotFoundException ||
277+
ex is PathTooLongException ||
278+
ex is DirectoryNotFoundException ||
279+
ex is IOException ||
280+
ex is UnauthorizedAccessException ||
281+
ex is SecurityException ||
282+
ex is NotSupportedException)
283+
{
284+
logger.LogError($"Could not open the file at {input}, reason: {ex.Message}");
285+
return null;
286+
}
205287
}
206-
288+
stopwatch.Stop();
289+
logger.LogTrace("{timestamp}ms: Read file {input}", stopwatch.ElapsedMilliseconds, input);
207290
return stream;
208291
}
209292

@@ -212,11 +295,11 @@ private static Stream GetStream(string input)
212295
/// </summary>
213296
/// <param name="stream"> A file stream.</param>
214297
/// <returns> A dictionary of request urls and http methods from a collection.</returns>
215-
public static Dictionary<string, List<string>> ParseJsonCollectionFile(Stream stream)
298+
public static Dictionary<string, List<string>> ParseJsonCollectionFile(Stream stream, ILogger logger)
216299
{
217300
var requestUrls = new Dictionary<string, List<string>>();
218301

219-
// Convert file to JsonDocument
302+
logger.LogTrace("Parsing the json collection file into a JsonDocument");
220303
using var document = JsonDocument.Parse(stream);
221304
var root = document.RootElement;
222305
var itemElement = root.GetProperty("item");
@@ -235,21 +318,21 @@ public static Dictionary<string, List<string>> ParseJsonCollectionFile(Stream st
235318
requestUrls[path].Add(method);
236319
}
237320
}
238-
321+
logger.LogTrace("Finished fetching the list of paths and Http methods defined in the Postman collection.");
239322
return requestUrls;
240323
}
241324

242-
internal static void ValidateOpenApiDocument(string openapi)
325+
internal static async void ValidateOpenApiDocument(string openapi, LogLevel loglevel)
243326
{
244-
if (openapi == null)
327+
if (string.IsNullOrEmpty(openapi))
245328
{
246-
throw new ArgumentNullException("openapi");
329+
throw new ArgumentNullException(nameof(openapi));
247330
}
248-
249-
var stream = GetStream(openapi);
331+
var logger = ConfigureLoggerInstance(loglevel);
332+
var stream = await GetStream(openapi, logger);
250333

251334
OpenApiDocument document;
252-
335+
logger.LogTrace("Parsing the OpenApi file");
253336
document = new OpenApiStreamReader(new OpenApiReaderSettings
254337
{
255338
RuleSet = ValidationRuleSet.GetDefaultRuleSet()
@@ -268,12 +351,33 @@ internal static void ValidateOpenApiDocument(string openapi)
268351
var walker = new OpenApiWalker(statsVisitor);
269352
walker.Walk(document);
270353

354+
logger.LogTrace("Finished walking through the OpenApi document. Generating a statistics report..");
271355
Console.WriteLine(statsVisitor.GetStatisticsReport());
272356
}
273357

274-
private static OpenApiFormat GetOpenApiFormat(string openapi)
358+
private static OpenApiFormat GetOpenApiFormat(string openapi, ILogger logger)
275359
{
360+
logger.LogTrace("Getting the OpenApi format");
276361
return !openapi.StartsWith("http") && Path.GetExtension(openapi) == ".json" ? OpenApiFormat.Json : OpenApiFormat.Yaml;
277362
}
363+
364+
private static ILogger ConfigureLoggerInstance(LogLevel loglevel)
365+
{
366+
// Configure logger options
367+
#if DEBUG
368+
loglevel = loglevel > LogLevel.Debug ? LogLevel.Debug : loglevel;
369+
#endif
370+
371+
var logger = LoggerFactory.Create((builder) => {
372+
builder
373+
.AddConsole()
374+
#if DEBUG
375+
.AddDebug()
376+
#endif
377+
.SetMinimumLevel(loglevel);
378+
}).CreateLogger<OpenApiService>();
379+
380+
return logger;
381+
}
278382
}
279383
}

0 commit comments

Comments
 (0)