openai/openai-dotnet
Publicmirrored from https://github.com/openai/openai-dotnetAvailable
scripts/Submit-GeneratorUpdatePr.ps1
324lines · modecode
| 1 | #!/usr/bin/env pwsh |
| 2 | |
| 3 | <# |
| 4 | .DESCRIPTION |
| 5 | Creates a pull request to update the @typespec/http-client-csharp dependency in the OpenAI SDK for .NET repository. |
| 6 | This script follows the pattern used by the TypeSpec repository for creating PRs in downstream repositories. |
| 7 | |
| 8 | .PARAMETER PackageVersion |
| 9 | The version of the @typespec/http-client-csharp package to update to. |
| 10 | |
| 11 | .PARAMETER AuthToken |
| 12 | A GitHub personal access token for authentication. |
| 13 | |
| 14 | .PARAMETER BranchName |
| 15 | The name of the branch to create in the repository. |
| 16 | |
| 17 | .PARAMETER RepoPath |
| 18 | The path to the local repository. Defaults to current directory. |
| 19 | |
| 20 | .EXAMPLE |
| 21 | # Update to a specific version |
| 22 | ./Submit-GeneratorUpdatePr.ps1 -PackageVersion "1.0.0-alpha.20250625.4" -AuthToken "ghp_xxxx" |
| 23 | #> |
| 24 | [CmdletBinding(SupportsShouldProcess = $true)] |
| 25 | param( |
| 26 | [Parameter(Mandatory = $true)] |
| 27 | [string]$PackageVersion, |
| 28 | |
| 29 | [Parameter(Mandatory = $true)] |
| 30 | [string]$AuthToken, |
| 31 | |
| 32 | [Parameter(Mandatory = $false)] |
| 33 | [string]$BranchName = "typespec/update-http-client-csharp-$PackageVersion", |
| 34 | |
| 35 | [Parameter(Mandatory = $false)] |
| 36 | [string]$RepoPath = "." |
| 37 | ) |
| 38 | |
| 39 | # Set up variables for the PR |
| 40 | # Track if any warnings were encountered during execution |
| 41 | $WarningsEncountered = $false |
| 42 | $RepoOwner = "openai" |
| 43 | $RepoName = "openai-dotnet" |
| 44 | $BaseBranch = "main" |
| 45 | $PRBranch = $BranchName |
| 46 | |
| 47 | function Write-Log { |
| 48 | param([string]$Message) |
| 49 | Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): $Message" -ForegroundColor Green |
| 50 | } |
| 51 | |
| 52 | function Write-Warning-Log { |
| 53 | param([string]$Message) |
| 54 | Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): WARNING: $Message" -ForegroundColor Yellow |
| 55 | # Set the global warning flag to track that warnings occurred |
| 56 | $script:WarningsEncountered = $true |
| 57 | } |
| 58 | |
| 59 | function Write-Error-Log { |
| 60 | param([string]$Message) |
| 61 | Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): ERROR: $Message" -ForegroundColor Red |
| 62 | } |
| 63 | |
| 64 | # Function to get package dependencies using npm view |
| 65 | function Get-PackageDependencies { |
| 66 | param([string]$PackageName, [string]$PackageVersion) |
| 67 | |
| 68 | Write-Log "Fetching dependencies for $PackageName version $PackageVersion" |
| 69 | |
| 70 | try { |
| 71 | # Properly format the package specification for npm view |
| 72 | $packageSpec = "$PackageName@$PackageVersion" |
| 73 | |
| 74 | # Run npm view command and parse JSON output |
| 75 | $npmViewOutput = & npm view $packageSpec devDependencies --json 2>&1 |
| 76 | |
| 77 | # Check if there was an error |
| 78 | if ($LASTEXITCODE -ne 0) { |
| 79 | Write-Warning-Log "Failed to get dependencies for $PackageName version $PackageVersion. Error: $npmViewOutput" |
| 80 | return $null |
| 81 | } |
| 82 | |
| 83 | # Parse the JSON output |
| 84 | $dependencies = $npmViewOutput | ConvertFrom-Json |
| 85 | |
| 86 | return $dependencies |
| 87 | } |
| 88 | catch { |
| 89 | Write-Warning-Log "Error fetching dependencies for $PackageName version $PackageVersion $_" |
| 90 | return $null |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | $InjectedDependencies = @( |
| 95 | '@azure-tools/typespec-client-generator-core', |
| 96 | '@typespec/http', |
| 97 | '@typespec/openapi' |
| 98 | ) |
| 99 | |
| 100 | Write-Log "Starting TypeSpec generator update process" |
| 101 | Write-Log "Target version: $PackageVersion" |
| 102 | Write-Log "Repository: $RepoOwner/$RepoName" |
| 103 | Write-Log "Branch: $PRBranch" |
| 104 | |
| 105 | try { |
| 106 | Push-Location $RepoPath |
| 107 | |
| 108 | # Get current version from package.json files |
| 109 | $openAiPackageJsonPath = "codegen/package.json" |
| 110 | |
| 111 | if (-not (Test-Path $openAiPackageJsonPath)) { |
| 112 | throw "OpenAI package.json not found at: $openAiPackageJsonPath" |
| 113 | } |
| 114 | |
| 115 | # Read current versions |
| 116 | $openAiPackageJson = Get-Content $openAiPackageJsonPath -Raw | ConvertFrom-Json |
| 117 | |
| 118 | $currentVersion = $openAiPackageJson.dependencies.'@typespec/http-client-csharp' |
| 119 | |
| 120 | Write-Log "Current OpenAI version: $currentVersion" |
| 121 | |
| 122 | # Check if update is needed |
| 123 | if ($currentVersion -eq $PackageVersion) { |
| 124 | Write-Log "No update needed. Already at version: $PackageVersion" |
| 125 | return |
| 126 | } |
| 127 | |
| 128 | Write-Log "Update needed: $currentVersion -> $PackageVersion" |
| 129 | |
| 130 | # Create a new branch |
| 131 | Write-Log "Creating branch: $PRBranch" |
| 132 | git checkout -b $PRBranch |
| 133 | if ($LASTEXITCODE -ne 0) { |
| 134 | throw "Failed to create branch: $PRBranch" |
| 135 | } |
| 136 | |
| 137 | # Update OpenAI package.json |
| 138 | Write-Log "Updating OpenAI package.json" |
| 139 | # Fetch dependencies of the http-client-csharp package |
| 140 | $httpClientDependencies = Get-PackageDependencies -PackageName '@typespec/http-client-csharp' -PackageVersion $PackageVersion |
| 141 | |
| 142 | # Update the injected dependencies in the package.json |
| 143 | if ($httpClientDependencies -ne $null) { |
| 144 | Write-Log "Updating injected dependencies in OpenAI package.json" |
| 145 | |
| 146 | foreach ($dependency in $InjectedDependencies) { |
| 147 | if ($httpClientDependencies.PSObject.Properties.Name -contains $dependency) { |
| 148 | $dependencyVersion = $httpClientDependencies.$dependency |
| 149 | Write-Log "Updating $dependency to version $dependencyVersion" |
| 150 | |
| 151 | # Update the dependency in the package.json |
| 152 | if ($openAiPackageJson.dependencies.PSObject.Properties.Name -contains $dependency) { |
| 153 | $openAiPackageJson.dependencies.$dependency = $dependencyVersion |
| 154 | Write-Log "Updated $dependency to version $dependencyVersion" |
| 155 | } else { |
| 156 | Write-Warning-Log "Dependency $dependency not found in package.json" |
| 157 | } |
| 158 | } else { |
| 159 | Write-Warning-Log "Dependency $dependency not found in @typespec/http-client-csharp version $PackageVersion" |
| 160 | } |
| 161 | } |
| 162 | } else { |
| 163 | Write-Warning-Log "Could not fetch dependencies for @typespec/http-client-csharp version $PackageVersion" |
| 164 | } |
| 165 | |
| 166 | |
| 167 | $openAiPackageJson.dependencies.'@typespec/http-client-csharp' = $PackageVersion |
| 168 | $openAiPackageJson | ConvertTo-Json -Depth 10 | Set-Content -Path $openAiPackageJsonPath |
| 169 | |
| 170 | # Update Microsoft.TypeSpec.Generator.ClientModel version in csproj files |
| 171 | $openAiCsprojPath = "codegen/generator/src/OpenAI.Library.Plugin.csproj" |
| 172 | |
| 173 | Write-Log "Updating Microsoft.TypeSpec.Generator.ClientModel version in csproj files" |
| 174 | |
| 175 | # Update OpenAI csproj |
| 176 | if (Test-Path $openAiCsprojPath) { |
| 177 | $openAiCsproj = Get-Content $openAiCsprojPath -Raw |
| 178 | $openAiCsproj = $openAiCsproj -replace '(<PackageReference Include="Microsoft\.TypeSpec\.Generator\.ClientModel" Version=")[^"]*(")', "`${1}$PackageVersion`${2}" |
| 179 | Set-Content -Path $openAiCsprojPath -Value $openAiCsproj -NoNewline |
| 180 | Write-Log "Updated OpenAI csproj: $openAiCsprojPath" |
| 181 | } else { |
| 182 | Write-Warning-Log "OpenAI csproj not found at: $openAiCsprojPath" |
| 183 | } |
| 184 | |
| 185 | # Delete previous package-lock.json |
| 186 | Write-Log "Deleting previous package-lock.json" |
| 187 | if (Test-Path "package-lock.json") { |
| 188 | Remove-Item -Path "package-lock.json" -Force |
| 189 | } |
| 190 | |
| 191 | # Install dependencies from root directory (using workspaces) |
| 192 | Write-Log "Installing dependencies from root directory" |
| 193 | npm install |
| 194 | if ($LASTEXITCODE -ne 0) { |
| 195 | throw "npm install failed" |
| 196 | } |
| 197 | |
| 198 | # Build OpenAI plugin |
| 199 | Write-Log "Building OpenAI plugin" |
| 200 | Push-Location "codegen" |
| 201 | npm run clean && npm run build |
| 202 | if ($LASTEXITCODE -ne 0) { |
| 203 | Write-Warning-Log "OpenAI plugin build failed, but continuing..." |
| 204 | } |
| 205 | Pop-Location |
| 206 | |
| 207 | # Regenerate OpenAI SDK code |
| 208 | Write-Log "Regenerating OpenAI SDK code" |
| 209 | Push-Location "." |
| 210 | try { |
| 211 | pwsh scripts/Invoke-CodeGen.ps1 |
| 212 | } catch { |
| 213 | Write-Warning-Log "OpenAI code generation failed: $_" |
| 214 | } |
| 215 | Pop-Location |
| 216 | |
| 217 | # Build the updated library |
| 218 | Write-Log "Building the library" |
| 219 | Push-Location "." |
| 220 | try { |
| 221 | & dotnet build src/OpenAI.csproj |
| 222 | if ($LASTEXITCODE -ne 0) { |
| 223 | throw "Build failed with exit code $LASTEXITCODE" |
| 224 | } |
| 225 | } catch { |
| 226 | Write-Warning-Log "Building the library failed: $_" |
| 227 | } |
| 228 | Pop-Location |
| 229 | |
| 230 | # Check if there are changes to commit |
| 231 | $gitStatus = git status --porcelain |
| 232 | if (-not $gitStatus) { |
| 233 | Write-Log "No changes detected. Skipping commit and PR creation." |
| 234 | return |
| 235 | } |
| 236 | |
| 237 | # Configure git |
| 238 | git config --local user.email "action@github.com" |
| 239 | git config --local user.name "GitHub Action" |
| 240 | |
| 241 | # Add and commit changes |
| 242 | Write-Log "Adding and committing changes" |
| 243 | git add codegen/package.json |
| 244 | git add codegen/generator/src/OpenAI.Library.Plugin.csproj |
| 245 | git add api |
| 246 | git add package-lock.json |
| 247 | git add ./ # Add any generated code changes |
| 248 | |
| 249 | $commitMessage = @" |
| 250 | Update @typespec/http-client-csharp to $PackageVersion |
| 251 | |
| 252 | - Updated @typespec/http-client-csharp from $currentVersion to $PackageVersion |
| 253 | - Updated Microsoft.TypeSpec.Generator.ClientModel from $currentVersion to $PackageVersion |
| 254 | - Regenerated OpenAI SDK code with new generator version |
| 255 | - Updated centrally managed package-lock.json file with new dependency versions |
| 256 | "@ |
| 257 | |
| 258 | git commit -m $commitMessage |
| 259 | if ($LASTEXITCODE -ne 0) { |
| 260 | throw "Failed to commit changes" |
| 261 | } |
| 262 | |
| 263 | # Push the branch |
| 264 | Write-Log "Pushing branch to remote" |
| 265 | git push origin $PRBranch |
| 266 | if ($LASTEXITCODE -ne 0) { |
| 267 | throw "Failed to push branch" |
| 268 | } |
| 269 | |
| 270 | # Create PR using GitHub CLI |
| 271 | Write-Log "Creating PR using GitHub CLI" |
| 272 | $env:GH_TOKEN = $AuthToken |
| 273 | |
| 274 | # Update PR title if warnings were encountered |
| 275 | $prTitle = "Update @typespec/http-client-csharp to $PackageVersion" |
| 276 | if ($WarningsEncountered) { |
| 277 | $prTitle = "Succeeded with Issues: $prTitle" |
| 278 | } |
| 279 | $prBody = @" |
| 280 | This PR automatically updates the TypeSpec HTTP client C# generator version and regenerates the SDK code. |
| 281 | |
| 282 | ## Changes |
| 283 | - Updated ``@typespec/http-client-csharp`` from ``$currentVersion`` to ``$PackageVersion`` |
| 284 | - Updated ``Microsoft.TypeSpec.Generator.ClientModel`` from ``$currentVersion`` to ``$PackageVersion`` |
| 285 | - Updated OpenAI plugin package.json file |
| 286 | - Updated OpenAI plugin csproj file |
| 287 | - Regenerated OpenAI SDK code using the new generator version |
| 288 | - Updated centrally managed package-lock.json file with new dependency versions |
| 289 | |
| 290 | ## Details |
| 291 | - Generator package: [@typespec/http-client-csharp](https://www.npmjs.com/package/@typespec/http-client-csharp) |
| 292 | - Version update: ``$currentVersion`` → ``$PackageVersion`` |
| 293 | |
| 294 | ## Testing |
| 295 | Please run the existing test suites to ensure the generated code works correctly: |
| 296 | - Build and test the OpenAI SDK |
| 297 | - Verify API compatibility and functionality |
| 298 | |
| 299 | ## Notes |
| 300 | This PR was created automatically by the **Update TypeSpec Generator Version** workflow. The workflow runs weekly and when manually triggered to keep the generator version current with the latest TypeSpec improvements and fixes. |
| 301 | |
| 302 | If there are any issues with the generated code, please review the [TypeSpec release notes](https://github.com/microsoft/typespec/releases) for breaking changes or new features that may require manual adjustments. |
| 303 | "@ |
| 304 | |
| 305 | $prUrl = gh pr create --title $prTitle --body $prBody --base $BaseBranch --head $PRBranch 2>&1 |
| 306 | |
| 307 | if ($LASTEXITCODE -ne 0) { |
| 308 | throw "Failed to create PR using gh CLI: $prUrl" |
| 309 | } |
| 310 | |
| 311 | Write-Log "Successfully created PR: $prUrl" |
| 312 | # If warnings were encountered, make the script exit with non-zero code |
| 313 | # This will mark the GitHub Action step as failed but still create the PR |
| 314 | if ($WarningsEncountered) { |
| 315 | Write-Warning-Log "Warnings were encountered during execution. PR was created but marking step as failed." |
| 316 | exit 1 |
| 317 | } |
| 318 | |
| 319 | } catch { |
| 320 | Write-Error-Log "Error creating PR: $_" |
| 321 | exit 1 |
| 322 | } finally { |
| 323 | Pop-Location |
| 324 | } |
| 325 | |