Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify idempotency #3158

Merged
merged 30 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c56e6e8
minor
andreaTP Aug 16, 2023
173f256
minor
andreaTP Aug 16, 2023
04df20e
verify idempotency
andreaTP Aug 16, 2023
fd07867
more
andreaTP Aug 16, 2023
27dd9cd
cleanup
andreaTP Aug 16, 2023
e607863
fix
andreaTP Aug 16, 2023
6a857dc
upload artifacts on failure
andreaTP Aug 16, 2023
627e502
fix the CI def
andreaTP Aug 16, 2023
5d586d9
fix file upload path
andreaTP Aug 17, 2023
222ef45
- disables zipping when dev mode for idempotency
baywet Aug 21, 2023
c278f27
- fixes a bug where the comment for composed types wrapper would be u…
baywet Aug 21, 2023
a561ee6
- fixes an issue where overload indexer would fail replacement
baywet Aug 21, 2023
233bb1b
- fixes a bug where description properties could collide with structu…
baywet Aug 21, 2023
33f6c20
- fixes formatting
baywet Aug 21, 2023
2aa8094
- fixes an issue where empty properties in model would fail to generate
baywet Aug 22, 2023
1a0cb93
- disables validation rules for compare to reduce verbosity
baywet Aug 22, 2023
dbf0b65
- fixes noisy zip cleanup
baywet Aug 22, 2023
accaca0
- fixes an issue where path extension would be ignored when projectin…
baywet Aug 22, 2023
70bc8f9
- fixes backward compatible indexer method for Go
baywet Aug 23, 2023
ec5740c
- adds a suppression mechanism for idempotency
baywet Aug 23, 2023
f0e2a17
- moves generator cleanup job after idempotency
baywet Aug 23, 2023
d93777e
- adds changelog entry for idempotency fixes
baywet Aug 23, 2023
2425aa8
- adds missing suppression for ruby
baywet Aug 23, 2023
90f3ed5
- adds python to strip suppressions
baywet Aug 23, 2023
675f389
- disables tutorial mode for integration tests
baywet Aug 23, 2023
a48bd9f
- attempt at fixing failed idempotency uploads
baywet Aug 23, 2023
0088e70
- another attempt at fixing archives upload
baywet Aug 23, 2023
e970bad
- updates getting the scripts directory
baywet Aug 23, 2023
d2b8282
- zips generation results to accelerate workflow
baywet Aug 23, 2023
af214cc
- corrects script verbosity
baywet Aug 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,66 @@ jobs:
if: always()
with:
name: generation-results-${{ matrix.language }}-${{ steps.replace_url.outputs.ARTKEY }}
path: it/${{ matrix.language }}
path: it/${{ matrix.language }}.zip

idempotency:
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
matrix:
language:
- java
- csharp
- go
- typescript
- ruby
- php
- python
description:
- "./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://raw.githubusercontent.com/googlemaps/openapi-specification/main/dist/google-maps-platform-openapi3.yml"
- "apisguru::meraki.com"
- "https://developers.pipedrive.com/docs/api/v1/openapi.yaml"
- "apisguru::twilio.com:api"
- "apisguru::docusign.net"
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: generator
path: publish
- run: chmod a+x ./publish/kiota
- name: Check if test is suppressed
id: check-suppressed
run: |
$isSuppressed = . ./it/get-is-suppressed.ps1 -descriptionUrl ${{ matrix.description }} -language ${{ matrix.language }} -kind idempotency
Write-Output "IS_SUPPRESSED=$($isSuppressed.ToString().ToLowerInvariant())" >> $Env:GITHUB_OUTPUT
shell: pwsh
- name: Verify idempotency
baywet marked this conversation as resolved.
Show resolved Hide resolved
shell: pwsh
run: ./it/compare-generation.ps1 -descriptionUrl ${{ matrix.description }} -language ${{ matrix.language }}
continue-on-error: ${{ steps.check-suppressed.outputs.IS_SUPPRESSED == 'true' }}
- id: replace_url
if: always()
run: |
ORIGINAL="${{ matrix.description }}"
REPLACED="${ORIGINAL//[-:<>|\*\?\\\/\.]/_}"
echo "ARTKEY=$REPLACED" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v3
if: always()
with:
name: idempotency-${{ matrix.language }}-${{ steps.replace_url.outputs.ARTKEY }}
path: idempotency-folder*.zip

cleanup:
runs-on: ubuntu-latest
needs: [integration]
needs: [integration, idempotency]
steps:
- uses: jimschubert/delete-artifacts-action@v1
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,5 @@ reports/

samples/
it/openapi.yaml

