diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index b6944af2f..35633cb2f 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -7,127 +7,346 @@ trigger: branches: include: - master -pr: none + - vnext +pr: + branches: + include: + - master + - vnext pool: name: Azure Pipelines vmImage: windows-latest - demands: - - msbuild - - vstest - -steps: -- task: NuGetCommand@2 - displayName: 'NuGet restore' - -- task: MSBuild@1 - displayName: 'Build solution **/*.sln' - inputs: - configuration: Release - -- task: VSTest@2 - displayName: 'XUnit Tests' - inputs: - testAssemblyVer2: | - **\*.Tests.dll - - vsTestVersion: 16.0 - codeCoverageEnabled: true - -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - displayName: 'ESRP CodeSigning' - inputs: - ConnectedServiceName: 'microsoftgraph ESRP CodeSign DLL and NuGet (AKV)' - FolderPath: src - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolSign", - "parameters": [ - { - "parameterName": "OpusName", - "parameterValue": "Microsoft" - }, - { - "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" - }, - { - "parameterName": "FileDigest", - "parameterValue": "/fd \"SHA256\"" - }, - { - "parameterName": "PageHash", - "parameterValue": "/NPH" - }, - { - "parameterName": "TimeStamp", - "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" - } - ], - "toolName": "sign", - "toolVersion": "1.0" - }, - { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolVerify", - "parameters": [ ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 20 - -- task: MSBuild@1 - displayName: 'Pack OpenAPI' - inputs: - solution: src/Microsoft.OpenApi/Microsoft.OpenApi.csproj - configuration: Release - msbuildArguments: '/t:pack /p:PackageOutputPath=$(Build.ArtifactStagingDirectory) /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg' - -- task: MSBuild@1 - displayName: 'Pack OpenAPI Readers' - inputs: - solution: src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj - configuration: Release - msbuildArguments: '/t:pack /p:PackageOutputPath=$(Build.ArtifactStagingDirectory) /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg' - -- task: MSBuild@1 - displayName: 'Pack OpenApi Hidi' - inputs: - solution: src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj - configuration: Release - msbuildArguments: '/t:pack /p:PackageOutputPath=$(Build.ArtifactStagingDirectory) /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg' - -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - displayName: 'ESRP CodeSigning Nuget Packages' - inputs: - ConnectedServiceName: 'microsoftgraph ESRP CodeSign DLL and NuGet (AKV)' - FolderPath: '$(Build.ArtifactStagingDirectory)' - Pattern: '*.nupkg' - signConfigType: inlineSignParams - inlineOperation: | - [ - { - "keyCode": "CP-401405", - "operationSetCode": "NuGetSign", - "parameters": [ ], - "toolName": "sign", - "toolVersion": "1.0" - }, - { - "keyCode": "CP-401405", - "operationSetCode": "NuGetVerify", - "parameters": [ ], - "toolName": "sign", - "toolVersion": "1.0" - } - ] - SessionTimeout: 20 - -- task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: Nugets' - inputs: - ArtifactName: Nugets \ No newline at end of file + +variables: + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + ProductBinPath: '$(Build.SourcesDirectory)\src\Microsoft.OpenApi\bin\$(BuildConfiguration)' + + +stages: + +- stage: build + jobs: + - job: build + steps: + - task: UseDotNet@2 + displayName: 'Use .NET 6' + inputs: + version: 6.x + + - task: PoliCheck@1 + displayName: 'Run PoliCheck "/src"' + inputs: + inputType: CmdLine + cmdLineArgs: '/F:$(Build.SourcesDirectory)/src /T:9 /Sev:"1|2" /PE:2 /O:poli_result_src.xml' + + - task: PoliCheck@1 + displayName: 'Run PoliCheck "/test"' + inputs: + inputType: CmdLine + cmdLineArgs: '/F:$(Build.SourcesDirectory)/test /T:9 /Sev:"1|2" /PE:2 /O:poli_result_test.xml' + + # Install the nuget tool. + - task: NuGetToolInstaller@0 + displayName: 'Use NuGet >=5.2.0' + inputs: + versionSpec: '>=5.2.0' + checkLatest: true + + # Build the Product project + - task: DotNetCoreCLI@2 + displayName: 'build' + inputs: + projects: '$(Build.SourcesDirectory)\Microsoft.OpenApi.sln' + arguments: '--configuration $(BuildConfiguration) --no-incremental' + + # Run the Unit test + - task: DotNetCoreCLI@2 + displayName: 'test' + inputs: + command: test + projects: '$(Build.SourcesDirectory)\Microsoft.OpenApi.sln' + arguments: '--configuration $(BuildConfiguration) --no-build' + + # CredScan + - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 + displayName: 'Run CredScan - Src' + inputs: + toolMajorVersion: 'V2' + scanFolder: '$(Build.SourcesDirectory)\src' + debugMode: false + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 + displayName: 'Run CredScan - Test' + inputs: + toolMajorVersion: 'V2' + scanFolder: '$(Build.SourcesDirectory)\test' + debugMode: false + + - task: AntiMalware@3 + displayName: 'Run MpCmdRun.exe - ProductBinPath' + inputs: + FileDirPath: '$(ProductBinPath)' + enabled: false + + - task: BinSkim@3 + displayName: 'Run BinSkim - Product Binaries' + inputs: + InputType: Basic + AnalyzeTarget: '$(ProductBinPath)\**\Microsoft.OpenApi.dll' + AnalyzeSymPath: '$(ProductBinPath)' + AnalyzeVerbose: true + AnalyzeHashes: true + AnalyzeEnvironment: true + + - task: PublishSecurityAnalysisLogs@2 + displayName: 'Publish Security Analysis Logs' + inputs: + ArtifactName: SecurityLogs + + - task: PostAnalysis@1 + displayName: 'Post Analysis' + inputs: + BinSkim: true + CredScan: true + PoliCheck: true + + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'ESRP CodeSigning' + inputs: + ConnectedServiceName: 'microsoftgraph ESRP CodeSign DLL and NuGet (AKV)' + FolderPath: src + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd \"SHA256\"" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 20 + + # Pack + - task: DotNetCoreCLI@2 + displayName: 'pack OpenAPI' + inputs: + command: pack + projects: src/Microsoft.OpenApi/Microsoft.OpenApi.csproj + arguments: '-o $(Build.ArtifactStagingDirectory) --configuration $(BuildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg' + + # Pack + - task: DotNetCoreCLI@2 + displayName: 'pack Readers' + inputs: + command: pack + projects: src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj + arguments: '-o $(Build.ArtifactStagingDirectory) --configuration $(BuildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg' + + # Pack + - task: DotNetCoreCLI@2 + displayName: 'pack Hidi' + inputs: + command: pack + projects: src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj + arguments: '-o $(Build.ArtifactStagingDirectory) --configuration $(BuildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg' + + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'ESRP CodeSigning Nuget Packages' + inputs: + ConnectedServiceName: 'microsoftgraph ESRP CodeSign DLL and NuGet (AKV)' + FolderPath: '$(Build.ArtifactStagingDirectory)' + Pattern: '*.nupkg' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetSign", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 20 + + - task: PowerShell@2 + displayName: "Get Hidi's version-number from .csproj" + inputs: + targetType: 'inline' + script: | + $xml = [Xml] (Get-Content .\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj) + $version = $xml.Project.PropertyGroup.Version + echo $version + echo "##vso[task.setvariable variable=hidiversion]$version" + + # publish hidi as an .exe + - task: DotNetCoreCLI@2 + displayName: publish Hidi as executable + inputs: + command: 'publish' + arguments: -c Release --runtime win-x64 /p:PublishSingleFile=true --self-contained --output $(Build.ArtifactStagingDirectory)/Microsoft.OpenApi.Hidi-v$(hidiversion) -p:PublishTrimmed=true + projects: 'src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj' + publishWebProjects: False + zipAfterPublish: false + + - task: CopyFiles@2 + displayName: Prepare staging folder for upload + inputs: + targetFolder: $(Build.ArtifactStagingDirectory)/Nugets + sourceFolder: $(Build.ArtifactStagingDirectory) + content: '*.nupkg' + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: Nugets' + inputs: + ArtifactName: Nugets + PathtoPublish: '$(Build.ArtifactStagingDirectory)/Nugets' + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: Hidi' + inputs: + ArtifactName: Microsoft.OpenApi.Hidi-v$(hidiversion) + PathtoPublish: '$(Build.ArtifactStagingDirectory)/Microsoft.OpenApi.Hidi-v$(hidiversion)' + +- stage: deploy + condition: and(contains(variables['build.sourceBranch'], 'refs/heads/vnext'), succeeded()) + dependsOn: build + jobs: + - deployment: deploy_hidi + dependsOn: [] + environment: nuget-org + strategy: + runOnce: + deploy: + pool: + vmImage: ubuntu-latest + steps: + - task: DownloadPipelineArtifact@2 + displayName: Download nupkg from artifacts + inputs: + artifact: Nugets + source: current + # TODO update that script so it looks at the artifact name (name starts with) rather than a fixed index + - powershell: | + $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds/$env:BUILD_BUILDID/artifacts?api-version=4.1" + Write-Host "URL: $url" + $pipeline = Invoke-RestMethod -Uri $url -Headers @{ + Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" + } + Write-Host "artifactName:" ($artifactName = $Pipeline.value.name[1]) + #Set Variable $artifactName + Write-Host "##vso[task.setvariable variable=artifactName; isSecret=false; isOutput=true;]$artifactName" + displayName: 'Fetch Artifact Name' + - task: DownloadPipelineArtifact@2 + displayName: Download hidi executable from artifacts + inputs: + artifact: $(artifactName) + source: current + - task: NuGetCommand@2 + displayName: 'NuGet push' + inputs: + command: push + packagesToPush: '$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.Hidi.*.nupkg' + nuGetFeedType: external + publishFeedCredentials: 'OpenAPI Nuget Connection' + - task: GitHubRelease@1 + displayName: 'GitHub release (create)' + inputs: + gitHubConnection: 'Github-MaggieKimani1' + tagSource: userSpecifiedTag + tag: '$(artifactName)' + title: '$(artifactName)' + releaseNotesSource: inline + assets: '$(System.DefaultWorkingDirectory)\**\*.exe' + changeLogType: issueBased + + - deployment: deploy_lib + dependsOn: [] + environment: nuget-org + strategy: + runOnce: + deploy: + pool: + vmImage: ubuntu-latest + steps: + - task: DownloadPipelineArtifact@2 + displayName: Download nupkg from artifacts + inputs: + artifact: Nugets + source: current + - powershell: | + $fileNames = "$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.Hidi.*.nupkg", "$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.Readers.*.nupkg", "$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.Workbench.*.nupkg" + foreach($fileName in $fileNames) { + if(Test-Path $fileName) { + rm $fileName -Verbose + } + } + displayName: remove other nupkgs to avoid duplication + - task: NuGetCommand@2 + displayName: 'NuGet push' + inputs: + command: push + packagesToPush: '$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.*.nupkg' + nuGetFeedType: external + publishFeedCredentials: 'OpenAPI Nuget Connection' + + - deployment: deploy_readers + dependsOn: deploy_lib + environment: nuget-org + strategy: + runOnce: + deploy: + pool: + vmImage: ubuntu-latest + steps: + - task: DownloadPipelineArtifact@2 + displayName: Download nupkg from artifacts + inputs: + artifact: Nugets + source: current + - task: NuGetCommand@2 + displayName: 'NuGet push' + inputs: + command: push + packagesToPush: '$(Pipeline.Workspace)/Nugets/Microsoft.OpenApi.Readers.*.nupkg' + nuGetFeedType: external + publishFeedCredentials: 'OpenAPI Nuget Connection' diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 610134cd0..6f619ca85 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -14,9 +14,9 @@ jobs: GITHUB_RUN_NUMBER: ${{ github.run_number }} steps: - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x - name: Data gatherer id: data_gatherer diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 347ff8bca..1d2d4106d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -17,9 +17,9 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x - name: Initialize CodeQL id: init_codeql diff --git a/.vscode/launch.json b/.vscode/launch.json index c26bf0c9f..b59349979 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/bin/Debug/netcoreapp3.1/Microsoft.OpenApi.Hidi.dll", + "program": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/bin/Debug/net6.0/Microsoft.OpenApi.Hidi.dll", "args": [], "cwd": "${workspaceFolder}/src/Microsoft.OpenApi.Hidi", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 358fd0e1a..6040a610f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,16 +5,43 @@ "tasks": [ { "label": "build", - "type": "shell", - "command": "msbuild", + "command": "dotnet", + "type": "process", + "group": "build", + "args": [ + "build", + "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "test", + "command": "dotnet", + "type": "process", + "group": "test", "args": [ + "test", + "${workspaceFolder}/Microsoft.OpenApi.sln", "/property:GenerateFullPaths=true", - "/t:build" + "/consoleloggerparameters:NoSummary", + "--collect:\"XPlat Code Coverage\"" ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", "group": "build", - "presentation": { - "reveal": "silent" - }, + "args": [ + "watch", + "run", + "${workspaceFolder}/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], "problemMatcher": "$msCompile" }, { diff --git a/Microsoft.OpenApi.sln b/Microsoft.OpenApi.sln index dc489bff8..cca18f1e5 100644 --- a/Microsoft.OpenApi.sln +++ b/Microsoft.OpenApi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29613.14 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32210.238 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi", "src\Microsoft.OpenApi\Microsoft.OpenApi.csproj", "{A8E50143-69B2-472A-9D45-3F9A05D13202}" EndProject @@ -12,7 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution readme.md = readme.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Workbench", "src\Microsoft.OpenApi.Workbench\Microsoft.OpenApi.Workbench.csproj", "{6A5E91E5-0441-46EE-AEB9-8334981B7F08}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Workbench", "src\Microsoft.OpenApi.Workbench\Microsoft.OpenApi.Workbench.csproj", "{6A5E91E5-0441-46EE-AEB9-8334981B7F08}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Readers", "src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj", "{79933258-0126-4382-8755-D50820ECC483}" EndProject diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index a210a5c94..e33f4777e 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -2,9 +2,10 @@ Exe - netcoreapp3.1 + net6.0 9.0 true + http://go.microsoft.com/fwlink/?LinkID=288890 https://github.com/Microsoft/OpenAPI.NET MIT true @@ -14,12 +15,14 @@ Microsoft.OpenApi.Hidi hidi ./../../artifacts - 0.5.0-preview4 + 0.5.0-preview5 + OpenAPI.NET CLI tool for slicing OpenAPI documents © Microsoft Corporation. All rights reserved. OpenAPI .NET https://github.com/Microsoft/OpenAPI.NET -- Publish symbols. +- Upgrades Microsoft.OpenApi.OData to 1.0.10-preview1 +- Fixes an issue where hidi would not process async operations Microsoft.OpenApi.Hidi Microsoft.OpenApi.Hidi @@ -34,6 +37,8 @@ + + diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs index 3c9fdb7d5..1f86e3c06 100644 --- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs +++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs @@ -13,8 +13,11 @@ using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using System.Xml.Linq; +using Microsoft.OData.Edm.Csdl; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.OData; using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations; @@ -24,8 +27,9 @@ namespace Microsoft.OpenApi.Hidi { public class OpenApiService { - public static async void ProcessOpenApiDocument( + public static async Task ProcessOpenApiDocument( string openapi, + string csdl, FileInfo output, OpenApiSpecVersion? version, OpenApiFormat? format, @@ -41,9 +45,9 @@ string filterbycollection try { - if (string.IsNullOrEmpty(openapi)) + if (string.IsNullOrEmpty(openapi) && string.IsNullOrEmpty(csdl)) { - throw new ArgumentNullException(nameof(openapi)); + throw new ArgumentNullException("Please input a file path"); } } catch (ArgumentNullException ex) @@ -75,36 +79,56 @@ string filterbycollection logger.LogError(ex.Message); return; } - - var stream = await GetStream(openapi, logger); - // Parsing OpenAPI file + Stream stream; + OpenApiDocument document; + OpenApiFormat openApiFormat; var stopwatch = new Stopwatch(); - stopwatch.Start(); - logger.LogTrace("Parsing OpenApi file"); - var result = new OpenApiStreamReader(new OpenApiReaderSettings - { - ReferenceResolution = resolveexternal ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences, - RuleSet = ValidationRuleSet.GetDefaultRuleSet() - } - ).ReadAsync(stream).GetAwaiter().GetResult(); - var document = result.OpenApiDocument; - stopwatch.Stop(); - var context = result.OpenApiDiagnostic; - if (context.Errors.Count > 0) + if (!string.IsNullOrEmpty(csdl)) { - var errorReport = new StringBuilder(); + // Default to yaml and OpenApiVersion 3 during csdl to OpenApi conversion + openApiFormat = format ?? GetOpenApiFormat(csdl, logger); + version ??= OpenApiSpecVersion.OpenApi3_0; - foreach (var error in context.Errors) - { - errorReport.AppendLine(error.ToString()); - } - logger.LogError($"{stopwatch.ElapsedMilliseconds}ms: OpenApi Parsing errors {string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray())}"); + stream = await GetStream(csdl, logger); + document = await ConvertCsdlToOpenApi(stream); } else { - logger.LogTrace("{timestamp}ms: Parsed OpenApi successfully. {count} paths found.", stopwatch.ElapsedMilliseconds, document.Paths.Count); + stream = await GetStream(openapi, logger); + + // Parsing OpenAPI file + stopwatch.Start(); + logger.LogTrace("Parsing OpenApi file"); + var result = new OpenApiStreamReader(new OpenApiReaderSettings + { + ReferenceResolution = resolveexternal ? ReferenceResolutionSetting.ResolveAllReferences : ReferenceResolutionSetting.ResolveLocalReferences, + RuleSet = ValidationRuleSet.GetDefaultRuleSet() + } + ).ReadAsync(stream).GetAwaiter().GetResult(); + + document = result.OpenApiDocument; + stopwatch.Stop(); + + var context = result.OpenApiDiagnostic; + if (context.Errors.Count > 0) + { + var errorReport = new StringBuilder(); + + foreach (var error in context.Errors) + { + errorReport.AppendLine(error.ToString()); + } + logger.LogError($"{stopwatch.ElapsedMilliseconds}ms: OpenApi Parsing errors {string.Join(Environment.NewLine, context.Errors.Select(e => e.Message).ToArray())}"); + } + else + { + logger.LogTrace("{timestamp}ms: Parsed OpenApi successfully. {count} paths found.", stopwatch.ElapsedMilliseconds, document.Paths.Count); + } + + openApiFormat = format ?? GetOpenApiFormat(openapi, logger); + version ??= result.OpenApiDiagnostic.SpecificationVersion; } Func predicate; @@ -151,8 +175,6 @@ string filterbycollection ReferenceInline = inline ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences }; - var openApiFormat = format ?? GetOpenApiFormat(openapi, logger); - var openApiVersion = version ?? result.OpenApiDiagnostic.SpecificationVersion; IOpenApiWriter writer = openApiFormat switch { OpenApiFormat.Json => new OpenApiJsonWriter(textWriter, settings), @@ -163,7 +185,7 @@ string filterbycollection logger.LogTrace("Serializing to OpenApi document using the provided spec version and writer"); stopwatch.Start(); - document.Serialize(writer, openApiVersion); + document.Serialize(writer, (OpenApiSpecVersion)version); stopwatch.Stop(); logger.LogTrace($"Finished serializing in {stopwatch.ElapsedMilliseconds}ms"); @@ -171,6 +193,58 @@ string filterbycollection textWriter.Flush(); } + /// + /// Converts CSDL to OpenAPI + /// + /// The CSDL stream. + /// An OpenAPI document. + public static async Task ConvertCsdlToOpenApi(Stream csdl) + { + using var reader = new StreamReader(csdl); + var csdlText = await reader.ReadToEndAsync(); + var edmModel = CsdlReader.Parse(XElement.Parse(csdlText).CreateReader()); + + var settings = new OpenApiConvertSettings() + { + AddSingleQuotesForStringParameters = true, + AddEnumDescriptionExtension = true, + DeclarePathParametersOnPathItem = true, + EnableKeyAsSegment = true, + EnableOperationId = true, + ErrorResponsesAsDefault = false, + PrefixEntityTypeNameBeforeKey = true, + TagDepth = 2, + EnablePagination = true, + EnableDiscriminatorValue = false, + EnableDerivedTypesReferencesForRequestBody = false, + EnableDerivedTypesReferencesForResponses = false, + ShowRootPath = true, + ShowLinks = true + }; + OpenApiDocument document = edmModel.ConvertToOpenApi(settings); + + document = FixReferences(document); + + return document; + } + + /// + /// Fixes the references in the resulting OpenApiDocument. + /// + /// The converted OpenApiDocument. + /// A valid OpenApiDocument instance. + public static OpenApiDocument FixReferences(OpenApiDocument document) + { + // This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance. + // So we write it out, and read it back in again to fix it up. + + var sb = new StringBuilder(); + document.SerializeAsV3(new OpenApiYamlWriter(new StringWriter(sb))); + var doc = new OpenApiStringReader().Read(sb.ToString(), out _); + + return doc; + } + private static async Task GetStream(string input, ILogger logger) { var stopwatch = new Stopwatch(); @@ -181,13 +255,13 @@ private static async Task GetStream(string input, ILogger logger) { try { - using var httpClientHandler = new HttpClientHandler() + var httpClientHandler = new HttpClientHandler() { SslProtocols = System.Security.Authentication.SslProtocols.Tls12, }; using var httpClient = new HttpClient(httpClientHandler) { - DefaultRequestVersion = HttpVersion.Version20 + DefaultRequestVersion = HttpVersion.Version20 }; stream = await httpClient.GetStreamAsync(input); } @@ -253,7 +327,7 @@ public static Dictionary> ParseJsonCollectionFile(Stream st return requestUrls; } - internal static async void ValidateOpenApiDocument(string openapi, LogLevel loglevel) + internal static async Task ValidateOpenApiDocument(string openapi, LogLevel loglevel) { if (string.IsNullOrEmpty(openapi)) { @@ -286,10 +360,10 @@ internal static async void ValidateOpenApiDocument(string openapi, LogLevel logl Console.WriteLine(statsVisitor.GetStatisticsReport()); } - private static OpenApiFormat GetOpenApiFormat(string openapi, ILogger logger) + private static OpenApiFormat GetOpenApiFormat(string input, ILogger logger) { logger.LogTrace("Getting the OpenApi format"); - return !openapi.StartsWith("http") && Path.GetExtension(openapi) == ".json" ? OpenApiFormat.Json : OpenApiFormat.Yaml; + return !input.StartsWith("http") && Path.GetExtension(input) == ".json" ? OpenApiFormat.Json : OpenApiFormat.Yaml; } private static ILogger ConfigureLoggerInstance(LogLevel loglevel) diff --git a/src/Microsoft.OpenApi.Hidi/Program.cs b/src/Microsoft.OpenApi.Hidi/Program.cs index 841c710e5..95e6f63f2 100644 --- a/src/Microsoft.OpenApi.Hidi/Program.cs +++ b/src/Microsoft.OpenApi.Hidi/Program.cs @@ -19,6 +19,9 @@ static async Task Main(string[] args) var descriptionOption = new Option("--openapi", "Input OpenAPI description file path or URL"); descriptionOption.AddAlias("-d"); + var csdlOption = new Option("--csdl", "Input CSDL file path or URL"); + csdlOption.AddAlias("-cs"); + var outputOption = new Option("--output", () => new FileInfo("./output"), "The output directory path for the generated file.") { Arity = ArgumentArity.ZeroOrOne }; outputOption.AddAlias("-o"); @@ -57,6 +60,7 @@ static async Task Main(string[] args) var transformCommand = new Command("transform") { descriptionOption, + csdlOption, outputOption, versionOption, formatOption, @@ -68,8 +72,8 @@ static async Task Main(string[] args) resolveExternalOption, }; - transformCommand.SetHandler ( - OpenApiService.ProcessOpenApiDocument, descriptionOption, outputOption, versionOption, formatOption, logLevelOption, inlineOption, resolveExternalOption, filterByOperationIdsOption, filterByTagsOption, filterByCollectionOption); + transformCommand.SetHandler ( + OpenApiService.ProcessOpenApiDocument, descriptionOption, csdlOption, outputOption, versionOption, formatOption, logLevelOption, inlineOption, resolveExternalOption, filterByOperationIdsOption, filterByTagsOption, filterByCollectionOption); rootCommand.Add(transformCommand); rootCommand.Add(validateCommand); diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj index ac11100c2..b4c41e6aa 100644 --- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj +++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj @@ -10,7 +10,7 @@ Microsoft Microsoft.OpenApi.Readers Microsoft.OpenApi.Readers - 1.3.1-preview4 + 1.3.1-preview5 OpenAPI.NET Readers for JSON and YAML documents © Microsoft Corporation. All rights reserved. OpenAPI .NET @@ -36,7 +36,7 @@ - + diff --git a/src/Microsoft.OpenApi.Readers/ParsingContext.cs b/src/Microsoft.OpenApi.Readers/ParsingContext.cs index b7cfb6acb..6c4dece2f 100644 --- a/src/Microsoft.OpenApi.Readers/ParsingContext.cs +++ b/src/Microsoft.OpenApi.Readers/ParsingContext.cs @@ -60,13 +60,13 @@ internal OpenApiDocument Parse(YamlDocument yamlDocument) switch (inputVersion) { case string version when version == "2.0": - VersionService = new OpenApiV2VersionService(); + VersionService = new OpenApiV2VersionService(Diagnostic); doc = VersionService.LoadDocument(RootNode); this.Diagnostic.SpecificationVersion = OpenApiSpecVersion.OpenApi2_0; break; case string version when version.StartsWith("3.0"): - VersionService = new OpenApiV3VersionService(); + VersionService = new OpenApiV3VersionService(Diagnostic); doc = VersionService.LoadDocument(RootNode); this.Diagnostic.SpecificationVersion = OpenApiSpecVersion.OpenApi3_0; break; @@ -93,12 +93,12 @@ internal T ParseFragment(YamlDocument yamlDocument, OpenApiSpecVersion versio switch (version) { case OpenApiSpecVersion.OpenApi2_0: - VersionService = new OpenApiV2VersionService(); + VersionService = new OpenApiV2VersionService(Diagnostic); element = this.VersionService.LoadElement(node); break; case OpenApiSpecVersion.OpenApi3_0: - this.VersionService = new OpenApiV3VersionService(); + this.VersionService = new OpenApiV3VersionService(Diagnostic); element = this.VersionService.LoadElement(node); break; } diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiSecuritySchemeDeserializer.cs index 7e0c6c1dc..b2aab773c 100644 --- a/src/Microsoft.OpenApi.Readers/V2/OpenApiSecuritySchemeDeserializer.cs +++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiSecuritySchemeDeserializer.cs @@ -30,7 +30,7 @@ internal static partial class OpenApiV2Deserializer { case "basic": o.Type = SecuritySchemeType.Http; - o.Scheme = "basic"; + o.Scheme = OpenApiConstants.Basic; break; case "apiKey": diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2VersionService.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiV2VersionService.cs index 5baa580af..fbd4dbb85 100644 --- a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2VersionService.cs +++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiV2VersionService.cs @@ -20,6 +20,17 @@ namespace Microsoft.OpenApi.Readers.V2 /// internal class OpenApiV2VersionService : IOpenApiVersionService { + public OpenApiDiagnostic Diagnostic { get; } + + /// + /// Create Parsing Context + /// + /// Provide instance for diagnotic object for collecting and accessing information about the parsing. + public OpenApiV2VersionService(OpenApiDiagnostic diagnostic) + { + Diagnostic = diagnostic; + } + private IDictionary> _loaders = new Dictionary> { [typeof(IOpenApiAny)] = OpenApiV2Deserializer.LoadAny, @@ -154,7 +165,15 @@ public OpenApiReference ConvertToOpenApiReference(string reference, ReferenceTyp if (reference.StartsWith("#")) { // "$ref": "#/definitions/Pet" - return ParseLocalReference(segments[1]); + try + { + return ParseLocalReference(segments[1]); + } + catch (OpenApiException ex) + { + Diagnostic.Errors.Add(new OpenApiError(ex)); + return null; + } } // $ref: externalSource.yaml#/Pet diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiV3VersionService.cs index 2663b6a3b..bdaedf560 100644 --- a/src/Microsoft.OpenApi.Readers/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiV3VersionService.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 System; @@ -19,6 +19,17 @@ namespace Microsoft.OpenApi.Readers.V3 /// internal class OpenApiV3VersionService : IOpenApiVersionService { + public OpenApiDiagnostic Diagnostic { get; } + + /// + /// Create Parsing Context + /// + /// Provide instance for diagnotic object for collecting and accessing information about the parsing. + public OpenApiV3VersionService(OpenApiDiagnostic diagnostic) + { + Diagnostic = diagnostic; + } + private IDictionary> _loaders = new Dictionary> { [typeof(IOpenApiAny)] = OpenApiV3Deserializer.LoadAny, @@ -88,7 +99,15 @@ public OpenApiReference ConvertToOpenApiReference( if (reference.StartsWith("#")) { // "$ref": "#/components/schemas/Pet" - return ParseLocalReference(segments[1]); + try + { + return ParseLocalReference(segments[1]); + } + catch (OpenApiException ex) + { + Diagnostic.Errors.Add(new OpenApiError(ex)); + return null; + } } // Where fragments point into a non-OpenAPI document, the id will be the complete fragment identifier string id = segments[1]; diff --git a/src/Microsoft.OpenApi.Workbench/App.config b/src/Microsoft.OpenApi.Workbench/App.config deleted file mode 100644 index 4bfa00561..000000000 --- a/src/Microsoft.OpenApi.Workbench/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/Microsoft.OpenApi.Workbench/App.xaml b/src/Microsoft.OpenApi.Workbench/App.xaml index 40e1d5bad..d4fbb4a0c 100644 --- a/src/Microsoft.OpenApi.Workbench/App.xaml +++ b/src/Microsoft.OpenApi.Workbench/App.xaml @@ -3,12 +3,4 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Microsoft.OpenApi.Workbench" StartupUri="MainWindow.xaml"> - - - - - - - - diff --git a/src/Microsoft.OpenApi.Workbench/Microsoft.OpenApi.Workbench.csproj b/src/Microsoft.OpenApi.Workbench/Microsoft.OpenApi.Workbench.csproj index 47a9d6ffe..d56e31ec5 100644 --- a/src/Microsoft.OpenApi.Workbench/Microsoft.OpenApi.Workbench.csproj +++ b/src/Microsoft.OpenApi.Workbench/Microsoft.OpenApi.Workbench.csproj @@ -1,136 +1,34 @@ - - - + - Debug - AnyCPU - {6A5E91E5-0441-46EE-AEB9-8334981B7F08} + net6.0-windows WinExe - Microsoft.OpenApi.Workbench - Microsoft.OpenApi.Workbench - v4.8 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - - - + false + true + true - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - - MainWindow.xaml - Code - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - + + + all + + - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - + - + + - + + - - {79933258-0126-4382-8755-d50820ecc483} - Microsoft.OpenApi.Readers - - - {a8e50143-69b2-472a-9d45-3f9a05d13202} - Microsoft.OpenApi.Core - + + + + + - \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj index 7279e56db..7f3671942 100644 --- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj +++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj @@ -1,7 +1,7 @@  netstandard2.0 - 9.0 + Latest true http://go.microsoft.com/fwlink/?LinkID=288890 https://github.com/Microsoft/OpenAPI.NET @@ -11,7 +11,7 @@ Microsoft Microsoft.OpenApi Microsoft.OpenApi - 1.3.1-preview4 + 1.3.1-preview5 .NET models with JSON and YAML writers for OpenAPI specification © Microsoft Corporation. All rights reserved. OpenAPI .NET @@ -38,7 +38,7 @@ - + diff --git a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs index 3a29a88b1..553844764 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs @@ -617,6 +617,16 @@ public static class OpenApiConstants /// public const string Basic = "basic"; + /// + /// Field: Bearer + /// + public const string Bearer = "bearer"; + + /// + /// Field: JWT + /// + public const string Jwt = "JWT"; + /// /// Field: Consumes /// diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index 7f1a8ec04..d38bd7f9e 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -103,7 +103,8 @@ public static class OpenApiParameterRules new ValidationRule( (context, parameter) => { - if (parameter.In == ParameterLocation.Path && !context.PathString.Contains("{" + parameter.Name + "}")) + if (parameter.In == ParameterLocation.Path && + !(context.PathString.Contains("{" + parameter.Name + "}") || context.PathString.Contains("#/components"))) { context.Enter("in"); context.CreateError( 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 7ed607fd3..086d80d75 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj +++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj @@ -1,6 +1,6 @@  - net48;net50 + net6.0 false Microsoft @@ -242,8 +242,8 @@ - - + + diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV2Tests.cs index e374dc205..ff6641f88 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV2Tests.cs @@ -10,12 +10,18 @@ namespace Microsoft.OpenApi.Readers.Tests { public class ConvertToOpenApiReferenceV2Tests { + public OpenApiDiagnostic Diagnostic{get;} + + public ConvertToOpenApiReferenceV2Tests() + { + Diagnostic = new OpenApiDiagnostic(); + } [Fact] public void ParseExternalReference() { // Arrange - var versionService = new OpenApiV2VersionService(); + var versionService = new OpenApiV2VersionService(Diagnostic); var externalResource = "externalSchema.json"; var id = "externalPathSegment1/externalPathSegment2/externalPathSegment3"; var input = $"{externalResource}#/{id}"; @@ -33,7 +39,7 @@ public void ParseExternalReference() public void ParseLocalParameterReference() { // Arrange - var versionService = new OpenApiV2VersionService(); + var versionService = new OpenApiV2VersionService(Diagnostic); var referenceType = ReferenceType.Parameter; var id = "parameterId"; var input = $"#/parameters/{id}"; @@ -51,7 +57,7 @@ public void ParseLocalParameterReference() public void ParseLocalSchemaReference() { // Arrange - var versionService = new OpenApiV2VersionService(); + var versionService = new OpenApiV2VersionService(Diagnostic); var referenceType = ReferenceType.Schema; var id = "parameterId"; var input = $"#/definitions/{id}"; @@ -69,7 +75,7 @@ public void ParseLocalSchemaReference() public void ParseTagReference() { // Arrange - var versionService = new OpenApiV2VersionService(); + var versionService = new OpenApiV2VersionService(Diagnostic); var referenceType = ReferenceType.Tag; var id = "tagId"; var input = $"{id}"; @@ -87,7 +93,7 @@ public void ParseTagReference() public void ParseSecuritySchemeReference() { // Arrange - var versionService = new OpenApiV2VersionService(); + var versionService = new OpenApiV2VersionService(Diagnostic); var referenceType = ReferenceType.SecurityScheme; var id = "securitySchemeId"; var input = $"{id}"; diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV3Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV3Tests.cs index 04debfd7d..c4e88998e 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV3Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/ConvertToOpenApiReferenceV3Tests.cs @@ -10,12 +10,20 @@ namespace Microsoft.OpenApi.Readers.Tests { public class ConvertToOpenApiReferenceV3Tests { + public OpenApiDiagnostic Diagnostic { get; } + + public ConvertToOpenApiReferenceV3Tests() + { + Diagnostic = new OpenApiDiagnostic(); + } + + [Fact] public void ParseExternalReference() { // Arrange - var versionService = new OpenApiV3VersionService(); + var versionService = new OpenApiV3VersionService(Diagnostic); var externalResource = "externalSchema.json"; var id = "/externalPathSegment1/externalPathSegment2/externalPathSegment3"; var input = $"{externalResource}#{id}"; @@ -33,7 +41,7 @@ public void ParseExternalReference() public void ParseLocalParameterReference() { // Arrange - var versionService = new OpenApiV3VersionService(); + var versionService = new OpenApiV3VersionService(Diagnostic); var referenceType = ReferenceType.Parameter; var id = "parameterId"; var input = $"#/components/parameters/{id}"; @@ -51,7 +59,7 @@ public void ParseLocalParameterReference() public void ParseLocalSchemaReference() { // Arrange - var versionService = new OpenApiV3VersionService(); + var versionService = new OpenApiV3VersionService(Diagnostic); var referenceType = ReferenceType.Schema; var id = "schemaId"; var input = $"#/components/schemas/{id}"; @@ -69,7 +77,7 @@ public void ParseLocalSchemaReference() public void ParseTagReference() { // Arrange - var versionService = new OpenApiV3VersionService(); + var versionService = new OpenApiV3VersionService(Diagnostic); var referenceType = ReferenceType.Tag; var id = "tagId"; var input = $"{id}"; @@ -87,7 +95,7 @@ public void ParseTagReference() public void ParseSecuritySchemeReference() { // Arrange - var versionService = new OpenApiV3VersionService(); + var versionService = new OpenApiV3VersionService(Diagnostic); var referenceType = ReferenceType.SecurityScheme; var id = "securitySchemeId"; var input = $"{id}"; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSecuritySchemeTests.cs index 1a4a2a3d7..22f7d1633 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSecuritySchemeTests.cs @@ -38,7 +38,7 @@ public void ParseHttpSecuritySchemeShouldSucceed() new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, - Scheme = "basic" + Scheme = OpenApiConstants.Basic }); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs index 57c156cc0..9d7a27d72 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs @@ -40,7 +40,7 @@ public void ParseHttpSecuritySchemeShouldSucceed() new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, - Scheme = "basic" + Scheme = OpenApiConstants.Basic }); } } @@ -95,8 +95,8 @@ public void ParseBearerSecuritySchemeShouldSucceed() new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT" + Scheme = OpenApiConstants.Bearer, + BearerFormat = OpenApiConstants.Jwt }); } } diff --git a/test/Microsoft.OpenApi.SmokeTests/Microsoft.OpenApi.SmokeTests.csproj b/test/Microsoft.OpenApi.SmokeTests/Microsoft.OpenApi.SmokeTests.csproj index 44d85ee21..aadfb919d 100644 --- a/test/Microsoft.OpenApi.SmokeTests/Microsoft.OpenApi.SmokeTests.csproj +++ b/test/Microsoft.OpenApi.SmokeTests/Microsoft.OpenApi.SmokeTests.csproj @@ -1,15 +1,14 @@  - net48 + net6.0 - TRACE;DEBUG;NET48 - + diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj index d8fd47fd1..360eeea92 100644 --- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj +++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj @@ -1,6 +1,6 @@  - net50 + net6.0 false Microsoft @@ -15,20 +15,20 @@ - - - + + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -44,5 +44,8 @@ Always + + Always + \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 002143b15..7ba6d132c 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -57,7 +57,7 @@ public class OpenApiComponentsTests { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, - Scheme = "openIdConnectUrl", + Scheme = OpenApiConstants.Bearer, OpenIdConnectUrl = new Uri("https://example.com/openIdConnect") } } @@ -129,7 +129,7 @@ public class OpenApiComponentsTests { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, - Scheme = "openIdConnectUrl", + Scheme = OpenApiConstants.Bearer, OpenIdConnectUrl = new Uri("https://example.com/openIdConnect"), Reference = new OpenApiReference { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index b7871f51f..1294f0f48 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -32,15 +32,16 @@ public class OpenApiSecuritySchemeTests { Description = "description1", Type = SecuritySchemeType.Http, - Scheme = "basic", + Scheme = OpenApiConstants.Basic + }; public static OpenApiSecurityScheme HttpBearerSecurityScheme = new OpenApiSecurityScheme { Description = "description1", Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT", + Scheme = OpenApiConstants.Bearer, + BearerFormat = OpenApiConstants.Jwt }; public static OpenApiSecurityScheme OAuth2SingleFlowSecurityScheme = new OpenApiSecurityScheme @@ -103,7 +104,7 @@ public class OpenApiSecuritySchemeTests { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, - Scheme = "openIdConnectUrl", + Scheme = OpenApiConstants.Bearer, OpenIdConnectUrl = new Uri("https://example.com/openIdConnect") }; @@ -111,7 +112,7 @@ public class OpenApiSecuritySchemeTests { Description = "description1", Type = SecuritySchemeType.OpenIdConnect, - Scheme = "openIdConnectUrl", + Scheme = OpenApiConstants.Bearer, OpenIdConnectUrl = new Uri("https://example.com/openIdConnect"), Reference = new OpenApiReference { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index f700fee15..263e5dd12 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -358,6 +358,7 @@ namespace Microsoft.OpenApi.Models public const string AuthorizationUrl = "authorizationUrl"; public const string BasePath = "basePath"; public const string Basic = "basic"; + public const string Bearer = "bearer"; public const string BearerFormat = "bearerFormat"; public const string BodyName = "x-bodyName"; public const string Callbacks = "callbacks"; @@ -400,6 +401,7 @@ namespace Microsoft.OpenApi.Models public const string In = "in"; public const string Info = "info"; public const string Items = "items"; + public const string Jwt = "JWT"; public const string License = "license"; public const string Links = "links"; public const string Mapping = "mapping"; @@ -1206,7 +1208,7 @@ namespace Microsoft.OpenApi.Validations.Rules public static Microsoft.OpenApi.Validations.ValidationRule ResponsesMustBeIdentifiedByDefaultOrStatusCode { get; } public static Microsoft.OpenApi.Validations.ValidationRule ResponsesMustContainAtLeastOneResponse { get; } } - [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.All, AllowMultiple=false, Inherited=false)] + [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false, Inherited=false)] public class OpenApiRuleAttribute : System.Attribute { public OpenApiRuleAttribute() { } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiServiceTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiServiceTests.cs new file mode 100644 index 000000000..1c9fd003b --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiServiceTests.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.OpenApi.Hidi; +using Microsoft.OpenApi.Services; +using Xunit; + +namespace Microsoft.OpenApi.Tests.Services +{ + public class OpenApiServiceTests + { + [Fact] + public async Task ReturnConvertedCSDLFile() + { + // Arrange + var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles\\Todo.xml"); + var fileInput = new FileInfo(filePath); + var csdlStream = fileInput.OpenRead(); + + // Act + var openApiDoc = await OpenApiService.ConvertCsdlToOpenApi(csdlStream); + var expectedPathCount = 6; + + // Assert + Assert.NotNull(openApiDoc); + Assert.NotEmpty(openApiDoc.Paths); + Assert.Equal(expectedPathCount, openApiDoc.Paths.Count); + } + + [Theory] + [InlineData("Todos.Todo.UpdateTodo",null, 1)] + [InlineData("Todos.Todo.ListTodo",null, 1)] + [InlineData(null, "Todos.Todo", 4)] + public async Task ReturnFilteredOpenApiDocBasedOnOperationIdsAndInputCsdlDocument(string operationIds, string tags, int expectedPathCount) + { + // Arrange + var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles\\Todo.xml"); + var fileInput = new FileInfo(filePath); + var csdlStream = fileInput.OpenRead(); + + // Act + var openApiDoc = await OpenApiService.ConvertCsdlToOpenApi(csdlStream); + var predicate = OpenApiFilterService.CreatePredicate(operationIds, tags); + var subsetOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(openApiDoc, predicate); + + // Assert + Assert.NotNull(subsetOpenApiDocument); + Assert.NotEmpty(subsetOpenApiDocument.Paths); + Assert.Equal(expectedPathCount, subsetOpenApiDocument.Paths.Count); + } + } +} diff --git a/test/Microsoft.OpenApi.Tests/UtilityFiles/Todo.xml b/test/Microsoft.OpenApi.Tests/UtilityFiles/Todo.xml new file mode 100644 index 000000000..b3b07debf --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/UtilityFiles/Todo.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +