Skip to content

Add step in publish pipeline to create PR to azure-sdk-for-net #7426

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

Merged
merged 37 commits into from
Jun 13, 2025
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d3223cd
Initial plan for issue
Copilot May 21, 2025
f81aed9
Implement script and pipeline for PR creation to azure-sdk-for-net
Copilot May 21, 2025
8597b3c
Fix implementation issues and improve pipeline
Copilot May 21, 2025
1a90c5f
Remove CLI command and use standalone script for azure-sdk-for-net PR…
Copilot Jun 11, 2025
6236c22
Replace Node.js script with PowerShell approach for azure-sdk-for-net…
Copilot Jun 11, 2025
64583d8
Validate and finalize PowerShell-based PR creation implementation
Copilot Jun 11, 2025
1270e79
Update script to target correct file and property per Azure SDK struc…
Copilot Jun 11, 2025
4526427
Update script to also modify package.json and run npm install
Copilot Jun 11, 2025
c8ba05d
Add npm run build and Generate.ps1 steps after npm install
Copilot Jun 11, 2025
a8627f8
Fix stage dependency to use 'Publish' instead of 'CSharp_Publish'
Copilot Jun 11, 2025
e92e4f4
Remove PullRequest condition from CreateAzureSdkForNetPR stage for te…
Copilot Jun 11, 2025
3a21b8d
Change stage dependency back to CSharp_Publish
Copilot Jun 11, 2025
0553f0c
Remove source branch main condition for testing
Copilot Jun 11, 2025
45414e9
Fix PowerShell script path in pipeline
Copilot Jun 11, 2025
124aab4
Move Submit-AzureSdkForNetPr.ps1 script to http-client-csharp/eng/scr…
Copilot Jun 11, 2025
db714e0
Fix GitHub token variable name in pipeline
Copilot Jun 11, 2025
836c3fb
Address feedback: delete CONTRIBUTING.md and remove unused package.js…
Copilot Jun 11, 2025
0a08a06
Replace Push-Location/Pop-Location with Invoke helper function
Copilot Jun 11, 2025
dabf99b
Remove blank line in publish.yml pipeline as requested
Copilot Jun 11, 2025
a555f20
Fix PowerShell script shebang line to resolve execution error
Copilot Jun 12, 2025
89fb560
Remove PackageUrl parameter from Submit-AzureSdkForNetPr.ps1 script
Copilot Jun 12, 2025
38a3582
Fix PowerShell script path to be rooted with Build.SourcesDirectory
Copilot Jun 12, 2025
f5d49d8
Fix temp directory path to use cross-platform GetTempPath method
Copilot Jun 12, 2025
c55bf4b
Fix version retrieval to use emitterVersion from build stage
Copilot Jun 12, 2025
a26a51a
Fix build output reference syntax in pipeline
Copilot Jun 12, 2025
70144f2
Restore conditions for main branch and non-PR builds to CreateAzureSd…
Copilot Jun 12, 2025
3ddcccf
Update pipeline condition and switch to gh CLI for PR creation
Copilot Jun 12, 2025
7e9ac33
Simplify pipeline condition to only check build reason not manual
Copilot Jun 12, 2025
d9a00bf
Add CreateUpdatePR parameter to allow manual testing of azure-sdk-for…
Copilot Jun 12, 2025
0c4a8df
Fix pipeline condition to include source branch check and update para…
Copilot Jun 12, 2025
e3104b9
Remove unnecessary Azure DevOps variable setting from PR creation script
Copilot Jun 13, 2025
93fe0b4
Add debugging for stage output variable references to identify correc…
Copilot Jun 13, 2025
084fd35
Add PackageVersionAlt5 debugging variable for pipeline output reference
Copilot Jun 13, 2025
6e64fe8
Remove debug code and use working stage output reference
Copilot Jun 13, 2025
435f9fe
Remove CreateUpdatePR parameter as it's only needed for public npm pu…
Copilot Jun 13, 2025
a48af8a
format: run pnpm format on http-client-csharp package
Copilot Jun 13, 2025
5ef409b
Add early bailout when no updates are needed in Submit-AzureSdkForNet…
Copilot Jun 13, 2025
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
42 changes: 42 additions & 0 deletions packages/http-client-csharp/eng/pipeline/publish.yml
Original file line number Diff line number Diff line change
@@ -47,3 +47,45 @@ extends:
inputs:
useGlobalJson: true
workingDirectory: $(Build.SourcesDirectory)/packages/http-client-csharp

- stage: CreateAzureSdkForNetPR
displayName: Create PR for azure-sdk-for-net
dependsOn:
- CSharp_Publish
- CSharp_Build
condition: and(succeeded(), and(ne(variables['Build.Reason'], 'Manual'), eq(variables['Build.SourceBranchName'], 'main')))
variables:
PackageVersion: $[ stageDependencies.CSharp_Build.Build_linux_20.outputs['ci_build.emitterVersion'] ]
pool:
name: $(LINUXPOOL)
image: $(LINUXVMIMAGE)
os: linux
jobs:
- job: CreatePR
steps:
- checkout: self
- pwsh: |
# Determine the TypeSpec PR URL
$sourceBranch = '$(Build.SourceBranch)'
$repoUrl = '$(Build.Repository.Uri)'