idempotency*.zip
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Multiple fixes to guarantee idempotency of subsequent runs. [#2442](https://github.com/microsoft/kiota/issues/2442)
- Fix issue with generating classes with Aliases(PHP)[microsoftgraph/msgraph-beta-sdk-php#197](https://github.com/microsoftgraph/msgraph-beta-sdk-php/pull/197)
- Flattens the models namespaces in Ruby to avoid circular dependencies.
- Adds ObjectId as a reserved keyword in Ruby to have memory management issues.
Expand Down
115 changes: 115 additions & 0 deletions it/compare-generation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env pwsh

param(
[Parameter(Mandatory = $true)][string]$descriptionUrl,
[Parameter(Mandatory = $true)][string]$language,
[Parameter(Mandatory = $false)][switch]$dev,
[Parameter(Mandatory = $false)][switch]$preserveOutput
)

if ([string]::IsNullOrEmpty($descriptionUrl)) {
Write-Error "Description URL is empty"
exit 1
}

if ([string]::IsNullOrEmpty($language)) {
Write-Error "Language is empty"
exit 1
}

function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}

$rootPath = Join-Path -Path $PSScriptRoot -ChildPath ".."

$Env:KIOTA_TUTORIAL_ENABLED = "false"
$executableName = "kiota"
if ($IsWindows) {
$executableName = "kiota.exe"
}

switch ($dev) {
$true {
Write-Warning "Using kiota in dev mode"
$kiotaExec = Join-Path -Path $rootPath -ChildPath "src" -AdditionalChildPath "kiota", "bin", "Debug", "net7.0", $executableName
break
}
default {
$kiotaExec = Join-Path -Path $rootPath -ChildPath "publish" -AdditionalChildPath $executableName
break
}
}

$targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml"
if (Test-Path $targetOpenapiPath) {
Remove-Item $targetOpenapiPath
}

if ($descriptionUrl.StartsWith("./")) {
Copy-Item -Path $descriptionUrl -Destination $targetOpenapiPath -Force
}
elseif ($descriptionUrl.StartsWith("http")) {
Invoke-WebRequest -Uri $descriptionUrl -OutFile $targetOpenapiPath
}
else {
Start-Process "$kiotaExec" -ArgumentList "download ${descriptionUrl} --clean-output --output $targetOpenapiPath" -Wait -NoNewWindow
}

$tmpFolder1 = New-TemporaryDirectory
$tmpFolder2 = New-TemporaryDirectory

Start-Process "$kiotaExec" -ArgumentList "generate --clean-output --language ${language} --openapi ${targetOpenapiPath} --dvr all --output $tmpFolder1" -Wait -NoNewWindow
Start-Process "$kiotaExec" -ArgumentList "generate --clean-output --language ${language} --openapi ${targetOpenapiPath} --dvr all --output $tmpFolder2" -Wait -NoNewWindow

# 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")
}

# Compare hashes
$HashString1 = (Get-ChildItem $tmpFolder1 -Recurse | 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
Get-FileHash -InputStream ([IO.MemoryStream]::new([char[]]$HashString2))

Write-Output "Folder 1: $tmpFolder1"
Write-Output "Folder 2: $tmpFolder2"

if ($HashString1 -eq $HashString2) {
Write-Output "The content of the folders is identical"

if (!$preserveOutput) {
Remove-Item $tmpFolder1 -Force -Recurse
Remove-Item $tmpFolder2 -Force -Recurse
}

Exit 0
}
else {
Write-Error "The content of the folders is NOT identical"
$archivePath1 = Join-Path $rootPath -ChildPath "idempotency-folder1.zip"
$archivePath2 = Join-Path $rootPath -ChildPath "idempotency-folder2.zip"

if (Test-Path $archivePath1) {
Remove-Item $archivePath1 -Force -Verbose
}
if (Test-Path $archivePath2) {
Remove-Item $archivePath2 -Force -Verbose
}

if ($dev -eq $false) {
Write-Host "Creating archives at location $archivePath1 and $archivePath2"
Compress-Archive -Path $tmpFolder1 -DestinationPath $archivePath1
Compress-Archive -Path $tmpFolder1 -DestinationPath $archivePath2
}
Exit 1
}
52 changes: 52 additions & 0 deletions it/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@
"Language": "python",
"Rationale": "https://github.com/microsoft/kiota/issues/2957"
}
],
"IdempotencySuppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
}
]
},
"apisguru::twilio.com:api": {
Expand Down Expand Up @@ -216,6 +222,12 @@
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/2484"
}
],
"IdempotencySuppressions": [
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
}
]
},
"apisguru::stripe.com": {
Expand Down Expand Up @@ -244,6 +256,36 @@
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
}
],
"IdempotencySuppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
},
{
"Language": "go",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
},
{
"Language": "php",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
},
{
"Language": "java",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
},
{
"Language": "csharp",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
},
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
},
{
"Language": "python",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
}
]
},
"apisguru::meraki.com": {
Expand Down Expand Up @@ -280,6 +322,16 @@
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
}
],
"IdempotencySuppressions": [
{
"Language": "php",
"Rationale": "https://github.com/microsoft/kiota/issues/3067"
},
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
}
]
}
}
9 changes: 7 additions & 2 deletions it/do-clean.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ if ([string]::IsNullOrEmpty($language)) {
exit 1
}

