diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 0b9019a83..77dc8fd7b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -59,85 +59,10 @@ jobs: id: build_projects shell: pwsh run: | - $projectsArray = @( - '.\src\Microsoft.OpenApi\Microsoft.OpenApi.csproj', - '.\src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj', - '.\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj' - ) - $gitNewVersion = if ("${{ steps.tag_generator.outputs.new_version }}") {"${{ steps.tag_generator.outputs.new_version }}"} else {$null} - $projectCurrentVersion = ([xml](Get-Content .\src\Microsoft.OpenApi\Microsoft.OpenApi.csproj)).Project.PropertyGroup.Version - $projectNewVersion = $gitNewVersion ?? $projectCurrentVersion - - $projectsArray | ForEach-Object { - dotnet build $PSItem ` - -c Release # ` - # -o $env:ARTIFACTS_FOLDER ` - # /p:Version=$projectNewVersion - } - - # Move NuGet packages to separate folder for pipeline convenience - # New-Item Artifacts/NuGet -ItemType Directory - # Get-ChildItem Artifacts/*.nupkg | Move-Item -Destination "Artifacts/NuGet" + dotnet build Microsoft.OpenApi.sln -c Release - name: Run unit tests id: run_unit_tests shell: pwsh run: | - $testProjectsArray = @( - '.\test\Microsoft.OpenApi.Tests\Microsoft.OpenApi.Tests.csproj', - '.\test\Microsoft.OpenApi.Readers.Tests\Microsoft.OpenApi.Readers.Tests.csproj', - '.\test\Microsoft.OpenApi.SmokeTests\Microsoft.OpenApi.SmokeTests.csproj' - ) - - $testProjectsArray | ForEach-Object { - dotnet test $PSItem ` - -c Release - } - - # - if: steps.tag_generator.outputs.new_version != '' - # name: Upload NuGet packages as artifacts - # id: ul_packages_artifact - # uses: actions/upload-artifact@v1 - # with: - # name: NuGet packages - # path: Artifacts/NuGet/ - - cd: - if: needs.ci.outputs.is_default_branch == 'true' && needs.ci.outputs.latest_version != '' - name: Continuous Deployment - needs: ci - runs-on: ubuntu-latest - steps: - # - name: Download and extract NuGet packages - # id: dl_packages_artifact - # uses: actions/download-artifact@v2 - # with: - # name: NuGet packages - # path: NuGet/ - - # - name: Push NuGet packages to NuGet.org - # id: push_nuget_packages - # continue-on-error: true - # shell: pwsh - # run: | - # Get-ChildItem NuGet/*.nupkg | ForEach-Object { - # nuget push $PSItem ` - # -ApiKey $env:NUGET_API_KEY ` - # -Source https://api.nuget.org/v3/index.json - # } - # env: - # NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - - - name: Create and publish release - id: create_release - uses: softprops/action-gh-release@v1 - with: - name: OpenApi v${{ needs.ci.outputs.latest_version }} - tag_name: v${{ needs.ci.outputs.latest_version }} - # files: | - # NuGet/Microsoft.OpenApi.${{ needs.ci.outputs.latest_version }}.nupkg - # NuGet/Microsoft.OpenApi.Readers.${{ needs.ci.outputs.latest_version }}.nupkg - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -# Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) \ No newline at end of file + dotnet test Microsoft.OpenApi.sln -c Release -v n diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..1ec34f04f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,25 @@ + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + Microsoft + Microsoft + MIT + true + https://github.com/Microsoft/OpenAPI.NET + https://github.com/microsoft/OpenAPI.NET/releases + true + http://go.microsoft.com/fwlink/?LinkID=288890 + https://github.com/Microsoft/OpenAPI.NET + © Microsoft Corporation. All rights reserved. + OpenAPI .NET + + + + true + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 6b3507124..e67c8c389 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,12 @@ FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env WORKDIR /app COPY ./src ./hidi/src +COPY ./Directory.Build.props ./hidi/Directory.Build.props +COPY ./README.md ./hidi/README.md WORKDIR /app/hidi RUN dotnet publish ./src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj -c Release -FROM mcr.microsoft.com/dotnet/runtime:7.0 as runtime +FROM mcr.microsoft.com/dotnet/runtime:7.0 AS runtime WORKDIR /app COPY --from=build-env /app/hidi/src/Microsoft.OpenApi.Hidi/bin/Release/net7.0 ./ diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index bfc937cba..000000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - - - - - \ No newline at end of file diff --git a/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs b/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs index 9d5077432..5b83212d5 100644 --- a/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs +++ b/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. +// Licensed under the MIT license. using System.Collections.Generic; using System.CommandLine; diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index 450a05d21..183de1691 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -24,7 +24,7 @@ static PowerShellFormatter() { // Add singularization exclusions. // Enhancement: Read exclusions from a user provided file. - Vocabularies.Default.AddSingular("(drive)s$", "$1"); // drives does not properly singularize to drive. + Vocabularies.Default.AddSingular("(drive)s$", "$1"); // drives does not properly singularize to drive. Vocabularies.Default.AddSingular("(data)$", "$1"); // exclude the following from singularization. Vocabularies.Default.AddSingular("(delta)$", "$1"); Vocabularies.Default.AddSingular("(quota)$", "$1"); @@ -133,7 +133,7 @@ private static string SingularizeAndDeduplicateOperationId(IList operati singularizedSegments.Add(segment); } - return string.Join(".", singularizedSegments); + return string.Join('.', singularizedSegments); } private static string RemoveHashSuffix(string operationId) @@ -153,7 +153,7 @@ private static string RemoveKeyTypeSegment(string operationId, IList ResolveFunctionParameters(IList parameters) @@ -179,7 +179,7 @@ private void AddAdditionalPropertiesToSchema(OpenApiSchema schema) { if (schema != null && !_schemaLoop.Contains(schema) && "object".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)) { - schema.AdditionalProperties = new OpenApiSchema() { Type = "object" }; + schema.AdditionalProperties = new OpenApiSchema { Type = "object" }; /* Because 'additionalProperties' are now being walked, * we need a way to keep track of visited schemas to avoid diff --git a/src/Microsoft.OpenApi.Hidi/Logger.cs b/src/Microsoft.OpenApi.Hidi/Logger.cs index 717ca1a41..dec4a5f8e 100644 --- a/src/Microsoft.OpenApi.Hidi/Logger.cs +++ b/src/Microsoft.OpenApi.Hidi/Logger.cs @@ -21,7 +21,7 @@ public static ILoggerFactory ConfigureLogger(LogLevel logLevel) { c.IncludeScopes = true; }) -#if DEBUG +#if DEBUG .AddDebug() #endif .SetMinimumLevel(logLevel); diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index ced9d9c3c..5ee796e07 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -7,29 +7,14 @@ true true enable - http://go.microsoft.com/fwlink/?LinkID=288890 - https://github.com/Microsoft/OpenAPI.NET - MIT - true - Microsoft - Microsoft - Microsoft.OpenApi.Hidi - Microsoft.OpenApi.Hidi hidi ./../../artifacts - 1.3.0 + 1.3.1 OpenAPI.NET CLI tool for slicing OpenAPI documents - © Microsoft Corporation. All rights reserved. - OpenAPI .NET - https://github.com/Microsoft/OpenAPI.NET - https://github.com/microsoft/OpenAPI.NET/releases - Microsoft.OpenApi.Hidi - Microsoft.OpenApi.Hidi true true $(NoWarn);NU5048;NU5104;CA1848; - true readme.md All @@ -50,7 +35,7 @@ - + diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs index 809e3ecf9..9a8247c84 100644 --- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs +++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs @@ -41,7 +41,7 @@ internal static class OpenApiService /// /// Implementation of the transform command /// - public static async Task TransformOpenApiDocument(HidiOptions options, ILogger logger, CancellationToken cancellationToken) + public static async Task TransformOpenApiDocument(HidiOptions options, ILogger logger, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(options.OpenApi) && string.IsNullOrEmpty(options.Csdl) && string.IsNullOrEmpty(options.FilterOptions?.FilterByApiManifest)) { @@ -81,11 +81,11 @@ public static async Task TransformOpenApiDocument(HidiOptions options, ILogger l if (!string.IsNullOrEmpty(options.FilterOptions?.FilterByCollection)) { using var collectionStream = await GetStream(options.FilterOptions.FilterByCollection, logger, cancellationToken).ConfigureAwait(false); - postmanCollection = JsonDocument.Parse(collectionStream); + postmanCollection = await JsonDocument.ParseAsync(collectionStream, cancellationToken: cancellationToken).ConfigureAwait(false); } // Load OpenAPI document - OpenApiDocument document = await GetOpenApi(options, logger, cancellationToken, options.MetadataVersion).ConfigureAwait(false); + OpenApiDocument document = await GetOpenApi(options, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false); if (options.FilterOptions != null) { @@ -116,7 +116,7 @@ public static async Task TransformOpenApiDocument(HidiOptions options, ILogger l } } - private static async Task FindApiDependency(string? apiManifestPath, ILogger logger, CancellationToken cancellationToken) + private static async Task FindApiDependency(string? apiManifestPath, ILogger logger, CancellationToken cancellationToken = default) { ApiDependency? apiDependency = null; // If API Manifest is provided, load it, use it get the OpenAPI path @@ -132,7 +132,8 @@ public static async Task TransformOpenApiDocument(HidiOptions options, ILogger l } using (var fileStream = await GetStream(apiManifestRef[0], logger, cancellationToken).ConfigureAwait(false)) { - apiManifest = ApiManifestDocument.Load(JsonDocument.Parse(fileStream).RootElement); + var document = await JsonDocument.ParseAsync(fileStream, cancellationToken: cancellationToken).ConfigureAwait(false); + apiManifest = ApiManifestDocument.Load(document.RootElement); } apiDependency = !string.IsNullOrEmpty(apiDependencyName) && apiManifest.ApiDependencies.TryGetValue(apiDependencyName, out var dependency) ? dependency : apiManifest.ApiDependencies.First().Value; @@ -153,7 +154,7 @@ private static OpenApiDocument ApplyFilters(HidiOptions options, ILogger logger, requestUrls = EnumerateJsonDocument(postmanCollection.RootElement, new()); logger.LogTrace("Finished fetching the list of paths and Http methods defined in the Postman collection."); } - else + else { requestUrls = new(); logger.LogTrace("No filter options provided."); @@ -185,7 +186,7 @@ private static void WriteOpenApi(HidiOptions options, OpenApiFormat openApiForma using var outputStream = options.Output.Create(); using var textWriter = new StreamWriter(outputStream); - var settings = new OpenApiWriterSettings() + var settings = new OpenApiWriterSettings { InlineLocalReferences = options.InlineLocal, InlineExternalReferences = options.InlineExternal @@ -210,10 +211,9 @@ private static void WriteOpenApi(HidiOptions options, OpenApiFormat openApiForma } } - // Get OpenAPI document either from OpenAPI or CSDL - private static async Task GetOpenApi(HidiOptions options, ILogger logger, CancellationToken cancellationToken, string? metadataVersion = null) + // Get OpenAPI document either from OpenAPI or CSDL + private static async Task GetOpenApi(HidiOptions options, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default) { - OpenApiDocument document; Stream stream; @@ -284,7 +284,7 @@ private static async Task GetOpenApi(HidiOptions options, ILogg private static Dictionary> GetRequestUrlsFromManifest(ApiDependency apiDependency) { - // Get the request URLs from the API Dependencies in the API manifest + // Get the request URLs from the API Dependencies in the API manifest var requests = apiDependency .Requests.Where(static r => !r.Exclude && !string.IsNullOrEmpty(r.UriTemplate) && !string.IsNullOrEmpty(r.Method)) .Select(static r => new { UriTemplate = r.UriTemplate!, Method = r.Method! }) @@ -325,7 +325,7 @@ private static Stream ApplyFilterToCsdl(Stream csdlStream, string entitySetOrSin public static async Task ValidateOpenApiDocument( string openApi, ILogger logger, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(openApi)) { @@ -360,7 +360,7 @@ public static async Task ValidateOpenApiDocument( } } - private static async Task ParseOpenApi(string openApiFile, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken) + private static async Task ParseOpenApi(string openApiFile, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default) { ReadResult result; Stopwatch stopwatch = Stopwatch.StartNew(); @@ -453,13 +453,13 @@ private static Dictionary> EnumerateJsonDocument(JsonElemen // Fetch list of methods and urls from collection, store them in a dictionary var path = request.GetProperty("url").GetProperty("raw").ToString(); var method = request.GetProperty("method").ToString(); - if (!paths.ContainsKey(path)) + if (paths.TryGetValue(path, out var value)) { - paths.Add(path, new List { method }); + value.Add(method); } else { - paths[path].Add(method); + paths.Add(path, new List {method}); } } else @@ -479,7 +479,7 @@ private static Dictionary> EnumerateJsonDocument(JsonElemen /// /// Reads stream from file system or makes HTTP request depending on the input string /// - private static async Task GetStream(string input, ILogger logger, CancellationToken cancellationToken) + private static async Task GetStream(string input, ILogger logger, CancellationToken cancellationToken = default) { Stream stream; using (logger.BeginScope("Reading input stream")) @@ -509,13 +509,15 @@ private static async Task GetStream(string input, ILogger logger, Cancel var fileInput = new FileInfo(input); stream = fileInput.OpenRead(); } - catch (Exception ex) when (ex is FileNotFoundException || - ex is PathTooLongException || - ex is DirectoryNotFoundException || - ex is IOException || - ex is UnauthorizedAccessException || - ex is SecurityException || - ex is NotSupportedException) + catch (Exception ex) when ( + ex is + FileNotFoundException or + PathTooLongException or + DirectoryNotFoundException or + IOException or + UnauthorizedAccessException or + SecurityException or + NotSupportedException) { throw new InvalidOperationException($"Could not open the file at {input}", ex); } @@ -553,7 +555,7 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl return extension; } - internal static async Task ShowOpenApiDocument(HidiOptions options, ILogger logger, CancellationToken cancellationToken) + internal static async Task ShowOpenApiDocument(HidiOptions options, ILogger logger, CancellationToken cancellationToken = default) { try { @@ -562,7 +564,7 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl throw new ArgumentException("Please input a file path or URL"); } - var document = await GetOpenApi(options, logger, cancellationToken).ConfigureAwait(false); + var document = await GetOpenApi(options, logger, null, cancellationToken).ConfigureAwait(false); using (logger.BeginScope("Creating diagram")) { @@ -661,18 +663,21 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d { var rootNode = OpenApiUrlTreeNode.Create(document, "main"); - writer.WriteLine(@" - - - - - - -"); + writer.WriteLine( + """ + + + + + + + + + """); writer.WriteLine("

" + document.Info.Title + "

"); writer.WriteLine(); writer.WriteLine($"

API Description: {sourceUrl}

"); @@ -683,6 +688,7 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d { writer.WriteLine($"{style.Key.Replace("_", " ", StringComparison.OrdinalIgnoreCase)}"); } + writer.WriteLine(""); writer.WriteLine("
"); writer.WriteLine(""); @@ -690,23 +696,26 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d writer.WriteLine(""); // Write script tag to include JS library for rendering markdown - writer.WriteLine(@""); + writer.WriteLine( + """ + + """); // Write script tag to include JS library for rendering mermaid writer.WriteLine("= 2 && result < 3) { return OpenApiSpecVersion.OpenApi2_0; diff --git a/src/Microsoft.OpenApi.Hidi/Options/CommandOptions.cs b/src/Microsoft.OpenApi.Hidi/Options/CommandOptions.cs index 735644970..6fee866cb 100644 --- a/src/Microsoft.OpenApi.Hidi/Options/CommandOptions.cs +++ b/src/Microsoft.OpenApi.Hidi/Options/CommandOptions.cs @@ -104,6 +104,6 @@ public IReadOnlyList