if ($sourceBranch -match "^refs/pull/(\d+)/(head|merge)$") {
$typeSpecPRUrl = "$repoUrl/pull/$($Matches[1])"
} elseif ($sourceBranch -match "^refs/heads/(.+)$") {
$typeSpecPRUrl = "$repoUrl/tree/$($Matches[1])"
} else {
$typeSpecPRUrl = "$repoUrl/tree/$sourceBranch"
}
Write-Host "TypeSpec PR URL: $typeSpecPRUrl"
Write-Host "##vso[task.setvariable variable=TypeSpecPRUrl]$typeSpecPRUrl"
displayName: Set variables for PR creation

- task: PowerShell@2
displayName: Create PR in azure-sdk-for-net
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/packages/http-client-csharp/eng/scripts/Submit-AzureSdkForNetPr.ps1
arguments: >
-PackageVersion '$(PackageVersion)'
-TypeSpecPRUrl '$(TypeSpecPRUrl)'
-AuthToken '$(azuresdk-github-pat)'
232 changes: 232 additions & 0 deletions packages/http-client-csharp/eng/scripts/Submit-AzureSdkForNetPr.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
#!/usr/bin/env pwsh

<#
.DESCRIPTION
Creates a pull request in the Azure SDK for .NET repository to update the UnbrandedGeneratorVersion property in eng/Packages.Data.props and the @typespec/http-client-csharp dependency in eng/packages/http-client-csharp/package.json.
.PARAMETER PackageVersion
The version of the Microsoft.TypeSpec.Generator.ClientModel package to update to.
.PARAMETER TypeSpecPRUrl
The URL of the pull request in the TypeSpec repository that triggered this update.
.PARAMETER AuthToken
A GitHub personal access token for authentication.
.PARAMETER BranchName
The name of the branch to create in the azure-sdk-for-net repository.
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true)]
[string]$PackageVersion,

[Parameter(Mandatory = $true)]
[string]$TypeSpecPRUrl,

[Parameter(Mandatory = $true)]
[string]$AuthToken,

[Parameter(Mandatory = $false)]
[string]$BranchName = "typespec/update-http-client-$PackageVersion"
)

# Import the Generation module to use the Invoke helper function
Import-Module (Join-Path $PSScriptRoot "Generation.psm1")

# Set up variables for the PR
$RepoOwner = "Azure"
$RepoName = "azure-sdk-for-net"
$BaseBranch = "main"
$PROwner = "azure-sdk"
$PRBranch = $BranchName

$PRTitle = "Update UnbrandedGeneratorVersion to $PackageVersion"
$PRBody = @"
This PR updates the UnbrandedGeneratorVersion property in eng/Packages.Data.props and the @typespec/http-client-csharp dependency in eng/packages/http-client-csharp/package.json to version $PackageVersion.

## Details

- Original TypeSpec PR: $TypeSpecPRUrl

## Changes

- Updated eng/Packages.Data.props UnbrandedGeneratorVersion property
- Updated eng/packages/http-client-csharp/package.json dependency version
- Ran npm install to update package-lock.json

This is an automated PR created by the TypeSpec publish pipeline.
"@

Write-Host "Creating PR in $RepoOwner/$RepoName"
Write-Host "Branch: $PRBranch"
Write-Host "Title: $PRTitle"

# Create temp folder for repo
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) "azure-sdk-for-net-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
Write-Host "Created temp directory: $tempDir"

