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