From 2860949347feb3a39c635d960426ee23231bb81d Mon Sep 17 00:00:00 2001 From: WolfgangHG Date: Tue, 9 Jun 2026 20:50:10 +0200 Subject: [PATCH 1/4] ci: Replace APIGurus as source for IT --- .github/workflows/idempotency-tests.yml | 33 ++-- .github/workflows/integration-tests.yml | 33 ++-- it/Readme.md | 55 ++++++ it/compare-generation.ps1 | 8 +- it/config.json | 217 +++++++++--------------- it/get-additional-arguments.ps1 | 7 +- it/get-description-artifact-key.ps1 | 8 +- it/java/gh/src/test/java/GHAPITest.java | 4 +- 8 files changed, 191 insertions(+), 174 deletions(-) diff --git a/.github/workflows/idempotency-tests.yml b/.github/workflows/idempotency-tests.yml index d996ac8069..d7ab202062 100644 --- a/.github/workflows/idempotency-tests.yml +++ b/.github/workflows/idempotency-tests.yml @@ -39,15 +39,15 @@ jobs: matrix: description: - "oas::petstore" - - "apisguru::twitter.com:current" - - "apisguru::notion.com" - - "apisguru::stripe.com" + - "https://api.twitter.com/2/openapi.json" + - "https://developers.notion.com/openapi.json" + - "https://raw.githubusercontent.com/stripe/openapi/refs/heads/master/latest/openapi.spec3.json" - "https://raw.githubusercontent.com/googlemaps/openapi-specification/refs/tags/v1.22.5/dist/google-maps-platform-openapi3.yml" - - "apisguru::meraki.com" + - "https://raw.githubusercontent.com/meraki/openapi/refs/heads/master/openapi/spec3.json" - "https://developers.pipedrive.com/docs/api/v1/openapi.yaml" - - "apisguru::twilio.com:api" - - "apisguru::docusign.net" - - "apisguru::github.com:api.github.com" + - "https://raw.githubusercontent.com/twilio/twilio-oai/refs/heads/main/spec/yaml/twilio_api_v2010.yaml" + - "https://raw.githubusercontent.com/docusign/OpenAPI-Specifications/refs/heads/master/esignature.rest.swagger-v2.1.json" + - "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json" - "apisguru::apis.guru" steps: - uses: actions/checkout@v7 @@ -65,7 +65,10 @@ jobs: - uses: actions/upload-artifact@v7 with: name: description-${{ steps.replace_url.outputs.ARTKEY }} - path: it/openapi.yaml + # Output is either openapi.json or openapi.yml. Try to upload the one that is found. + path: | + it/openapi.yaml + it/openapi.json idempotency: runs-on: ubuntu-latest @@ -86,15 +89,15 @@ jobs: - "./tests/Kiota.Builder.IntegrationTests/InheritingErrors.yaml" - "./tests/Kiota.Builder.IntegrationTests/NoUnderscoresInModel.yaml" - "oas::petstore" - - "apisguru::twitter.com:current" - - "apisguru::notion.com" - - "apisguru::stripe.com" + - "https://api.twitter.com/2/openapi.json" + - "https://developers.notion.com/openapi.json" + - "https://raw.githubusercontent.com/stripe/openapi/refs/heads/master/latest/openapi.spec3.json" - "https://raw.githubusercontent.com/googlemaps/openapi-specification/refs/tags/v1.22.5/dist/google-maps-platform-openapi3.yml" - - "apisguru::meraki.com" + - "https://raw.githubusercontent.com/meraki/openapi/refs/heads/master/openapi/spec3.json" - "https://developers.pipedrive.com/docs/api/v1/openapi.yaml" - - "apisguru::twilio.com:api" - - "apisguru::docusign.net" - - "apisguru::github.com:api.github.com" + - "https://raw.githubusercontent.com/twilio/twilio-oai/refs/heads/main/spec/yaml/twilio_api_v2010.yaml" + - "https://raw.githubusercontent.com/docusign/OpenAPI-Specifications/refs/heads/master/esignature.rest.swagger-v2.1.json" + - "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json" - "apisguru::apis.guru" steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 290798aa25..3a1f370004 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -39,15 +39,15 @@ jobs: matrix: description: - "oas::petstore" - - "apisguru::twitter.com:current" - - "apisguru::notion.com" - - "apisguru::stripe.com" + - "https://api.twitter.com/2/openapi.json" + - "https://developers.notion.com/openapi.json" + - "https://raw.githubusercontent.com/stripe/openapi/refs/heads/master/latest/openapi.spec3.json" - "https://raw.githubusercontent.com/googlemaps/openapi-specification/refs/tags/v1.22.5/dist/google-maps-platform-openapi3.yml" - - "apisguru::meraki.com" + - "https://raw.githubusercontent.com/meraki/openapi/refs/heads/master/openapi/spec3.json" - "https://developers.pipedrive.com/docs/api/v1/openapi.yaml" - - "apisguru::twilio.com:api" - - "apisguru::docusign.net" - - "apisguru::github.com:api.github.com" + - "https://raw.githubusercontent.com/twilio/twilio-oai/refs/heads/main/spec/yaml/twilio_api_v2010.yaml" + - "https://raw.githubusercontent.com/docusign/OpenAPI-Specifications/refs/heads/master/esignature.rest.swagger-v2.1.json" + - "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json" - "apisguru::apis.guru" - "https://github.com/microsoftgraph/msgraph-metadata/raw/refs/heads/master/openapi/beta/openapi.yaml" steps: @@ -66,7 +66,10 @@ jobs: - uses: actions/upload-artifact@v7 with: name: description-${{ steps.replace_url.outputs.ARTKEY }} - path: it/openapi.yaml + # Output is either openapi.json or openapi.yml. Try to upload the one that is found. + path: | + it/openapi.yaml + it/openapi.json integration: runs-on: ubuntu-latest @@ -92,15 +95,15 @@ jobs: - "./tests/Kiota.Builder.IntegrationTests/DiscriminatorSample.yaml" - "./tests/Kiota.Builder.IntegrationTests/ModelWithDefaultValues.json" - "oas::petstore" - - "apisguru::twitter.com:current" - - "apisguru::notion.com" - - "apisguru::stripe.com" + - "https://api.twitter.com/2/openapi.json" + - "https://developers.notion.com/openapi.json" + - "https://raw.githubusercontent.com/stripe/openapi/refs/heads/master/latest/openapi.spec3.json" - "https://raw.githubusercontent.com/googlemaps/openapi-specification/refs/tags/v1.22.5/dist/google-maps-platform-openapi3.yml" - - "apisguru::meraki.com" + - "https://raw.githubusercontent.com/meraki/openapi/refs/heads/master/openapi/spec3.json" - "https://developers.pipedrive.com/docs/api/v1/openapi.yaml" - - "apisguru::twilio.com:api" - - "apisguru::docusign.net" - - "apisguru::github.com:api.github.com" + - "https://raw.githubusercontent.com/twilio/twilio-oai/refs/heads/main/spec/yaml/twilio_api_v2010.yaml" + - "https://raw.githubusercontent.com/docusign/OpenAPI-Specifications/refs/heads/master/esignature.rest.swagger-v2.1.json" + - "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json" - "apisguru::apis.guru" - "https://github.com/microsoftgraph/msgraph-metadata/raw/refs/heads/master/openapi/beta/openapi.yaml" diff --git a/it/Readme.md b/it/Readme.md index 44e87f8f24..a65fab0979 100644 --- a/it/Readme.md +++ b/it/Readme.md @@ -14,12 +14,67 @@ Generate the code: ./it/generate-code.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} ``` +Instead of publishing, you could also build the project and use the "-Dev" switch that executes Kiota from "src\kiota\bin\Debug\net8.0": + +```bash +./it/generate-code.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} -Dev +``` + And finally run the test: ```bash ./it/exec-cmd.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} ``` +# Suppressions + +Some API files do not work for a specific target language. There are two ways to define suppressions: + +## Suppress the full test + +This will execute the test in Github CI anyway and maybe an error will happen, but the test will not be marked as "failed" (see "integration-tests.yml" and "get-is-suppressed.ps1") + +``` + "https://www.sample.com/sample-api.json": { + "MockServerITFolder": "sampleapi", + "Suppressions": [ + { + "Language": "ruby", + "Rationale": "Feature x in file is not supported for ruby." + } + ] + } +``` + +## Suppress creating certain API paths + +This will tell Kiota not to generate the code for the specified endpoint. Use it if something inside this endpoint definition is either invalid OpenAPI +or Kiota cannot handle it. + +``` + "https://www.sample.com/sample-api.json": { + "MockServerITFolder": "sampleapi", + "ExcludePatterns": [ + { + "Pattern": "/users/*/gpg_keys", + "Rationale": "invalid data type for argument XYZ" + }, + { + "Pattern": "/repos/{owner}/{repo}/releases#POST", + "Rationale": "here is something wrong, too" + }, + { + "Language": "typescript", + "Pattern": "/repos/{owner}/{repo}/contents/{path}#GET", + "Rationale": "an error only for typescript" + } + ] + } +``` + +The second snippet demonstrates that you can suppress also creating a method for just one of the HTTP methods of an endpoint. +The third sample shows a suppression only for a single language. + # Surface area / DOM diff test The surface area test guards against **binary/source breaking changes** that a change to diff --git a/it/compare-generation.ps1 b/it/compare-generation.ps1 index 872ce4cb4e..7be250c449 100755 --- a/it/compare-generation.ps1 +++ b/it/compare-generation.ps1 @@ -50,7 +50,13 @@ switch ($dev) { } } -$targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml" +#api description might be a JSON or a yaml file (or a apigurus name, which is hopefully a yaml file). +if ($descriptionUrl.ToLower().EndsWith(".json")) { + $targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.json" +} +else { + $targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml" +} if (Test-Path $targetOpenapiPath) { Remove-Item $targetOpenapiPath } diff --git a/it/config.json b/it/config.json index b4e8f0eb0e..8346919d59 100644 --- a/it/config.json +++ b/it/config.json @@ -1,19 +1,13 @@ { "./tests/Kiota.Builder.IntegrationTests/InheritingErrors.yaml": { - "MockServerITFolder": "basic", - "Suppressions": [ - { - "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" - } - ] + "MockServerITFolder": "basic" }, "./tests/Kiota.Builder.IntegrationTests/GeneratesUritemplateHints.yaml": { "MockServerITFolder": "query-params", "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/4262" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/59" } ] }, @@ -22,174 +16,102 @@ "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/66" } ] }, "./tests/Kiota.Builder.IntegrationTests/ModelWithDefaultValues.json": { "MockServerITFolder": "defaultvalues" }, - "apisguru::github.com:api.github.com": { + "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json": { "MockServerITFolder": "gh", "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/1816" - } - ], - "ExcludePatterns": [ - { - "Pattern": "/users/*/gpg_keys", - "Rationale": "https://github.com/github/rest-api-description/issues/2247" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/73" }, { - "Pattern": "/user/gpg_keys", - "Rationale": "https://github.com/github/rest-api-description/issues/2247" + "Language": "dart", + "Rationale": "Multiple compilation errors with api from 2026-06-22 - https://github.com/microsoft/kiota/issues/7821" }, { - "Pattern": "/user/gpg_keys/**", - "Rationale": "https://github.com/github/rest-api-description/issues/2247" - }, + "Language": "typescript", + "Rationale": "Multiple compilation errors with api from 2026-06-25 - https://github.com/microsoft/kiota/issues/7862" + } + ], + "ExcludePatterns": [ { - "Pattern": "/repos/{owner}/{repo}/releases/{release_id}#PATCH", - "Rationale": "https://github.com/microsoft/kiota/pull/7414#issuecomment-4033965839 and https://github.com/github/rest-api-description/issues/6100 (default value for enum is not quoted)" + "Language": "typescript", + "Pattern": "/repos/{owner}/{repo}/contents/{path}#GET", + "Rationale": "Kiota fails for typescript with api version 1.1.4 dated 2026-06-17 - https://github.com/microsoft/kiota/issues/7803" }, { - "Pattern": "/repos/{owner}/{repo}/releases#POST", - "Rationale": "https://github.com/microsoft/kiota/pull/7414#issuecomment-4033965839 (default value for enum is not quoted, fixed in recent file as of 03/2026 but not updated to APIGurus)" + "Language": "java", + "Pattern": "/repos/{owner}/{repo}/contents/{path}#GET", + "Rationale": "Compilation fails for Java with api version 1.1.4 dated 2026-06-23 - https://github.com/microsoft/kiota/issues/7829" } ] }, - "apisguru::notion.com": { - "ExcludePatterns": [ - { - "Pattern": "/v1/databases/**", - "Rationale": "next_cursor in commentResponse is invalid" - }, + "https://developers.notion.com/openapi.json": { + "Suppressions": [ { - "Pattern": "/v1/blocks/**", - "Rationale": "next_cursor in commentResponse is invalid" + "Language": "ruby", + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/66" }, { - "Pattern": "/v1/comments", - "Rationale": "next_cursor in commentResponse is invalid" + "Language": "typescript", + "Rationale": "Kiota client generation fails with api from 2026-06-17 - https://github.com/microsoft/kiota/issues/7802" }, { - "Pattern": "/v1/users/*", - "Rationale": "avatar_url in usersResponse is invalid" + "Language": "dart", + "Rationale": "Compilation fails with api from 2026-06-18 - https://github.com/microsoft/kiota/issues/7807" }, { - "Pattern": "/v1/pages/*", - "Rationale": "code in pageResponse is invalid" + "Language": "go", + "Rationale": "Compilation fails with api from 2026-06-18 - https://github.com/microsoft/kiota/issues/7808" } ], - "Suppressions": [ + "IdempotencySuppressions": [ { - "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Language": "typescript", + "Rationale": "Kiota client generation fails with api from 2026-06-17 - https://github.com/microsoft/kiota/issues/7802" } ] }, "https://raw.githubusercontent.com/googlemaps/openapi-specification/refs/tags/v1.22.5/dist/google-maps-platform-openapi3.yml": { - "ExcludePatterns": [ - { - "Pattern": "/maps/api/directions/json", - "Rationale": "DirectionsGeocodedWaypoint.partial_match is invalid" - } - ], "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota/issues/7856" } ] }, "https://developers.pipedrive.com/docs/api/v1/openapi.yaml": { - "ExcludePatterns": [ - { - "Pattern": "/itemSearch/field", - "Rationale": "$field_key for fieldResponse_data is invalid" - }, - { - "Pattern": "/subscriptions/*/payments", - "Rationale": "data for model paymentsResponse is invalid" - }, - { - "Pattern": "/permissionSets/**", - "Rationale": "error 404 is invalid" - }, - { - "Pattern": "/oauth/token/", - "Rationale": "Duplicate path exists in the spec without the trailing '/'" - } - ], "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/66" } ], - "IdempotencySuppressions": [] - }, - "apisguru::twilio.com:api": { + "IdempotencySuppressions": [], "ExcludePatterns": [ { - "Pattern": "/2010-04-01/Accounts/*/Addresses/*/DependentPhoneNumbers.json", - "Rationale": "dependent_phone_number is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Recordings.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Recordings/*.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Conferences/*/Recordings.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Calls/*/Recordings.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Calls/*/Recordings/*.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Conferences/*/Recordings/*.json", - "Rationale": "encryption_details is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Calls/FeedbackSummary.json", - "Rationale": "issues is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Calls/FeedbackSummary/*.json", - "Rationale": "issues is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/Calls/*/Events.json", - "Rationale": "request is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/IncomingPhoneNumbers/*/AssignedAddOns.json", - "Rationale": "configuration is invalid" - }, - { - "Pattern": "/2010-04-01/Accounts/*/IncomingPhoneNumbers/*/AssignedAddOns/*.json", - "Rationale": "configuration is invalid" + "Language": "typescript", + "Pattern": "/oauth/token/", + "Rationale": "Fails for typescript with api dated 2026-06-25 - https://github.com/microsoft/kiota/issues/7861" }, { - "Pattern": "/2010-04-01/Accounts/*/Calls/*/Payments.json", - "Rationale": "Parameter is invalid" + "Language": "go", + "Pattern": "/oauth/token/", + "Rationale": "Compilation fails with api from 2026-06-22 - https://github.com/microsoft/kiota/issues/7823" } - ], + ] + }, + "https://raw.githubusercontent.com/twilio/twilio-oai/refs/heads/main/spec/yaml/twilio_api_v2010.yaml": { "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/66. The API of 06/2026 reports an error 'The element to rename was not found available_phone_number_countryModelModelModelModel'" } ], "IdempotencySuppressions": [ @@ -199,16 +121,12 @@ } ] }, - "apisguru::stripe.com": { + "https://raw.githubusercontent.com/stripe/openapi/refs/heads/master/latest/openapi.spec3.json": { "Suppressions": [ { "Language": "java", "Rationale": "https://github.com/microsoft/kiota/issues/2842" }, - { - "Language": "python", - "Rationale": "https://github.com/microsoft/kiota/issues/2842" - }, { "Language": "ruby", "Rationale": "https://github.com/microsoft/kiota/issues/1816" @@ -223,40 +141,63 @@ "Language": "java", "Rationale": "https://github.com/microsoft/kiota/issues/2842" }, - { - "Language": "python", - "Rationale": "https://github.com/microsoft/kiota/issues/2842" - }, { "Language": "ruby", "Rationale": "https://github.com/microsoft/kiota/issues/1816" } ] }, - "apisguru::meraki.com": { + "https://raw.githubusercontent.com/meraki/openapi/refs/heads/master/openapi/spec3.json": { "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/66" + }, + { + "Language": "dart", + "Rationale": "Compilation fails with api from 2026-06-22 - https://github.com/microsoft/kiota/issues/7822" + }, + { + "Language": "go", + "Rationale": "Compilation fails only on linux systems (CI) with api from 2026-06-22 - https://github.com/microsoft/kiota/issues/7828" + } + ], + "ExcludePatterns": [ + { + "Language": "php", + "Pattern": "/organizations/{organizationId}/apiRequests/overview", + "Rationale": "Fails for php with api dated 2026-06-24 - https://github.com/microsoft/kiota/issues/7830" + }, + { + "Language": "php", + "Pattern": "/networks/{networkId}/clients/{clientId}/splashAuthorizationStatus", + "Rationale": "Fails for php with api dated 2026-06-24 (GET and PUT) - https://github.com/microsoft/kiota/issues/7830" } ] }, - "apisguru::docusign.net": { + "https://raw.githubusercontent.com/docusign/OpenAPI-Specifications/refs/heads/master/esignature.rest.swagger-v2.1.json": { "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/2484" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/59" } ] }, - "apisguru::twitter.com:current": { + "https://api.twitter.com/2/openapi.json": { "Suppressions": [ { "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/1816" + "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/73" } ], - "IdempotencySuppressions": [] + "IdempotencySuppressions": [], + "ExcludePatterns": [ + { + "Language": "typescript", + "Pattern": "/2/activity/stream", + "Rationale": "Fails for typescript with api version 2.166 dated 2026-06-25 - https://github.com/microsoft/kiota/issues/7860" + } + ] }, "apisguru::apis.guru": { "Suppressions": [], diff --git a/it/get-additional-arguments.ps1 b/it/get-additional-arguments.ps1 index f5f661cd10..a5160df7d7 100755 --- a/it/get-additional-arguments.ps1 +++ b/it/get-additional-arguments.ps1 @@ -55,8 +55,11 @@ $descriptionValue = $jsonValue.psobject.properties.Where({ $_.name -eq $descript if ($null -ne $descriptionValue) { if ($descriptionValue.PSObject.Properties.Name -contains "ExcludePatterns") { $descriptionValue.ExcludePatterns | ForEach-Object { - Write-Information "Excluding $($_.Pattern) rationale: $($_.Rationale)" - $command += " -e `"$($_.Pattern)`"" + # A "Language" might be defined. + if ([string]::IsNullOrEmpty($_.Language) -or ($_.Language -eq $language)) { + Write-Information "Excluding $($_.Pattern) rationale: $($_.Rationale)" + $command += " -e `"$($_.Pattern)`"" + } } } diff --git a/it/get-description-artifact-key.ps1 b/it/get-description-artifact-key.ps1 index 3f83b9da08..dc3d2f24d0 100644 --- a/it/get-description-artifact-key.ps1 +++ b/it/get-description-artifact-key.ps1 @@ -15,5 +15,11 @@ if ($descriptionUrl.StartsWith("./")) { Write-Output "DESCRIPTION_PATH=$descriptionUrl" >> $Env:GITHUB_OUTPUT } else { - Write-Output "DESCRIPTION_PATH=./description/openapi.yaml" >> $Env:GITHUB_OUTPUT + #api description might be a JSON or a yaml file (or a apigurus name, which is hopefully a yaml file). + if ($descriptionUrl.ToLower().EndsWith(".json")) { + Write-Output "DESCRIPTION_PATH=./description/openapi.json" >> $Env:GITHUB_OUTPUT + } + else { + Write-Output "DESCRIPTION_PATH=./description/openapi.yaml" >> $Env:GITHUB_OUTPUT + } } \ No newline at end of file diff --git a/it/java/gh/src/test/java/GHAPITest.java b/it/java/gh/src/test/java/GHAPITest.java index 1a0409497e..27249babac 100644 --- a/it/java/gh/src/test/java/GHAPITest.java +++ b/it/java/gh/src/test/java/GHAPITest.java @@ -12,14 +12,14 @@ void basicTest() throws Exception { adapter.setBaseUrl("http://127.0.0.1:1080"); var client = new ApiClient(adapter); - client.repos().byOrgId("my-owner").byRepoId("my-repo").get(); + client.repos().byOwnerId("my-owner").byRepoId("my-repo").get(); final GeneratePostRequestBody body = new GeneratePostRequestBody(); body.setDescription("my description"); body.setIncludeAllBranches(true); body.setName("my-repo2"); body.setOwner("my-owner2"); body.setPrivate(false); - client.repos().byOrgId("my-owner").byRepoId("my-repo").generate().post(body); + client.repos().byOwnerId("my-owner").byRepoId("my-repo").generate().post(body); } } From fc33a767e28dd41a4ab7818096c8fb8ae697381e Mon Sep 17 00:00:00 2001 From: WolfgangHG Date: Thu, 9 Jul 2026 21:12:46 +0200 Subject: [PATCH 2/4] (ci) report differing files in idempotency tests --- it/compare-generation.ps1 | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/it/compare-generation.ps1 b/it/compare-generation.ps1 index 7be250c449..aff53d85ff 100755 --- a/it/compare-generation.ps1 +++ b/it/compare-generation.ps1 @@ -123,11 +123,45 @@ if ($HashString1 -eq $HashString2) { } else { Write-Host "The content of the folders is NOT identical" + + # Print differing files: get hash for each file and compare. Print files the differ. + function Get-FileHashMap { + param([string]$Root) + $map = @{} + Get-ChildItem -Path $Root -File -Recurse | ForEach-Object { + $rel = $_.FullName.Substring($Root.Length).TrimStart('\','/') + $hash = (Get-FileHash -Algorithm MD5 -Path $_.FullName).Hash + $map[$rel] = $hash + } + return $map + } + + $map1 = Get-FileHashMap -Root $tmpFolder1 + $map2 = Get-FileHashMap -Root $tmpFolder2 + + $allKeys = ($map1.Keys + $map2.Keys) | Sort-Object -Unique + + foreach ($key in $allKeys) { + $in1 = $map1.ContainsKey($key) + $in2 = $map2.ContainsKey($key) + + if (-not $in1) { + Write-Host "Missing in ${tmpFolder1}: $key" # Should not happen + } elseif (-not $in2) { + Write-Host "Missing in ${tmpFolder2}: $key" # Should not happen + } else { + if ($map1[$key] -ne $map2[$key]) { + Write-Host "Difference found in: $key" + } + } + } + + # Now zip the results in the upload folder: $resultsFolder = Join-Path -Path $rootPath -ChildPath "idempotency-results" if (Test-Path $resultsFolder) { Remove-Item $resultsFolder -Force -Verbose -Recurse } - New-Item -ItemType Directory -Path $resultsFolder -Force + New-Item -ItemType Directory -Path $resultsFolder -Force | Out-Null if ($dev -eq $false) { $archivePath1 = Join-Path $resultsFolder -ChildPath "idempotency-folder1.zip" From 32801bf4c3eecb045e74deb35b812164bfd3fce5 Mon Sep 17 00:00:00 2001 From: WolfgangHG Date: Thu, 9 Jul 2026 21:17:23 +0200 Subject: [PATCH 3/4] (ci) change section order in it/Readme.md --- it/Readme.md | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/it/Readme.md b/it/Readme.md index a65fab0979..e8cd787192 100644 --- a/it/Readme.md +++ b/it/Readme.md @@ -1,4 +1,6 @@ -# Running the Integration Tests +# Integration tests + +## Running the Integration Tests Run the following steps to locally run the integration tests. @@ -26,11 +28,11 @@ And finally run the test: ./it/exec-cmd.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} ``` -# Suppressions +## Suppressions Some API files do not work for a specific target language. There are two ways to define suppressions: -## Suppress the full test +### Suppress the full test This will execute the test in Github CI anyway and maybe an error will happen, but the test will not be marked as "failed" (see "integration-tests.yml" and "get-is-suppressed.ps1") @@ -46,7 +48,7 @@ This will execute the test in Github CI anyway and maybe an error will happen, b } ``` -## Suppress creating certain API paths +### Suppress creating certain API paths This will tell Kiota not to generate the code for the specified endpoint. Use it if something inside this endpoint definition is either invalid OpenAPI or Kiota cannot handle it. @@ -75,47 +77,8 @@ or Kiota cannot handle it. The second snippet demonstrates that you can suppress also creating a method for just one of the HTTP methods of an endpoint. The third sample shows a suppression only for a single language. -# Surface area / DOM diff test - -The surface area test guards against **binary/source breaking changes** that a change to -kiota's generation logic could introduce into downstream SDKs (notably the Microsoft Graph -SDKs). It compares the public-API surface (`kiota-dom-export.txt`) produced by the currently -published `Microsoft.OpenApi.Kiota` NuGet tool (baseline) against the surface produced by a -locally built kiota (current changeset). - -In CI this runs via `.github/workflows/surface-area-tests.yml` and feeds the resulting patch -to the [`microsoftgraph/kiota-dom-export-diff-tool`](https://github.com/microsoftgraph/kiota-dom-export-diff-tool) -`tool` action with `fail-on-removal: true`: any removed surface line fails the check. - -To run it locally, first publish a development build of `kiota`: - -```bash -dotnet publish ./src/kiota/kiota.csproj -c Release -p:PublishSingleFile=true -p:PublishReadyToRun=true -o ./publish -f net10.0 -``` - -Then generate the baseline/current exports and a diff patch: - -```bash -./it/compare-dom-export.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} -``` - -Useful options: - -* `-baselineVersion` — pin a specific published `Microsoft.OpenApi.Kiota` version (defaults to latest stable). -* `-patchPath` — where to write the unified diff (defaults to `./-dom-export.patch`). -* `-kiotaExec` — path to the locally built kiota (defaults to `./publish/kiota`). -* `-additionalArguments` — extra arguments forwarded to both `kiota generate` invocations. - -**Interpreting results:** removed lines (`-`) in the patch indicate API removed/changed since -the baseline release — i.e. potential breaking changes. Added lines (`+`) are additive and do -not fail the check. Because the baseline is the last published release, the diff reflects every -change since that release, not just the current changeset. - -**Intended breaking changes:** review the explanations produced by the diff tool. If a breaking -change is deliberate, it must be acknowledged through normal PR review (and, where configured, a -required-check override) before merging. -# MockServer tests +## MockServer tests The OpenAPI description can be published to a mock server, and you can execute tests that call this API. @@ -159,3 +122,43 @@ The handling depends on the language: If you create e.g. a custom "csproj" file for your test (might be necessary if you need additional dependencies), add this file to the Dependabot config so that dependencies are updated. + +# Surface area / DOM diff test + +The surface area test guards against **binary/source breaking changes** that a change to +kiota's generation logic could introduce into downstream SDKs (notably the Microsoft Graph +SDKs). It compares the public-API surface (`kiota-dom-export.txt`) produced by the currently +published `Microsoft.OpenApi.Kiota` NuGet tool (baseline) against the surface produced by a +locally built kiota (current changeset). + +In CI this runs via `.github/workflows/surface-area-tests.yml` and feeds the resulting patch +to the [`microsoftgraph/kiota-dom-export-diff-tool`](https://github.com/microsoftgraph/kiota-dom-export-diff-tool) +`tool` action with `fail-on-removal: true`: any removed surface line fails the check. + +To run it locally, first publish a development build of `kiota`: + +```bash +dotnet publish ./src/kiota/kiota.csproj -c Release -p:PublishSingleFile=true -p:PublishReadyToRun=true -o ./publish -f net10.0 +``` + +Then generate the baseline/current exports and a diff patch: + +```bash +./it/compare-dom-export.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} +``` + +Useful options: + +* `-baselineVersion` — pin a specific published `Microsoft.OpenApi.Kiota` version (defaults to latest stable). +* `-patchPath` — where to write the unified diff (defaults to `./-dom-export.patch`). +* `-kiotaExec` — path to the locally built kiota (defaults to `./publish/kiota`). +* `-additionalArguments` — extra arguments forwarded to both `kiota generate` invocations. + +**Interpreting results:** removed lines (`-`) in the patch indicate API removed/changed since +the baseline release — i.e. potential breaking changes. Added lines (`+`) are additive and do +not fail the check. Because the baseline is the last published release, the diff reflects every +change since that release, not just the current changeset. + +**Intended breaking changes:** review the explanations produced by the diff tool. If a breaking +change is deliberate, it must be acknowledged through normal PR review (and, where configured, a +required-check override) before merging. \ No newline at end of file From 80fd7d56ee402ef176fc9730af4efdc8ebad7e9b Mon Sep 17 00:00:00 2001 From: WolfgangHG Date: Thu, 9 Jul 2026 21:45:29 +0200 Subject: [PATCH 4/4] (ci) add kiota-lock.json to idempotency test result zip, but ignore in hash --- it/compare-generation.ps1 | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/it/compare-generation.ps1 b/it/compare-generation.ps1 index aff53d85ff..0ad97d62cf 100755 --- a/it/compare-generation.ps1 +++ b/it/compare-generation.ps1 @@ -91,21 +91,14 @@ if ($firstGenerationProcess.ExitCode -ne 0 -or $secondGenerationProcess.ExitCode exit 1 } -# Remove variable output files -Remove-Item (Join-Path -Path $tmpFolder1 -ChildPath "kiota-lock.json") -if (Test-Path (Join-Path -Path $tmpFolder1 -ChildPath ".kiota.log")) { - Remove-Item -Force (Join-Path -Path $tmpFolder1 -ChildPath ".kiota.log") -} -Remove-Item (Join-Path -Path $tmpFolder2 -ChildPath "kiota-lock.json") -if (Test-Path (Join-Path -Path $tmpFolder2 -ChildPath ".kiota.log")) { - Remove-Item -Force (Join-Path -Path $tmpFolder2 -ChildPath ".kiota.log") -} +# Exclude variable output files +$excludes = @("kiota-lock.json",".kiota.log") # Compare hashes -$HashString1 = (Get-ChildItem $tmpFolder1 -Recurse | where { ! $_.PSIsContainer } | Get-FileHash -Algorithm MD5).Hash | Out-String +$HashString1 = (Get-ChildItem $tmpFolder1 -Recurse -Exclude $excludes | where { ! $_.PSIsContainer } | Get-FileHash -Algorithm MD5).Hash | Out-String Get-FileHash -InputStream ([IO.MemoryStream]::new([char[]]$HashString1)) -$HashString2 = (Get-ChildItem $tmpFolder2 -Recurse | where { ! $_.PSIsContainer } | Get-FileHash -Algorithm MD5).Hash | Out-String +$HashString2 = (Get-ChildItem $tmpFolder2 -Recurse -Exclude $excludes | where { ! $_.PSIsContainer } | Get-FileHash -Algorithm MD5).Hash | Out-String Get-FileHash -InputStream ([IO.MemoryStream]::new([char[]]$HashString2)) Write-Output "Folder 1: $tmpFolder1" @@ -128,7 +121,7 @@ else { function Get-FileHashMap { param([string]$Root) $map = @{} - Get-ChildItem -Path $Root -File -Recurse | ForEach-Object { + Get-ChildItem -Path $Root -File -Recurse -Exclude $excludes | ForEach-Object { $rel = $_.FullName.Substring($Root.Length).TrimStart('\','/') $hash = (Get-FileHash -Algorithm MD5 -Path $_.FullName).Hash $map[$rel] = $hash