diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 87b987112..c3da60bcb 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -16,6 +16,9 @@ updates:
MicrosoftExtensions:
patterns:
- "Microsoft.Extensions.*"
+ coverlet:
+ patterns:
+ - "coverlet.*"
- package-ecosystem: dotnet-sdk
directory: /
schedule:
diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml
index ba2243c97..9d9039433 100644
--- a/.github/workflows/auto-merge-dependabot.yml
+++ b/.github/workflows/auto-merge-dependabot.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Dependabot metadata
id: metadata
- uses: dependabot/fetch-metadata@v2.5.0
+ uses: dependabot/fetch-metadata@v3.1.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
index b9d453d2a..fb99868ee 100644
--- a/.github/workflows/ci-cd.yml
+++ b/.github/workflows/ci-cd.yml
@@ -9,6 +9,10 @@ jobs:
ci:
name: Continuous Integration
runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ code-quality: write
+ pull-requests: read
env:
ARTIFACTS_FOLDER: ${{ github.workspace }}/Artifacts
GITHUB_RUN_NUMBER: ${{ github.run_number }}
@@ -27,6 +31,7 @@ jobs:
id: checkout_repo
uses: actions/checkout@v6
with:
+ ref: ${{ github.event.pull_request.head.sha || github.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
@@ -40,7 +45,36 @@ jobs:
id: run_unit_tests
shell: pwsh
run: |
- dotnet test Microsoft.OpenApi.slnx -c Release -v n
+ dotnet test Microsoft.OpenApi.slnx -c Release --no-build -v n --collect:"XPlat Code Coverage"
+
+ - name: Install report generator
+ shell: pwsh
+ run: |
+ dotnet tool install --global dotnet-reportgenerator-globaltool
+
+ - name: Generate coverage report
+ shell: pwsh
+ run: |
+ reportgenerator -reports:**/coverage.cobertura.xml -targetdir:./reports/coverage -reporttypes:"Html;MarkdownSummaryGithub;Cobertura"
+
+ - name: Add coverage to job summary
+ shell: bash
+ run: |
+ cat ./reports/coverage/SummaryGithub.md >> "$GITHUB_STEP_SUMMARY"
+
+ - name: Upload coverage report
+ if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') || (github.event_name != 'pull_request' && github.ref_name == github.event.repository.default_branch)
+ uses: actions/upload-code-coverage@v1
+ with:
+ file: ./reports/coverage/Cobertura.xml
+ language: CSharp
+ label: code-coverage/dotnet
+
+ - name: Upload coverage artifact
+ uses: actions/upload-artifact@v7
+ with:
+ name: coverage
+ path: reports/coverage
validate-trimming:
name: Validate Project for Trimming
diff --git a/.github/workflows/promote-shipped-apis.yml b/.github/workflows/promote-shipped-apis.yml
index aa611b7a0..569a73905 100644
--- a/.github/workflows/promote-shipped-apis.yml
+++ b/.github/workflows/promote-shipped-apis.yml
@@ -16,9 +16,9 @@ jobs:
steps:
- name: Generate GitHub App token
id: app-token
- uses: actions/create-github-app-token@v2
+ uses: actions/create-github-app-token@v3
with:
- app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }}
+ client-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }}
private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }}
- name: Checkout code
diff --git a/.github/workflows/release-please-gha.yml b/.github/workflows/release-please-gha.yml
index 6e2c9825d..a6fdc1927 100644
--- a/.github/workflows/release-please-gha.yml
+++ b/.github/workflows/release-please-gha.yml
@@ -22,7 +22,16 @@ permissions:
contents: read
jobs:
+ check-secret:
+ runs-on: ubuntu-latest
+ outputs:
+ has-token: ${{ steps.check.outputs.has-token }}
+ steps:
+ - id: check
+ run: echo "has-token=${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM != '' }}" >> $GITHUB_OUTPUT
release:
+ needs: check-secret
+ if: needs.check-secret.outputs.has-token == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
@@ -53,13 +62,13 @@ jobs:
- name: Generate GitHub App token
id: app-token
- uses: actions/create-github-app-token@v2
+ uses: actions/create-github-app-token@v3
with:
- app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }}
+ client-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }}
private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }}
- name: Release Please
- uses: googleapis/release-please-action@v4
+ uses: googleapis/release-please-action@v5
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ca3f730c7..21f60560a 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.7.5"
+ ".": "2.10.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b22097196..ef8c896c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,61 @@
# Changelog
+## [2.10.0](https://github.com/microsoft/OpenAPI.NET/compare/v2.9.0...v2.10.0) (2026-07-03)
+
+
+### Features
+
+* add JsonConverter for OpenApiSchema System.Text.Json serialization ([#2915](https://github.com/microsoft/OpenAPI.NET/issues/2915)) ([465521b](https://github.com/microsoft/OpenAPI.NET/commit/465521ba723ea9377d6838395d58e7212d64ece7))
+* **library:** support schema keywords on references ([2749463](https://github.com/microsoft/OpenAPI.NET/commit/2749463f1ec1d452ba2334876d32466ea45ee8d1)), closes [#2903](https://github.com/microsoft/OpenAPI.NET/issues/2903)
+
+
+### Bug Fixes
+
+* Don't silently skip null assignment to OpenApiDocument.Tags ([#2917](https://github.com/microsoft/OpenAPI.NET/issues/2917)) ([6a45a82](https://github.com/microsoft/OpenAPI.NET/commit/6a45a826e095d198605b340c50d46c066eed72ad))
+* handling of nullable enums for 3.0 ([#2920](https://github.com/microsoft/OpenAPI.NET/issues/2920)) ([f4778e0](https://github.com/microsoft/OpenAPI.NET/commit/f4778e024e6bf033a4b6c4b90ea6636de712f826))
+* **library:** keep v3 schema references ref-only ([8d811c3](https://github.com/microsoft/OpenAPI.NET/commit/8d811c3e76a8963be6e7a605b80c98d0ea0c63a5))
+* preserve JSON Schema 2020-12 keyword siblings on $ref schemas for OAS 3.1+ ([#2896](https://github.com/microsoft/OpenAPI.NET/issues/2896)) ([fb20d46](https://github.com/microsoft/OpenAPI.NET/commit/fb20d460ffe95505847da5a6e4c6fc065e41d9d1))
+* preserve JSON Schema 2020-12 keyword siblings on $ref schemas for OAS 3.1+ ([#2896](https://github.com/microsoft/OpenAPI.NET/issues/2896)) ([c79a83e](https://github.com/microsoft/OpenAPI.NET/commit/c79a83e74a0a41367c37f050d78d3e0ace838bc0))
+* use async method for crypto flush ([677b519](https://github.com/microsoft/OpenAPI.NET/commit/677b5197d9c4f7de2122852ad49d5012f7082e71))
+
+## [2.9.0](https://github.com/microsoft/OpenAPI.NET/compare/v2.8.0...v2.9.0) (2026-06-10)
+
+
+### Features
+
+* add contains/minContains/maxContains members ([fadb422](https://github.com/microsoft/OpenAPI.NET/commit/fadb42225561e150aa99459c0c359c00cf52fb1a))
+* **library:** add missing json schema properties ([db41a3c](https://github.com/microsoft/OpenAPI.NET/commit/db41a3c952e651f80a6bbdb7d8aac001031e6dd3))
+
+
+### Bug Fixes
+
+* **library:** always copy unevaluated properties ([3951a31](https://github.com/microsoft/OpenAPI.NET/commit/3951a310da6056fd7a6852fda129a8ad8583639a))
+* **library:** avoid false circular refs for external schema re-exports ([a058913](https://github.com/microsoft/OpenAPI.NET/commit/a058913943d4c197ccf03742f1c67ecc50e11a03))
+* **library:** avoid false circular refs for external schema re-exports ([1bace68](https://github.com/microsoft/OpenAPI.NET/commit/1bace6804bc15c22b7665df7c66bed2a4a27bad0))
+* **library:** merge contains compat members into missing properties ([7dc45e1](https://github.com/microsoft/OpenAPI.NET/commit/7dc45e14160825f79d5e64e6c9c8ba2a02900bcf))
+* **library:** remove unshipped schema extension fallback ([b301827](https://github.com/microsoft/OpenAPI.NET/commit/b30182773fd875fb0a55c1a2bf48018910922ead))
+* **library:** use version-specific schema keyword callbacks ([f93d76a](https://github.com/microsoft/OpenAPI.NET/commit/f93d76a4643022fc5d35b3d8ca8078276bbcce4f))
+* **library:** use x-jsonschema schema extensions ([ec04a7f](https://github.com/microsoft/OpenAPI.NET/commit/ec04a7fcd43c296602edc15c197dc49cee112472))
+
+## [2.8.0](https://github.com/microsoft/OpenAPI.NET/compare/v2.7.6...v2.8.0) (2026-06-01)
+
+
+### Features
+
+* **reader:** remove ParseNode infrastructure ([d7c6a9d](https://github.com/microsoft/OpenAPI.NET/commit/d7c6a9dbe2da8cccac2a3dcbc5277bf0f20b0aa9))
+
+
+### Bug Fixes
+
+* **reader:** adapt no-parse-node backport for v2 ([ddd2539](https://github.com/microsoft/OpenAPI.NET/commit/ddd253990f9741bcc3b5e649c71c8908728694c2))
+
+## [2.7.6](https://github.com/microsoft/OpenAPI.NET/compare/v2.7.5...v2.7.6) (2026-05-28)
+
+
+### Bug Fixes
+
+* **reader:** preserve nullable Null flag when type appears after nullable in V3.1/V3.2 deserializers ([288e95a](https://github.com/microsoft/OpenAPI.NET/commit/288e95aa743cb98dc69b44577ae78956f3f1c7c4))
+
## [2.7.5](https://github.com/microsoft/OpenAPI.NET/compare/v2.7.4...v2.7.5) (2026-05-26)
diff --git a/Directory.Build.props b/Directory.Build.props
index f06b5bb92..d8aa99b81 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -12,7 +12,7 @@
https://github.com/Microsoft/OpenAPI.NET
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
- 2.7.5
+ 2.10.0
diff --git a/global.json b/global.json
index d895dfe5a..12f5b9de6 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "10.0.300"
+ "version": "10.0.301"
}
}
\ No newline at end of file
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
index 36532861e..c6bade521 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
@@ -1,20 +1,20 @@
```
-BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
-AMD EPYC 7763 2.79GHz, 1 CPU, 4 logical and 2 physical cores
-.NET SDK 10.0.204
- [Host] : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
- ShortRun : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
+BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8655/25H2/2025Update/HudsonValley2)
+Snapdragon X 12-core X1E80100 3.40 GHz (Max: 3.42GHz), 1 CPU, 12 logical and 12 physical cores
+.NET SDK 10.0.301
+ [Host] : .NET 8.0.28 (8.0.28, 8.0.2826.26413), Arm64 RyuJIT armv8.0-a
+ ShortRun : .NET 8.0.28 (8.0.28, 8.0.2826.26413), Arm64 RyuJIT armv8.0-a
Job=ShortRun IterationCount=3 LaunchCount=1
WarmupCount=3
```
-| Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
-|------------- |---------------:|--------------:|-------------:|-----------:|-----------:|----------:|-------------:|
-| PetStoreYaml | 528.6 μs | 178.98 μs | 9.81 μs | 19.5313 | 3.9063 | - | 363.54 KB |
-| PetStoreJson | 232.1 μs | 12.90 μs | 0.71 μs | 13.6719 | 1.9531 | - | 225.39 KB |
-| GHESYaml | 1,072,146.4 μs | 200,482.34 μs | 10,989.11 μs | 24000.0000 | 19000.0000 | 3000.0000 | 345905.05 KB |
-| GHESJson | 483,939.6 μs | 288,033.88 μs | 15,788.11 μs | 13000.0000 | 9000.0000 | 2000.0000 | 207426.91 KB |
-| GHESNextYaml | 1,325,231.0 μs | 240,938.48 μs | 13,206.65 μs | 36000.0000 | 20000.0000 | 3000.0000 | 542041.88 KB |
-| GHESNextJson | 699,920.8 μs | 85,692.01 μs | 4,697.07 μs | 25000.0000 | 11000.0000 | 2000.0000 | 407243.96 KB |
+| Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
+|------------- |--------------:|---------------:|--------------:|-----------:|-----------:|----------:|-------------:|
+| PetStoreYaml | 281.26 μs | 87.951 μs | 4.821 μs | 74.2188 | 15.6250 | - | 313.05 KB |
+| PetStoreJson | 99.37 μs | 7.974 μs | 0.437 μs | 42.4805 | 8.3008 | - | 175.2 KB |
+| GHESYaml | 558,007.40 μs | 245,240.510 μs | 13,442.460 μs | 45000.0000 | 19000.0000 | 3000.0000 | 254573.63 KB |
+| GHESJson | 263,444.90 μs | 586,112.802 μs | 32,126.821 μs | 18000.0000 | 9000.0000 | 2000.0000 | 111745.13 KB |
+| GHESNextYaml | 785,094.03 μs | 214,946.431 μs | 11,781.939 μs | 80000.0000 | 20000.0000 | 3000.0000 | 450674.2 KB |
+| GHESNextJson | 461,067.00 μs | 50,227.814 μs | 2,753.156 μs | 53000.0000 | 13000.0000 | 3000.0000 | 312434.25 KB |
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
index 7bf9078cd..7d98a61ea 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
@@ -1,7 +1,7 @@
Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Gen0,Gen1,Gen2,Allocated
-PetStoreYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,528.6 μs,178.98 μs,9.81 μs,19.5313,3.9063,0.0000,363.54 KB
-PetStoreJson,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,232.1 μs,12.90 μs,0.71 μs,13.6719,1.9531,0.0000,225.39 KB
-GHESYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"1,072,146.4 μs","200,482.34 μs","10,989.11 μs",24000.0000,19000.0000,3000.0000,345905.05 KB
-GHESJson,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"483,939.6 μs","288,033.88 μs","15,788.11 μs",13000.0000,9000.0000,2000.0000,207426.91 KB
-GHESNextYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"1,325,231.0 μs","240,938.48 μs","13,206.65 μs",36000.0000,20000.0000,3000.0000,542041.88 KB
-GHESNextJson,ShortRun,False,Default,Default,Default,Default,Default,Default,1111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"699,920.8 μs","85,692.01 μs","4,697.07 μs",25000.0000,11000.0000,2000.0000,407243.96 KB
+PetStoreYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,281.26 μs,87.951 μs,4.821 μs,74.2188,15.6250,0.0000,313.05 KB
+PetStoreJson,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,99.37 μs,7.974 μs,0.437 μs,42.4805,8.3008,0.0000,175.2 KB
+GHESYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"558,007.40 μs","245,240.510 μs","13,442.460 μs",45000.0000,19000.0000,3000.0000,254573.63 KB
+GHESJson,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"263,444.90 μs","586,112.802 μs","32,126.821 μs",18000.0000,9000.0000,2000.0000,111745.13 KB
+GHESNextYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"785,094.03 μs","214,946.431 μs","11,781.939 μs",80000.0000,20000.0000,3000.0000,450674.2 KB
+GHESNextJson,ShortRun,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"461,067.00 μs","50,227.814 μs","2,753.156 μs",53000.0000,13000.0000,3000.0000,312434.25 KB
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
index a694be1ea..f09c24ea8 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
@@ -2,7 +2,7 @@
-performance.Descriptions-20260526-151849
+performance.Descriptions-20260626-150505