From bc05994497fa16969ede804e30feafed28069381 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Feb 2026 09:01:50 -0500 Subject: [PATCH 1/5] docs: adds information about promoting shipped APIs Signed-off-by: Vincent Biret --- CONTRIBUTING.md | 32 +++++++++++++++++++++++++++++++- scripts/promoteUnshipped.ps1 | 13 +++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 scripts/promoteUnshipped.ps1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 195723567..19b90210c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,4 +74,34 @@ The recommended commit types used are: - __ci__ for CI configuration file changes e.g. updating a pipeline - __chore__ for miscallaneous non-sdk changesin the repo e.g. removing an unused file -Adding an exclamation mark after the commit type (`feat!`) or footer with the prefix __BREAKING CHANGE:__ will cause an increment of the _major_ version. \ No newline at end of file +Adding an exclamation mark after the commit type (`feat!`) or footer with the prefix __BREAKING CHANGE:__ will cause an increment of the _major_ version. + +## Updates to public API surface + +Because we need to maintain a compatible public API surface within a major version, this project is using the public API analyzers to ensure no prior public API is changed/removed inadvertently. + +This means that: + +- All entries in an __Unshipped__ document need to be moved to the __Shipped__ document before any public release. +- All new APIs being added need to be __Unshipped__ document before the pull request can be merged, otherwise build will fail with a message like the example below. + +```txt +Error: /home/runner/work/OpenAPI.NET/OpenAPI.NET/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs(39,46): error RS0016: Symbol 'OAuth2MetadataUrl.set' is not part of the declared public API (https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [/home/runner/work/OpenAPI.NET/OpenAPI.NET/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj::TargetFramework=net8.0] +``` + +### Update the unshipped document + +To update the unshipped document, simply run the following commands + +```shell +# add the missing public api entries +dotnet format --diagnostics RS0016 +# discard changes to cs files to avoid creating conflicts +git checkout *.cs +``` + +### Move items from unshipped to unshipped document + +```pwsh +. ./scripts/promoteUnshipped.ps1 +``` diff --git a/scripts/promoteUnshipped.ps1 b/scripts/promoteUnshipped.ps1 new file mode 100644 index 000000000..ad7ea908a --- /dev/null +++ b/scripts/promoteUnshipped.ps1 @@ -0,0 +1,13 @@ +$nullableConstant = "#nullable enable" +$unshippedDocuments = ls *.Unshipped* -R | Select-Object -ExpandProperty FullName +foreach ($unshippedDocumentPath in $unshippedDocuments) { + $shippedDocumentPath = $unshippedDocumentPath -replace '\.Unshipped', '.Shipped' + $unshippedDocumentContent = Get-Content $unshippedDocumentPath -Raw + $unshippedDocumentContent = ($unshippedDocumentContent -replace [regex]::Escape($nullableConstant), '').Trim() + if ([string]::IsNullOrWhiteSpace($unshippedDocumentContent)) { + Write-Host "No content to promote for $unshippedDocumentPath, skipping." -ForegroundColor Yellow + continue + } + Add-Content -Path $shippedDocumentPath -Value $unshippedDocumentContent -Verbose + Set-Content -Path $unshippedDocumentPath -Value $nullableConstant -Verbose +} \ No newline at end of file From 4de55a4cfa714de748983677f9b3f49c608ce951 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Feb 2026 09:04:32 -0500 Subject: [PATCH 2/5] docs: adds contributing guidelines for the benchmarks Signed-off-by: Vincent Biret --- CONTRIBUTING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19b90210c..0300792ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,3 +105,20 @@ git checkout *.cs ```pwsh . ./scripts/promoteUnshipped.ps1 ``` + +## Updating the benchmark information + +To ensure performance of the library does not degrade over time, we have continuous benchmarks running. You might see the continuous integration failing if your pull request changed any model under __src/Microsoft.OpenApi/Models__. + +```txt +Benchmark result for EmptyApiSchema does not match the existing benchmark result (original!=new). Allocated bytes differ: 408 != 416 +``` + +To update the benchmarks, run the following script: + +```shell +cd performance/benchmark +dotnet run -c Release +``` + +Then commit the report files using a "chore" commit. From 9368efd1e0358f0a29f4cf916f54dd2503b6d11c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Feb 2026 09:17:36 -0500 Subject: [PATCH 3/5] ci: adds a workflow to automatically promote unshipped APIs Signed-off-by: Vincent Biret --- .github/workflows/promote-shipped-apis.yml | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 .github/workflows/promote-shipped-apis.yml diff --git a/.github/workflows/promote-shipped-apis.yml b/.github/workflows/promote-shipped-apis.yml new file mode 100644 index 000000000..d2a56788a --- /dev/null +++ b/.github/workflows/promote-shipped-apis.yml @@ -0,0 +1,122 @@ +name: Promote Shipped APIs + +on: + push: + branches: + - main + - support/v2 + +jobs: + promote-apis: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Configure git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Check for existing PR + id: check_pr + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + $branch = "${{ github.ref_name }}" + $prs = gh pr list --state open --head "promote-shipped-apis-$branch" --json number --jq '.[0].number' 2>$null + if ($prs) { + echo "pr_number=$prs" >> $env:GITHUB_OUTPUT + echo "pr_exists=true" >> $env:GITHUB_OUTPUT + Write-Host "Found existing PR: $prs" + } else { + echo "pr_exists=false" >> $env:GITHUB_OUTPUT + Write-Host "No existing PR found" + } + + - name: Checkout existing PR branch + if: steps.check_pr.outputs.pr_exists == 'true' + shell: pwsh + run: | + $branch = "${{ github.ref_name }}" + $prBranch = "promote-shipped-apis-$branch" + + git fetch origin + git checkout $prBranch + + - name: Merge trigger branch into PR branch + if: steps.check_pr.outputs.pr_exists == 'true' + shell: pwsh + run: | + $branch = "${{ github.ref_name }}" + git merge origin/$branch -m "Merge $branch into promote branch" + + - name: Run promote unshipped script + shell: pwsh + run: | + & .\scripts\promoteUnshipped.ps1 + + - name: Check for changes + id: check_changes + shell: pwsh + run: | + $changes = git diff --name-only -- "*Shipped.txt" + if ($changes) { + echo "has_changes=true" >> $env:GITHUB_OUTPUT + Write-Host "Changed files: $changes" + } else { + echo "has_changes=false" >> $env:GITHUB_OUTPUT + Write-Host "No changes detected" + } + + - name: Commit and push changes + if: steps.check_changes.outputs.has_changes == 'true' + shell: pwsh + run: | + git add *Shipped.txt + git commit -m "chore: promote shipped APIs" + + $branch = "${{ github.ref_name }}" + $prBranch = "promote-shipped-apis-$branch" + git push origin $prBranch + + - name: Create new PR + if: steps.check_pr.outputs.pr_exists == 'false' && steps.check_changes.outputs.has_changes == 'true' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + $branch = "${{ github.ref_name }}" + $prBranch = "promote-shipped-apis-$branch" + $title = "automatic promotion of shipped APIs for $branch" + + git checkout -b $prBranch + git push origin $prBranch + + gh pr create --title "$title" --base "$branch" --head "$prBranch" --body "Automatically promotes unshipped APIs to shipped after running the promotion script." + + - name: Dispatch other workflows + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + $owner = "${{ github.repository_owner }}" + $repo = "${{ github.event.repository.name }}" + $branch = "${{ github.ref_name }}" + + # Get all workflows + $workflows = gh workflow list --repo "$owner/$repo" --json name --jq '.[].name' + + foreach ($workflow in $workflows) { + if ($workflow -ne "Promote Shipped APIs") { + Write-Host "Dispatching workflow: $workflow" + gh workflow run "$workflow" --repo "$owner/$repo" --ref "$branch" 2>$null || Write-Host "Could not dispatch $workflow" + } + } From 807683bd3d891b0d8463d89317896daf99dd2226 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Feb 2026 09:19:33 -0500 Subject: [PATCH 4/5] docs: adds the automatic PR information Signed-off-by: Vincent Biret --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0300792ca..7719a3839 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,6 +106,8 @@ git checkout *.cs . ./scripts/promoteUnshipped.ps1 ``` +> Note: the promotion of APIs is automated through the dedicated workflow and should result in pull requests being automatically opened. + ## Updating the benchmark information To ensure performance of the library does not degrade over time, we have continuous benchmarks running. You might see the continuous integration failing if your pull request changed any model under __src/Microsoft.OpenApi/Models__. From 3ecc8e06aef8b45834469a21fa50b078fc3ef89c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Feb 2026 09:25:18 -0500 Subject: [PATCH 5/5] ci: moves to custom app registration to avoid using a script to queue subsequent workflows Signed-off-by: Vincent Biret --- .github/workflows/promote-shipped-apis.yml | 36 +++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/.github/workflows/promote-shipped-apis.yml b/.github/workflows/promote-shipped-apis.yml index d2a56788a..3e18427b0 100644 --- a/.github/workflows/promote-shipped-apis.yml +++ b/.github/workflows/promote-shipped-apis.yml @@ -10,8 +10,7 @@ jobs: promote-apis: runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: read steps: - name: Checkout code @@ -19,16 +18,27 @@ jobs: with: fetch-depth: 0 + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} + private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} + - name: Configure git + shell: pwsh + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global url."https://x-access-token:$env:GH_TOKEN@github.com/".insteadOf "https://github.com/" - name: Check for existing PR id: check_pr shell: pwsh env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | $branch = "${{ github.ref_name }}" $prs = gh pr list --state open --head "promote-shipped-apis-$branch" --json number --jq '.[0].number' 2>$null @@ -91,7 +101,7 @@ jobs: if: steps.check_pr.outputs.pr_exists == 'false' && steps.check_changes.outputs.has_changes == 'true' shell: pwsh env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | $branch = "${{ github.ref_name }}" $prBranch = "promote-shipped-apis-$branch" @@ -102,21 +112,3 @@ jobs: gh pr create --title "$title" --base "$branch" --head "$prBranch" --body "Automatically promotes unshipped APIs to shipped after running the promotion script." - - name: Dispatch other workflows - shell: pwsh - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - $owner = "${{ github.repository_owner }}" - $repo = "${{ github.event.repository.name }}" - $branch = "${{ github.ref_name }}" - - # Get all workflows - $workflows = gh workflow list --repo "$owner/$repo" --json name --jq '.[].name' - - foreach ($workflow in $workflows) { - if ($workflow -ne "Promote Shipped APIs") { - Write-Host "Dispatching workflow: $workflow" - gh workflow run "$workflow" --repo "$owner/$repo" --ref "$branch" 2>$null || Write-Host "Could not dispatch $workflow" - } - }