$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$testPath = Join-Path -Path $scriptPath -ChildPath $language
$testPath = Join-Path -Path $PSScriptRoot -ChildPath $language

Push-Location $testPath
if ($language -eq "csharp") {
Expand All @@ -30,3 +29,9 @@ elseif ($language -eq "php") {
Remove-Item composer.lock -ErrorAction SilentlyContinue
}
Pop-Location

$archiveLocation = Join-Path -Path $PSScriptRoot -ChildPath "$language.zip"
if (Test-Path $archiveLocation) {
Remove-Item $archiveLocation -Force -ErrorAction SilentlyContinue -Verbose
}
Compress-Archive -Path $testPath -DestinationPath $archiveLocation
40 changes: 19 additions & 21 deletions it/exec-cmd.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,33 @@ function Invoke-Call {
}
}

function Retry([Action]$action)
{
$attempts=10
$sleepInSeconds=1
do
{
try
{
function Retry([Action]$action) {
$attempts = 10
$sleepInSeconds = 1
do {
try {
$action.Invoke();
break;
}
catch [Exception]
{
catch [Exception] {
Write-Host $_.Exception.Message
}
$attempts--
if ($attempts -gt 0) { sleep $sleepInSeconds }
} while ($attempts -gt 0)
}

$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$testPath = Join-Path -Path $scriptPath -ChildPath $language
$mockServerPath = Join-Path -Path $scriptPath -ChildPath "mockserver"
$testPath = Join-Path -Path $PSScriptRoot -ChildPath $language
$mockServerPath = Join-Path -Path $PSScriptRoot -ChildPath "mockserver"

function Kill-MockServer {
Push-Location $mockServerPath
mvn --batch-mode mockserver:stopForked
mvn --batch-mode mockserver:stopForked
Pop-Location
}

$mockSeverITFolder = $null
$configPath = Join-Path -Path $scriptPath -ChildPath "config.json"
$configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
$jsonValue = Get-Content -Path $configPath -Raw | ConvertFrom-Json
$descriptionValue = $jsonValue.psobject.properties.Where({ $_.name -eq $descriptionUrl }).value
if ($null -ne $descriptionValue) {
Expand All @@ -73,14 +68,14 @@ if (!([string]::IsNullOrEmpty($mockSeverITFolder))) {
# Kill any leftover MockServer
Kill-MockServer
Push-Location $mockServerPath
mvn --batch-mode mockserver:runForked
mvn --batch-mode mockserver:runForked
Pop-Location

# Provision Mock server with the right spec
$openapiUrl = Join-Path -Path $scriptPath -ChildPath "openapi.yaml"
$openapiUrl = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml"

# provision MockServer to mock the specific openapi description https://www.mock-server.com/mock_server/using_openapi.html#button_open_api_filepath
Retry({Invoke-WebRequest -Method PUT -Body "{ `"specUrlOrPayload`": `"$openapiUrl`" }" -Uri http://localhost:1080/mockserver/openapi -ContentType application/json})
Retry({ Invoke-WebRequest -Method PUT -Body "{ `"specUrlOrPayload`": `"$openapiUrl`" }" -Uri http://localhost:1080/mockserver/openapi -ContentType application/json })
}

Push-Location $testPath
Expand All @@ -101,7 +96,8 @@ if ($language -eq "csharp") {
} -ErrorAction Stop

Pop-Location
} else {
}
else {
Invoke-Call -ScriptBlock {
dotnet build
} -ErrorAction Stop
Expand All @@ -124,7 +120,8 @@ elseif ($language -eq "java") {
} -ErrorAction Stop

Pop-Location
} else {
}
else {
Invoke-Call -ScriptBlock {
mvn clean compile --batch-mode
} -ErrorAction Stop
Expand All @@ -147,7 +144,8 @@ elseif ($language -eq "go") {
} -ErrorAction Stop

Pop-Location
} else {
}
else {
Invoke-Call -ScriptBlock {
go install
go build
Expand Down
Loading
Loading