@@ -137,17 +137,56 @@ extends:
137137 $sourceBranch = '$(Build.SourceBranch)'
138138 $buildReason = '$(Build.Reason)'
139139 $buildNumber = '$(Build.BuildNumber)'
140+ $emitterPackagePath = '${{ parameters.EmitterPackagePath }}'
141+
142+ # Create emitter identifier from package path for disambiguation
143+ $emitterIdentifier = ""
144+ if (-not [string]::IsNullOrWhiteSpace($emitterPackagePath)) {
145+ # Resolve emitterPackagePath to absolute path (it's relative to repo root)
146+ # EmitterPackagePath is a directory, so append package.json
147+ $absoluteEmitterPackagePath = Join-Path '$(Build.SourcesDirectory)' $emitterPackagePath
148+ $packageJsonPath = Join-Path $absoluteEmitterPackagePath 'package.json'
149+
150+ # Read the package name from package.json
151+ if (Test-Path $packageJsonPath) {
152+ try {
153+ $packageJson = Get-Content $packageJsonPath -Raw | ConvertFrom-Json
154+ if ($packageJson.name) {
155+ $emitterIdentifier = $packageJson.name
156+ }
157+ } catch {
158+ Write-Host "Warning: Could not read package name from $packageJsonPath"
159+ }
160+ }
161+
162+ # If we still don't have an identifier, fall back to filename
163+ if ([string]::IsNullOrWhiteSpace($emitterIdentifier)) {
164+ Write-Host "Warning: Could not read emitter name from package.json, falling back to package path"
165+ $emitterIdentifier = [System.IO.Path]::GetFileNameWithoutExtension($emitterPackagePath)
166+ }
167+
168+ # Clean up the identifier: remove @ prefix, replace invalid chars
169+ $emitterIdentifier = $emitterIdentifier -replace '^@', ''
170+ $emitterIdentifier = $emitterIdentifier -replace '[^a-zA-Z0-9\-_/]', '-'
171+ $emitterIdentifier = $emitterIdentifier.Trim('-').ToLower()
172+
173+ if (-not [string]::IsNullOrWhiteSpace($emitterIdentifier)) {
174+ $emitterIdentifier = "-$emitterIdentifier"
175+ }
176+ }
140177
141178 if ($buildReason -eq 'Schedule') {
142- $branchName = ' validate-typespec-scheduled'
179+ $branchName = " validate-typespec-scheduled$emitterIdentifier"
143180 } elseif ($sourceBranch -match "^refs/pull/(\d+)/(head|merge)$") {
144- $branchName = "validate-typespec-pr-$($Matches[1])"
181+ $branchName = "validate-typespec-pr-$($Matches[1])$emitterIdentifier "
145182 } else {
146- $branchName = "validate-typespec-$buildNumber"
183+ $branchName = "validate-typespec-$buildNumber$emitterIdentifier "
147184 }
148185
149186 Write-Host "Setting variable 'branchName' to '$branchName'"
150187 Write-Host "##vso[task.setvariable variable=branchName;isOutput=true]$branchName"
188+ Write-Host "Setting variable 'emitterIdentifier' to '$emitterIdentifier'"
189+ Write-Host "##vso[task.setvariable variable=emitterIdentifier;isOutput=true]$emitterIdentifier"
151190 displayName: Set branch name
152191 name: set_branch_name
153192
@@ -259,27 +298,34 @@ extends:
259298 displayName : Download pipeline artifacts
260299
261300 - pwsh : |
262- npm install -g @azure-tools/typespec-client-generator-cli@latest
301+ npm ci
263302 displayName: Install tsp-client
303+ workingDirectory: $(Build.SourcesDirectory)/eng/common/tsp-client
264304
265305 - pwsh : |
306+ # Resolve EmitterPackageJsonOutputPath to absolute path if it's relative
307+ $emitterPath = '${{ parameters.EmitterPackageJsonOutputPath }}'
308+ if (-not [System.IO.Path]::IsPathRooted($emitterPath)) {
309+ $emitterPath = Join-Path '$(Build.SourcesDirectory)' $emitterPath
310+ }
311+
266312 Write-Host "Overrides location: $(buildArtifactsPath)/packages/overrides.json"
313+ Write-Host "Resolved emitter package path: $emitterPath"
267314
268315 if (Test-Path -Path '$(buildArtifactsPath)/packages/overrides.json') {
269316 Write-Host "Using overrides.json to generate emitter-package.json"
270- tsp-client generate-config-files `
271- --package-json '$(buildArtifactsPath)/lock-files/package.json' `
272- --emitter-package-json-path '${{ parameters.EmitterPackageJsonOutputPath }}' `
273- --overrides '$(buildArtifactsPath)/packages/overrides.json'
317+ npm exec --no -- tsp-client generate-config-files `
318+ --package-json '$(buildArtifactsPath)/lock-files/package.json' `
319+ --emitter-package-json-path "$emitterPath" `
320+ --overrides '$(buildArtifactsPath)/packages/overrides.json'
274321 } else {
275322 Write-Host "No overrides.json found. Running tsp-client without overrides."
276-
277- tsp-client generate-config-files `
278- --package-json '$(buildArtifactsPath)/lock-files/package.json' `
279- --emitter-package-json-path '${{ parameters.EmitterPackageJsonOutputPath }}'
323+ npm exec --no -- tsp-client generate-config-files `
324+ --package-json '$(buildArtifactsPath)/lock-files/package.json' `
325+ --emitter-package-json-path "$emitterPath"
280326 }
281327 displayName: Generate emitter-package.json and emitter-package-lock files
282- workingDirectory: $(Build.SourcesDirectory)
328+ workingDirectory: $(Build.SourcesDirectory)/eng/common/tsp-client
283329
284330 - ${{ parameters.InitializationSteps }}
285331
@@ -361,15 +407,18 @@ extends:
361407 displayName : Create PR
362408 dependsOn :
363409 - Generate
410+ condition : succeededOrFailed()
364411 variables :
365412 generateJobResult : $[dependencies.Generate.result]
366413 emitterVersion : $[stageDependencies.Build.Build.outputs['initialize.emitterVersion']]
414+ emitterIdentifier : $[stageDependencies.Build.Build.outputs['set_branch_name.emitterIdentifier']]
367415 steps :
368416 - template : /eng/common/pipelines/templates/steps/sparse-checkout.yml
369417
370418 - pwsh : |
371419 $generateJobResult = '$(generateJobResult)'
372420 $emitterVersion = '$(emitterVersion)'
421+ $emitterIdentifier = '$(emitterIdentifier)'
373422 $collectionUri = '$(System.CollectionUri)'
374423 $project = '$(System.TeamProject)'
375424 $definitionName = '$(Build.DefinitionName)'
@@ -381,6 +430,12 @@ extends:
381430 $buildNumber = '$(Build.BuildNumber)'
382431 $preRelease = '${{ parameters.BuildPrereleaseVersion }}' -eq 'true'
383432
433+ # Use emitterIdentifier for PR title (remove leading dash if present)
434+ $emitterName = "TypeSpec emitter"
435+ if (-not [string]::IsNullOrWhiteSpace($emitterIdentifier)) {
436+ $emitterName = $emitterIdentifier.TrimStart('-')
437+ }
438+
384439 $prBody = "Generated by $definitionName build [$buildNumber]($collectionUri/$project/_build/results?buildId=$buildId)<br/>"
385440
386441 if ($sourceBranch -match "^refs/heads/(.+)$") {
@@ -397,9 +452,9 @@ extends:
397452 $prTitle = "Scheduled code regeneration test"
398453 } else {
399454 if ($preRelease) {
400- $prTitle = "Update TypeSpec emitter version to prerelease $emitterVersion"
455+ $prTitle = "Update $emitterName version to prerelease $emitterVersion"
401456 } else {
402- $prTitle = "Update TypeSpec emitter version to $emitterVersion"
457+ $prTitle = "Update $emitterName version to $emitterVersion"
403458 }
404459
405460 if ($generateJobResult -ne 'Succeeded') {
@@ -424,7 +479,8 @@ extends:
424479 Write-Error "Build.Repository.Name not in the expected {Owner}/{Name} format"
425480 }
426481
427- $openAsDraft = -not ($reason -eq 'IndividualCI' -and $sourceBranch -eq 'refs/heads/main')
482+ # Open PR as draft if generation failed, or if it's not an IndividualCI build from main
483+ $openAsDraft = ($generateJobResult -ne 'Succeeded') -or (-not ($reason -eq 'IndividualCI' -and $sourceBranch -eq 'refs/heads/main'))
428484 Write-Host "Setting OpenAsDraftBool = $openAsDraft"
429485 Write-Host "##vso[task.setvariable variable=OpenAsDraft]$openAsDraft"
430486 if ($openAsDraft) {
0 commit comments