try {
# Clone the repository
Write-Host "Cloning azure-sdk-for-net repository..."
git clone "https://github.com/$RepoOwner/$RepoName.git" $tempDir
if ($LASTEXITCODE -ne 0) {
throw "Failed to clone repository"
}

Push-Location $tempDir

# Create a new branch
Write-Host "Creating branch $PRBranch..."
git checkout -b $PRBranch
if ($LASTEXITCODE -ne 0) {
throw "Failed to create branch"
}

# Update the dependency in eng/Packages.Data.props
Write-Host "Updating dependency version in eng/Packages.Data.props..."
$propsFilePath = Join-Path $tempDir "eng/Packages.Data.props"

if (-not (Test-Path $propsFilePath)) {
throw "eng/Packages.Data.props not found in the repository"
}

$propsFileContent = Get-Content $propsFilePath -Raw

# Update the UnbrandedGeneratorVersion property in the file
$pattern = '<UnbrandedGeneratorVersion>[^<]*</UnbrandedGeneratorVersion>'
$replacement = '<UnbrandedGeneratorVersion>' + $PackageVersion + '</UnbrandedGeneratorVersion>'

$updatedContent = $propsFileContent -replace $pattern, $replacement

$propsFileUpdated = $false
if ($updatedContent -eq $propsFileContent) {
Write-Warning "No changes were made to eng/Packages.Data.props. The UnbrandedGeneratorVersion property might not exist or have a different format."
Write-Host "Current content around UnbrandedGeneratorVersion:"
$propsFileContent | Select-String -Pattern "UnbrandedGeneratorVersion" -Context 2, 2
} else {
$propsFileUpdated = $true
# Write the updated file back
Set-Content -Path $propsFilePath -Value $updatedContent -NoNewline
}

# Update the dependency in eng/packages/http-client-csharp/package.json
Write-Host "Updating dependency version in eng/packages/http-client-csharp/package.json..."
$packageJsonPath = Join-Path $tempDir "eng/packages/http-client-csharp/package.json"

if (-not (Test-Path $packageJsonPath)) {
throw "eng/packages/http-client-csharp/package.json not found in the repository"
}

$packageJsonContent = Get-Content $packageJsonPath -Raw | ConvertFrom-Json

# Update the Microsoft.TypeSpec.Generator.ClientModel dependency version
$packageJsonUpdated = $false
if ($packageJsonContent.dependencies -and $packageJsonContent.dependencies."@typespec/http-client-csharp") {
$packageJsonContent.dependencies."@typespec/http-client-csharp" = $PackageVersion
$packageJsonUpdated = $true
Write-Host "Updated @typespec/http-client-csharp in dependencies"
# Write the updated package.json back
$packageJsonContent | ConvertTo-Json -Depth 10 | Set-Content -Path $packageJsonPath
} else {
Write-Warning "No @typespec/http-client-csharp dependency found in package.json"
}

# Check if any updates were made - bail early if not
if (-not $propsFileUpdated -and -not $packageJsonUpdated) {
Write-Warning "No updates were made to any files. The package version might already be current or the files might not contain the expected properties."
return
}

# Only run expensive operations if we actually made updates
if ($packageJsonUpdated) {
# Run npm install in the http-client-csharp directory
Write-Host "Running npm install in eng/packages/http-client-csharp..."
$httpClientDir = Join-Path $tempDir "eng/packages/http-client-csharp"
Invoke "npm install" $httpClientDir
if ($LASTEXITCODE -ne 0) {
throw "npm install failed"
}

# Run npm run build
Write-Host "Running npm run build in eng/packages/http-client-csharp..."
Invoke "npm run build" $httpClientDir
if ($LASTEXITCODE -ne 0) {
throw "npm run build failed"
}

# Run Generate.ps1 from the repository root
Write-Host "Running eng/scripts/Generate.ps1..."
Invoke "eng/scripts/Generate.ps1" $tempDir
if ($LASTEXITCODE -ne 0) {
throw "Generate.ps1 failed"
}
}

# Check if there are changes to commit
$gitStatus = git status --porcelain
if (-not $gitStatus) {
Write-Warning "No changes detected. Skipping commit and PR creation."
return
}

# Commit the changes
Write-Host "Committing changes..."
if ($propsFileUpdated) {
git add eng/Packages.Data.props
}
if ($packageJsonUpdated) {
git add eng/packages/http-client-csharp/package.json
git add eng/packages/http-client-csharp/package-lock.json
}
if ($LASTEXITCODE -ne 0) {
throw "Failed to add changes"
}

# Build commit message based on what was updated
$commitMessage = "Update UnbrandedGeneratorVersion to $PackageVersion`n"
if ($propsFileUpdated) {
$commitMessage += "`n- Updated eng/Packages.Data.props"
}
if ($packageJsonUpdated) {
$commitMessage += "`n- Updated eng/packages/http-client-csharp/package.json"
$commitMessage += "`n- Ran npm install to update package-lock.json"
}

git commit -m $commitMessage
if ($LASTEXITCODE -ne 0) {
throw "Failed to commit changes"
}

# Push the branch
Write-Host "Pushing branch to remote..."
$remoteUrl = "https://$AuthToken@github.com/$RepoOwner/$RepoName.git"
git push $remoteUrl $PRBranch
if ($LASTEXITCODE -ne 0) {
throw "Failed to push branch"
}

# Create PR using GitHub CLI
Write-Host "Creating PR in $RepoOwner/$RepoName using gh CLI..."

# Set the authentication token for gh CLI
$env:GH_TOKEN = $AuthToken

# Create the PR using gh CLI
$ghOutput = gh pr create --repo "$RepoOwner/$RepoName" --title $PRTitle --body $PRBody --base $BaseBranch --head $PRBranch 2>&1

if ($LASTEXITCODE -ne 0) {
throw "Failed to create PR using gh CLI: $ghOutput"
}

# Extract PR URL from gh output
$prUrl = $ghOutput.Trim()
Write-Host "Successfully created PR: $prUrl"

} catch {
Write-Error "Error creating PR: $_"
exit 1
} finally {
Pop-Location
# Clean up temp directory
if (Test-Path $tempDir) {
Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
Loading
Oops, something went wrong.