diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index bbd00501d..9521826fe 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -66,6 +66,11 @@ extends: inputs: version: 8.x + - task: UseDotNet@2 + displayName: 'Use .NET 10' + inputs: + version: 10.x + # Install the nuget tool. - task: NuGetToolInstaller@1 displayName: 'Use NuGet >=6.11.0' @@ -94,19 +99,26 @@ extends: projects: '$(Build.SourcesDirectory)\Microsoft.OpenApi.OData.sln' arguments: '--configuration $(BuildConfiguration) --no-incremental' - # Run the Unit test + # Both suites are in the solution, but SDK10 cannot run MTP via VSTest. + # Keep OData on VSTest and invoke the hidi MTP executable separately (#885). - task: DotNetCoreCLI@2 displayName: 'test' inputs: command: test - projects: '$(Build.SourcesDirectory)\Microsoft.OpenApi.OData.sln' + projects: '$(Build.SourcesDirectory)\test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj' arguments: '--configuration $(BuildConfiguration) --no-build' + - pwsh: | + dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c $(BuildConfiguration) --no-build -- --minimum-expected-tests 1 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + displayName: 'Test hidi (Microsoft.Testing.Platform)' + - task: EsrpCodeSigning@6 displayName: 'ESRP CodeSigning' inputs: ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - FolderPath: 'src' + FolderPath: 'bin\$(BuildConfiguration)' + Pattern: 'Microsoft.OpenApi.OData.Reader.dll' AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' AuthAKVName: 'akv-prod-eastus' @@ -242,7 +254,7 @@ extends: vmImage: ubuntu-latest steps: - pwsh: | - $artifactName = Get-ChildItem -Path $(Pipeline.Workspace) -Filter Microsoft.OpenApi.*.nupkg -recurse | select -First 1 + $artifactName = Get-ChildItem -Path $(Pipeline.Workspace) -Filter Microsoft.OpenApi.OData.*.nupkg -recurse | select -First 1 $artifactVersion= $artifactName.Name -replace "Microsoft.OpenApi.OData.", "" -replace ".nupkg", "" #Set Variable $artifactName and $artifactVersion Write-Host "##vso[task.setvariable variable=artifactVersion; isSecret=false;]$artifactVersion" @@ -258,5 +270,5 @@ extends: tag: 'v$(artifactVersion)' title: 'v$(artifactVersion)' releaseNotesSource: inline - assets: '$(Pipeline.Workspace)\**\*.nupkg' + assets: '$(Pipeline.Workspace)\**\Microsoft.OpenApi.OData.*.nupkg' addChangeLog: false diff --git a/.azure-pipelines/hidi-release.yml b/.azure-pipelines/hidi-release.yml new file mode 100644 index 000000000..0d16e78c6 --- /dev/null +++ b/.azure-pipelines/hidi-release.yml @@ -0,0 +1,346 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +name: Hidi_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r) + +trigger: + branches: + include: + - main + tags: + include: + - hidi-v3.* +pr: + branches: + include: + - main + +variables: + buildConfiguration: Release + # Keep OFF until destination merges and source publishing is cut over. + hidiPublishingEnabled: 'false' + hidiPreviewPublishingEnabled: 'false' + +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + image: windows-latest + os: windows + stages: + - stage: build + jobs: + - job: hidi + templateContext: + outputs: + - output: pipelineArtifact + artifactName: Hidi + targetPath: '$(Build.ArtifactStagingDirectory)\hidi' + - output: pipelineArtifact + artifactName: HidiDockerContext + targetPath: '$(Build.ArtifactStagingDirectory)\hidi-docker-context' + steps: + - task: UseDotNet@2 + displayName: Use .NET 6 for ESRP + inputs: + version: 6.x + - task: UseDotNet@2 + displayName: Use .NET 8 + inputs: + version: 8.x + - task: UseDotNet@2 + displayName: Use .NET 10 + inputs: + version: 10.x + - task: NuGetToolInstaller@1 + inputs: + versionSpec: '>=6.11.0' + checkLatest: true + - task: NuGetAuthenticate@1 + displayName: Authenticate to Azure Artifacts + - pwsh: | + @" + + + + + + + + "@ | Set-Content -Path "$(Build.SourcesDirectory)/nuget.config" -Encoding UTF8 + displayName: Create nuget.config (central feed) + - pwsh: | + $ErrorActionPreference = 'Stop' + $sourceRoot = '$(Build.SourcesDirectory)' + $context = Join-Path '$(Build.ArtifactStagingDirectory)' 'hidi-docker-context' + New-Item -ItemType Directory -Path $context | Out-Null + $rootFiles = @('Dockerfile', '.dockerignore', 'Directory.Build.props', 'Build.props', 'build.root', 'global.json', 'README.md', 'src/Build.props') + foreach ($relativePath in $rootFiles) { + $destination = Join-Path $context $relativePath + New-Item -ItemType Directory -Force (Split-Path $destination -Parent) | Out-Null + Copy-Item -LiteralPath (Join-Path $sourceRoot $relativePath) -Destination $destination + } + foreach ($sourceDirectory in @('src/Microsoft.OpenApi.Hidi', 'src/Microsoft.OpenApi.OData.Reader')) { + $directory = Join-Path $sourceRoot $sourceDirectory + foreach ($file in Get-ChildItem -LiteralPath $directory -File -Recurse -Force) { + $relativePath = [IO.Path]::GetRelativePath($sourceRoot, $file.FullName) + if ($relativePath -match '(^|[\\/])(bin|obj|\.git|artifacts)([\\/]|$)' -or $file.Extension -in @('.snk', '.pfx', '.p12', '.pem', '.key')) { continue } + if ($file.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw "Unexpected linked Docker context file: $relativePath" } + $destination = Join-Path $context $relativePath + New-Item -ItemType Directory -Force (Split-Path $destination -Parent) | Out-Null + Copy-Item -LiteralPath $file.FullName -Destination $destination + } + } + foreach ($keyName in @('Microsoft.OpenApi.Hidi.public.snk', 'Microsoft.OpenApi.OData.public.snk')) { + $keyPath = Join-Path $sourceRoot 'tool' $keyName + $key = [IO.File]::ReadAllBytes($keyPath) + if ($key.Length -ne 160 -or $key[12] -ne 6 -or [Text.Encoding]::ASCII.GetString($key, 20, 4) -ne 'RSA1') { + throw "Expected the public-only strong-name identity: $keyName" + } + New-Item -ItemType Directory -Force (Join-Path $context 'tool') | Out-Null + Copy-Item -LiteralPath $keyPath -Destination (Join-Path $context 'tool' $keyName) + } + $keys = @(Get-ChildItem -LiteralPath $context -File -Recurse -Force -Filter '*.snk') + if ($keys.Count -ne 2) { throw "Expected exactly two public-only signing keys in the Docker context." } + foreach ($file in Get-ChildItem -LiteralPath $context -File -Recurse -Force) { + $relativePath = [IO.Path]::GetRelativePath($context, $file.FullName) + if ($relativePath -match '(^|[\\/])(bin|obj|\.git|artifacts)([\\/]|$)' -or $file.Extension -in @('.pfx', '.p12', '.pem', '.key')) { + throw "Forbidden Docker context file: $relativePath" + } + if ($file.Extension -eq '.snk' -and $relativePath -notmatch '^tool[\\/]Microsoft\.OpenApi\.(Hidi|OData)\.public\.snk$') { + throw "Unexpected Docker signing key: $relativePath" + } + } + displayName: Stage public-only hidi Docker context + - pwsh: | + $version = ([xml](Get-Content src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj)).Project.PropertyGroup.Version + if ($version -notmatch '^3\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected a hidi 3.x version, got $version." } + if ('$(Build.SourceBranch)' -like 'refs/tags/*' -and '$(Build.SourceBranch)' -ne "refs/tags/hidi-v$version") { + throw "Hidi tag must exactly match the hidi project version." + } + Write-Host "##vso[task.setvariable variable=HidiVersion]$version" + dotnet build src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) -p:GeneratePackageOnBuild=false + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c $(buildConfiguration) -- --minimum-expected-tests 1 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet publish src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) -r win-x64 --self-contained true -p:PublishSingleFile=true -p:PackAsTool=false -p:GeneratePackageOnBuild=false -o artifacts\hidi\win-x64 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & .\artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe --help + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + New-Item -ItemType Directory -Force artifacts\hidi\signing | Out-Null + Copy-Item src\Microsoft.OpenApi.Hidi\bin\$(buildConfiguration)\net8.0\Microsoft.OpenApi.Hidi.dll artifacts\hidi\signing + Copy-Item artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe artifacts\hidi\signing + displayName: Build, test and stage hidi binaries + - task: EsrpCodeSigning@6 + displayName: Sign hidi DLL and Windows executable + inputs: + ConnectedServiceName: Federated DevX ESRP Managed Identity Connection + FolderPath: 'artifacts\hidi\signing' + Pattern: 'Microsoft.OpenApi.Hidi.*' + AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' + AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' + AuthAKVName: akv-prod-eastus + AuthCertName: ReferenceLibraryPrivateCert + AuthSignCertName: ReferencePackagePublisherCertificate + 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' + MaxConcurrency: '50' + MaxRetryAttempts: '5' + PendingAnalysisWaitTimeoutMinutes: '5' + - pwsh: | + Copy-Item artifacts\hidi\signing\Microsoft.OpenApi.Hidi.dll src\Microsoft.OpenApi.Hidi\bin\$(buildConfiguration)\net8.0\Microsoft.OpenApi.Hidi.dll + Copy-Item artifacts\hidi\signing\Microsoft.OpenApi.Hidi.exe artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe + New-Item -ItemType Directory -Force '$(Build.ArtifactStagingDirectory)\hidi' | Out-Null + dotnet pack src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) --no-build -o '$(Build.ArtifactStagingDirectory)\hidi' + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + Compress-Archive -Path artifacts\hidi\win-x64\* -DestinationPath '$(Build.ArtifactStagingDirectory)\hidi\hidi-win-x64-$(HidiVersion).zip' + Copy-Item artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe '$(Build.ArtifactStagingDirectory)\hidi\Microsoft.OpenApi.Hidi.exe' + displayName: Pack signed hidi binaries + - task: EsrpCodeSigning@6 + displayName: Sign hidi NuGet package + inputs: + ConnectedServiceName: Federated DevX ESRP Managed Identity Connection + FolderPath: '$(Build.ArtifactStagingDirectory)\hidi' + Pattern: 'Microsoft.OpenApi.Hidi.$(HidiVersion).nupkg' + AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' + AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' + AuthAKVName: akv-prod-eastus + AuthCertName: ReferenceLibraryPrivateCert + AuthSignCertName: ReferencePackagePublisherCertificate + 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: '60' + MaxConcurrency: '50' + MaxRetryAttempts: '5' + PendingAnalysisWaitTimeoutMinutes: '5' + - stage: publish + dependsOn: build + condition: and(succeeded(), eq(variables.hidiPublishingEnabled, 'true'), startsWith(variables['Build.SourceBranch'], 'refs/tags/hidi-v3.')) + jobs: + - deployment: publish_hidi + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: Hidi + targetPath: '$(Pipeline.Workspace)\hidi' + environment: nuget-org + strategy: + runOnce: + deploy: + steps: + - pwsh: | + $tag = '$(Build.SourceBranch)' -replace '^refs/tags/hidi-v', '' + if ([version]($tag -split '-')[0] -le [version]'3.10.2') { throw "Never republish the source migration baseline or an older hidi version." } + $package = "$(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.$tag.nupkg" + if (-not (Test-Path $package)) { throw "Missing exact hidi package: $package" } + Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$tag" + displayName: Verify new hidi release version and exact package + - task: 1ES.PublishNuget@1 + displayName: Publish hidi NuGet tool + inputs: + packagesToPush: '$(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.$(HidiReleaseVersion).nupkg' + nuGetFeedType: external + publishFeedCredentials: OpenAPI Nuget Connection + packageParentPath: '$(Pipeline.Workspace)\hidi' + - task: GitHubRelease@1 + displayName: Attach signed hidi release artifacts + inputs: + gitHubConnection: Github-MaggieKimani1 + action: edit + tagSource: userSpecifiedTag + tag: 'hidi-v$(HidiReleaseVersion)' + title: 'Hidi v$(HidiReleaseVersion)' + assets: | + $(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.$(HidiReleaseVersion).nupkg + $(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.exe + $(Pipeline.Workspace)\hidi\hidi-win-x64-$(HidiReleaseVersion).zip + addChangeLog: false + - deployment: publish_container + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: HidiDockerContext + targetPath: '$(Pipeline.Workspace)/hidi-docker-context' + environment: docker-images-deploy + strategy: + runOnce: + deploy: + pool: + vmImage: ubuntu-latest + steps: + - pwsh: | + $version = ([xml](Get-Content src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj)).Project.PropertyGroup.Version + if ('$(Build.SourceBranch)' -ne "refs/tags/hidi-v$version") { throw "Hidi tag does not match project version." } + if ([version]($version -split '-')[0] -le [version]'3.10.2') { throw "Do not republish the migration baseline or an older hidi version." } + Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$version" + displayName: Read independent hidi version + workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context' + - task: AzureCLI@2 + displayName: Publish multi-platform hidi image + inputs: + azureSubscription: ACR Images Push Service Connection + scriptType: bash + scriptLocation: inlineScript + workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context' + inlineScript: | + set -euo pipefail + az acr login --name msgraphprodregistry + docker run --privileged --rm tonistiigi/binfmt --install all + docker buildx create --use + docker buildx build --platform linux/amd64,linux/arm64/v8 \ + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiReleaseVersion)" \ + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:latest" \ + --push . + - stage: preview + dependsOn: build + condition: and(succeeded(), eq(variables.hidiPublishingEnabled, 'true'), eq(variables.hidiPreviewPublishingEnabled, 'true'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + jobs: + - deployment: publish_preview_container + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: HidiDockerContext + targetPath: '$(Pipeline.Workspace)/hidi-docker-context' + environment: docker-images-deploy + strategy: + runOnce: + deploy: + pool: + vmImage: ubuntu-latest + steps: + - pwsh: | + $version = ([xml](Get-Content src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj)).Project.PropertyGroup.Version + if ($version -notmatch '^3\.\d+\.\d+$') { throw "Expected a stable hidi 3.x base version." } + $previewVersion = "$version.$([DateTime]::UtcNow.ToString('yyyyMMdd'))$(Build.BuildId)" + Write-Host "##vso[task.setvariable variable=HidiPreviewVersion]$previewVersion" + displayName: Compute independent hidi preview tag + workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context' + - task: AzureCLI@2 + displayName: Publish multi-platform hidi preview image + inputs: + azureSubscription: ACR Images Push Service Connection + scriptType: bash + scriptLocation: inlineScript + workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context' + inlineScript: | + set -euo pipefail + az acr login --name msgraphprodregistry + docker run --privileged --rm tonistiigi/binfmt --install all + docker buildx create --use + docker buildx build --platform linux/amd64,linux/arm64/v8 \ + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiPreviewVersion)" \ + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:nightly" \ + --push . diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..b9099d2c0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +**/bin +**/obj +**/artifacts +.git +.vs +.idea +test +**/*.snk +!tool/Microsoft.OpenApi.Hidi.public.snk +!tool/Microsoft.OpenApi.OData.public.snk diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 2574f3a2a..05205e8ea 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -19,7 +19,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: - dotnet-version: 8.0.x + dotnet-version: | + 8.0.x + 10.0.x - name: Data gatherer id: data_gatherer @@ -74,6 +76,7 @@ jobs: -c Release # ` # -o $env:ARTIFACTS_FOLDER ` # /p:Version=$projectNewVersion + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } # Move NuGet packages to separate folder for pipeline convenience @@ -91,8 +94,65 @@ jobs: $testProjectsArray | ForEach-Object { dotnet test $PSItem ` -c Release + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } + - name: Run hidi tests (Microsoft.Testing.Platform) + shell: pwsh + run: | + dotnet run --project .\test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c Release -- --minimum-expected-tests 1 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + - name: Pack and install hidi locally + shell: pwsh + run: | + dotnet pack .\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c Release --no-build -o .\artifacts\hidi\nuget + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + .\install-tool.ps1 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $workspace = (Get-Location).Path + $fixtures = Join-Path $workspace 'test' 'Microsoft.OpenApi.Hidi.Tests' 'UtilityFiles' + $outputs = Join-Path $workspace 'artifacts' 'hidi' + $hidi = Join-Path $outputs 'installed' 'hidi' + $sampleInput = Join-Path $fixtures 'SampleOpenApi.yml' + $csdlInput = Join-Path $fixtures 'Todo.xml' + $jsonOutput = Join-Path $outputs 'openapi.json' + $defaultOutput = Join-Path $outputs 'openapi-default.json' + $csdlOutput = Join-Path $outputs 'csdl.yaml' + $diagramOutput = Join-Path $outputs 'diagram.md' + & $hidi --help + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & $hidi validate --openapi $sampleInput + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & $hidi transform --openapi $sampleInput --format json --version 3.0 --output $jsonOutput --clean-output + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & $hidi transform --csdl $csdlInput --format yaml --version 3.0 --output $csdlOutput --clean-output + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $document = Get-Content $jsonOutput -Raw | ConvertFrom-Json + if ($document.openapi -notlike '3.0.*' -or @($document.paths.PSObject.Properties).Count -eq 0) { + throw "Expected an OpenAPI 3.0 document with paths from SampleOpenApi." + } + & $hidi transform --openapi $sampleInput --format json --output $defaultOutput --clean-output + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $defaultDocument = Get-Content $defaultOutput -Raw | ConvertFrom-Json + if ($defaultDocument.openapi -notlike '3.2.*' -or @($defaultDocument.paths.PSObject.Properties).Count -eq 0) { + throw "Expected main's default OpenAPI 3.2 behavior with paths." + } + $csdlDocument = Get-Content $csdlOutput -Raw + if ($csdlDocument -notmatch '(?m)^openapi:\s*3\.0\.' -or $csdlDocument -notmatch '(?m)^ /Todos:\s*$' -or $csdlDocument -notmatch '(?m)^ schemas:\s*$') { + throw "Expected OpenAPI 3.0, /Todos paths and schemas in the CSDL YAML output." + } + & $hidi show --openapi $sampleInput --output $diagramOutput + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + if (-not (Select-String $diagramOutput -Pattern 'mermaid' -Quiet)) { throw "Expected a Mermaid diagram from hidi show." } + + - name: Upload hidi NuGet artifact (not a release) + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: hidi-nuget + path: artifacts/hidi/nuget + if-no-files-found: error + # - if: steps.tag_generator.outputs.new_version != '' # name: Upload NuGet packages as artifacts # id: ul_packages_artifact @@ -101,6 +161,68 @@ jobs: # name: NuGet packages # path: Artifacts/NuGet/ + hidi-windows: + name: Hidi Windows executable + runs-on: windows-latest + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + dotnet-version: | + 8.0.x + 10.0.x + - name: Publish and smoke-test Windows executable + shell: pwsh + run: | + dotnet publish .\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:PackAsTool=false -p:GeneratePackageOnBuild=false -o .\artifacts\hidi\win-x64 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & .\artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe --help + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + Compress-Archive -Path .\artifacts\hidi\win-x64\* -DestinationPath .\artifacts\hidi\hidi-win-x64.zip + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: hidi-windows-executable + path: | + artifacts/hidi/hidi-win-x64.zip + artifacts/hidi/win-x64/Microsoft.OpenApi.Hidi.exe + if-no-files-found: error + + hidi-docker: + name: Hidi Docker build + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Build and smoke-test Docker image (no push) + run: | + set -euo pipefail + docker build --tag hidi:ci . + docker run --rm hidi:ci --help + mkdir -p artifacts/hidi/docker + docker run --rm --user "$(id -u):$(id -g)" \ + --mount "type=bind,source=$PWD/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/SampleOpenApi.yml,target=/app/openapi.yml,readonly" \ + --mount "type=bind,source=$PWD/artifacts/hidi/docker,target=/app/output" \ + hidi:ci transform --openapi /app/openapi.yml --format json --output /app/output/openapi.json --clean-output + docker run --rm --user "$(id -u):$(id -g)" \ + --mount "type=bind,source=$PWD/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/Todo.xml,target=/app/api.csdl,readonly" \ + --mount "type=bind,source=$PWD/artifacts/hidi/docker,target=/app/output" \ + hidi:ci transform --csdl /app/api.csdl --format yaml --version 3.0 --output /app/output/csdl.yaml --clean-output + - name: Verify Docker transformation outputs + shell: pwsh + run: | + $outputs = Join-Path (Get-Location).Path 'artifacts' 'hidi' 'docker' + $document = Get-Content (Join-Path $outputs 'openapi.json') -Raw | ConvertFrom-Json + if ($document.openapi -notlike '3.2.*' -or @($document.paths.PSObject.Properties).Count -eq 0) { + throw "Expected main's default OpenAPI 3.2 behavior with paths in Docker." + } + $csdlDocument = Get-Content (Join-Path $outputs 'csdl.yaml') -Raw + if ($csdlDocument -notmatch '(?m)^openapi:\s*3\.0\.' -or $csdlDocument -notmatch '(?m)^ /Todos:\s*$' -or $csdlDocument -notmatch '(?m)^ schemas:\s*$') { + throw "Expected OpenAPI 3.0, /Todos paths and schemas in the Docker CSDL YAML output." + } + cd: if: needs.ci.outputs.is_default_branch == 'true' && needs.ci.outputs.latest_version != '' name: Continuous Deployment diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4f97ad3bb..ac02bed91 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -44,7 +44,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: - dotnet-version: 8.0.x + dotnet-version: | + 8.0.x + 10.0.x # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -62,7 +64,7 @@ jobs: # uses: github/codeql-action/autobuild@v2 - name: build - run: dotnet build src\Microsoft.OpenApi.OData.Reader\Microsoft.OpenAPI.OData.Reader.csproj -c Release + run: dotnet build Microsoft.OpenApi.OData.sln -c Release # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl diff --git a/.github/workflows/release-please-gha.yml b/.github/workflows/release-please-gha.yml index 31b2ea292..f503b3d48 100644 --- a/.github/workflows/release-please-gha.yml +++ b/.github/workflows/release-please-gha.yml @@ -50,3 +50,25 @@ jobs: config-file: release-please-config.json manifest-file: .release-please-manifest.json target-branch: ${{ github.ref_name }} + + release-please-hidi: + # Enable only after destination merges and source publishing is cut over. + if: ${{ false }} + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} + private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} + - name: Release Please (independent hidi version) + uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 + with: + token: ${{ steps.app-token.outputs.token }} + config-file: hidi-release-please-config.json + manifest-file: .hidi-release-please-manifest.json + target-branch: ${{ github.ref_name }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index f39b75988..a0900ac26 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -43,7 +43,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: - dotnet-version: 8.0.x + dotnet-version: | + 8.0.x + 10.0.x - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis @@ -62,8 +64,26 @@ jobs: CoverletOutputFormat: 'opencover' # https://github.com/microsoft/vstest/issues/4014#issuecomment-1307913682 shell: pwsh run: | - dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml" + dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet workload restore + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet build - dotnet test Microsoft.OpenApi.OData.sln --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet test test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj --no-build -- --minimum-expected-tests 1 --coverlet --coverlet-output-format opencover --coverlet-include "[Microsoft.OpenApi.Hidi]*" --results-directory artifacts\hidi\coverage + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $reports = @(Get-ChildItem artifacts\hidi\coverage -Filter '*opencover*.xml') + if ($reports.Count -eq 0) { throw "Hidi OpenCover report was not generated." } + $hidiModules = @($reports | ForEach-Object { + ([xml](Get-Content $_.FullName -Raw)).CoverageSession.Modules.Module + } | Where-Object { $_.ModuleName -eq 'Microsoft.OpenApi.Hidi' }) + if (-not ($hidiModules | Where-Object { + $_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint').Count -gt 0 -and + $_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint[@vc > 0]').Count -gt 0 + })) { + throw "Hidi OpenCover report contains no covered Hidi sequence points." + } dotnet tool run dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/.hidi-release-please-manifest.json b/.hidi-release-please-manifest.json new file mode 100644 index 000000000..0ddfa5e48 --- /dev/null +++ b/.hidi-release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "3.10.2" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..0ec43beb9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env +WORKDIR /app + +COPY ./src ./hidi/src +COPY ./Directory.Build.props ./hidi/Directory.Build.props +COPY ./Build.props ./hidi/Build.props +COPY ./build.root ./hidi/build.root +COPY ./global.json ./hidi/global.json +COPY ./tool/Microsoft.OpenApi.OData.public.snk ./hidi/tool/Microsoft.OpenApi.OData.public.snk +COPY ./tool/Microsoft.OpenApi.Hidi.public.snk ./hidi/tool/Microsoft.OpenApi.Hidi.public.snk +COPY ./README.md ./hidi/README.md +WORKDIR /app/hidi +RUN dotnet publish ./src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj -c Release -o /app/publish -p:GeneratePackageOnBuild=false -p:HidiPublicSignBuild=true + +FROM mcr.microsoft.com/dotnet/runtime:8.0-jammy-chiseled AS runtime +WORKDIR /app + +COPY --from=build-env /app/publish ./ + +VOLUME /app/output +VOLUME /app/openapi.yml +VOLUME /app/api.csdl +VOLUME /app/collection.json +ENV HIDI_CONTAINER=true DOTNET_TieredPGO=1 DOTNET_TC_QuickJitForLoops=1 +ENTRYPOINT ["dotnet", "Microsoft.OpenApi.Hidi.dll"] +LABEL description="# Welcome to Hidi \ +To start transforming OpenAPI documents checkout [the getting started documentation](https://github.com/microsoft/OpenAPI.NET.OData/tree/main/src/Microsoft.OpenApi.Hidi) \ +[Source dockerfile](https://github.com/microsoft/OpenAPI.NET.OData/blob/main/Dockerfile)" +LABEL org.opencontainers.image.source="https://github.com/microsoft/OpenAPI.NET.OData" diff --git a/Microsoft.OpenApi.OData.sln b/Microsoft.OpenApi.OData.sln index 085f0a157..348ae6a94 100644 --- a/Microsoft.OpenApi.OData.sln +++ b/Microsoft.OpenApi.OData.sln @@ -16,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Hidi", "src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj", "{E80E81B7-C4FD-4061-875A-F7F7EC635722}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Hidi.Tests", "test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj", "{521CDCFF-1E62-4396-9266-7CAA99205969}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +42,14 @@ Global {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Release|Any CPU.Build.0 = Release|Any CPU + {E80E81B7-C4FD-4061-875A-F7F7EC635722}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E80E81B7-C4FD-4061-875A-F7F7EC635722}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E80E81B7-C4FD-4061-875A-F7F7EC635722}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E80E81B7-C4FD-4061-875A-F7F7EC635722}.Release|Any CPU.Build.0 = Release|Any CPU + {521CDCFF-1E62-4396-9266-7CAA99205969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {521CDCFF-1E62-4396-9266-7CAA99205969}.Debug|Any CPU.Build.0 = Debug|Any CPU + {521CDCFF-1E62-4396-9266-7CAA99205969}.Release|Any CPU.ActiveCfg = Release|Any CPU + {521CDCFF-1E62-4396-9266-7CAA99205969}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index b02123072..e3b392206 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,17 @@ The `GetEdmModel()` method can load a model in 3 ways: The OpenAPI.OData.reader nuget package is at: [https://www.nuget.org/packages/Microsoft.OpenApi.OData/](https://www.nuget.org/packages/Microsoft.OpenApi.OData) +## Hidi command line tool + +[Hidi](src/Microsoft.OpenApi.Hidi/readme.md) validates, transforms and slices +OpenAPI documents, converts OData CSDL, and generates API diagrams. +The NuGet package remains `Microsoft.OpenApi.Hidi` and the command remains `hidi`. +Hidi 3.x is maintained on `main`; Hidi 2.x is maintained on `support/v2`. +Both tracks use independent versions and require the .NET 8 runtime. +Building this repository, including the Hidi tests, requires the .NET 10 SDK. +Destination Hidi release publishing is disabled during the migration; the +source repository remains intact until the destination PRs are completed. + --- # Contributing diff --git a/build.ps1 b/build.ps1 index 1becaff9b..6186dd8fc 100644 --- a/build.ps1 +++ b/build.ps1 @@ -105,6 +105,8 @@ ForEach ($ver in $SNVersions) # Other variables $ProductProj = $ENLISTMENT_ROOT + "\src\Microsoft.OpenAPI.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj" $TESTProj = $ENLISTMENT_ROOT + "\test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenApi.OData.Reader.Tests.csproj" +$HidiProj = $ENLISTMENT_ROOT + "\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj" +$HidiTESTProj = $ENLISTMENT_ROOT + "\test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj" $TESTDIR = $ENLISTMENT_ROOT + "\bin\$Configuration\Test\net472" $PRODUCTDIR = $ENLISTMENT_ROOT + "\bin\$Configuration\net472" @@ -193,6 +195,12 @@ Function BuildProcess Write-Host "Build Test ..." & dotnet.exe build $TESTProj -c $Configuration + + Write-Host "Build Hidi ..." + & dotnet.exe build $HidiProj -c $Configuration + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & dotnet.exe build $HidiTESTProj -c $Configuration + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "Build Done" -ForegroundColor $Success $script:BUILD_END_TIME = Get-Date @@ -205,6 +213,10 @@ Function TestProcess $script:TEST_START_TIME = Get-Date & dotnet test $TESTProj -c $Configuration + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + & dotnet run --project $HidiTESTProj -c $Configuration --no-build -- --minimum-expected-tests 1 + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "Test Done" -ForegroundColor $Success $script:TEST_END_TIME = Get-Date diff --git a/global.json b/global.json new file mode 100644 index 000000000..d46d21e50 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "10.0.100", + "rollForward": "latestFeature", + "allowPrerelease": false + } +} diff --git a/hidi-release-please-config.json b/hidi-release-please-config.json new file mode 100644 index 000000000..457dc5244 --- /dev/null +++ b/hidi-release-please-config.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "bootstrap-sha": "5574ccc6d8d129d7a49729619fac3e3e36d334fd", + "release-type": "simple", + "include-component-in-tag": true, + "include-v-in-tag": true, + "exclude-paths": [ + ".azure-pipelines", + ".github", + ".idea", + ".vs", + ".vscode", + "src/Microsoft.OpenApi.OData.Reader", + "src/OoasGui", + "src/OoasUtil", + "test/Microsoft.OpenAPI.OData.Reader.Tests", + "docs", + "CHANGELOG.md", + "Directory.Build.props", + "release-please-config.json", + ".release-please-manifest.json" + ], + "packages": { + ".": { + "package-name": "Microsoft.OpenApi.Hidi", + "component": "hidi", + "changelog-path": "src/Microsoft.OpenApi.Hidi/CHANGELOG.md", + "extra-files": [ + { + "type": "xml", + "path": "src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj", + "xpath": "//Project/PropertyGroup/Version" + } + ] + } + } +} diff --git a/install-tool.ps1 b/install-tool.ps1 new file mode 100644 index 000000000..4d1a74c07 --- /dev/null +++ b/install-tool.ps1 @@ -0,0 +1,25 @@ +$ErrorActionPreference = 'Stop' + +$projectPath = Join-Path $PSScriptRoot 'src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj' +$version = ([xml](Get-Content $projectPath)).Project.PropertyGroup.Version +$packageDirectory = Join-Path $PSScriptRoot 'artifacts\hidi\nuget' +$packagePath = Join-Path $packageDirectory "Microsoft.OpenApi.Hidi.$version.nupkg" +$toolDirectory = Join-Path $PSScriptRoot 'artifacts\hidi\installed' +$configPath = Join-Path $PSScriptRoot 'tool\hidi-local-nuget.config' + +if (-not (Test-Path $packagePath)) { + throw "Missing $packagePath. Pack the hidi project in Release configuration before installing." +} +if ((Test-Path (Join-Path $toolDirectory 'hidi.exe')) -or (Test-Path (Join-Path $toolDirectory 'hidi'))) { + dotnet tool uninstall --tool-path $toolDirectory Microsoft.OpenApi.Hidi + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +} +dotnet tool install --tool-path $toolDirectory --configfile $configPath --add-source $packageDirectory --no-cache --version $version Microsoft.OpenApi.Hidi +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +$installedDlls = @(Get-ChildItem $toolDirectory -Force -Recurse -Filter Microsoft.OpenApi.Hidi.dll) +if ($installedDlls.Count -ne 1) { throw 'Expected exactly one installed hidi DLL.' } +$builtDll = Join-Path $PSScriptRoot 'src\Microsoft.OpenApi.Hidi\bin\Release\net8.0\Microsoft.OpenApi.Hidi.dll' +if ((Get-FileHash $installedDlls[0].FullName).Hash -ne (Get-FileHash $builtDll).Hash) { + throw 'Installed hidi does not match the locally built package.' +} \ No newline at end of file diff --git a/release-please-config.json b/release-please-config.json index 0e431d4d9..75e417d68 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -5,7 +5,21 @@ ".github", ".idea", ".vs", - ".vscode" + ".vscode", + "src/Microsoft.OpenApi.Hidi", + "src/Microsoft.OpenApi.Tool", + "src/Microsoft.Hidi", + "Microsoft.OpenApi.Hidi.Tests", + "test/Microsoft.OpenApi.Hidi.Tests", + "test/Microsoft.OpenApi.Tests", + "tool/Microsoft.OpenApi.Hidi.public.snk", + "tool/Microsoft.OpenApi.OData.public.snk", + "tool/hidi-local-nuget.config", + "Dockerfile", + ".dockerignore", + "install-tool.ps1", + "hidi-release-please-config.json", + ".hidi-release-please-manifest.json" ], "release-type": "simple", "bump-minor-pre-major": true, diff --git a/src/Microsoft.OpenApi.Hidi/CHANGELOG.md b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md new file mode 100644 index 000000000..8857fc2f7 --- /dev/null +++ b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md @@ -0,0 +1,8 @@ +# Hidi changelog + +## 3.10.2 + +This is the source migration baseline from OpenAPI.NET. It is already published +and must not be republished from this repository. Hidi 3.x is maintained on +`main`, independently of the OData library and the Hidi 2.x `support/v2` track. +Destination publishing remains disabled until source cutover. diff --git a/src/Microsoft.OpenApi.Hidi/CsdlFilter.xslt b/src/Microsoft.OpenApi.Hidi/CsdlFilter.xslt new file mode 100644 index 000000000..ee3bf0d40 --- /dev/null +++ b/src/Microsoft.OpenApi.Hidi/CsdlFilter.xslt @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs b/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs new file mode 100644 index 000000000..1a2dc477d --- /dev/null +++ b/src/Microsoft.OpenApi.Hidi/Extensions/CommandExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.CommandLine; + +namespace Microsoft.OpenApi.Hidi.Extensions +{ + internal static class CommandExtensions + { + public static void AddOptions(this Command command, IReadOnlyList