From bdef5251dfdbd2c8278af3fe6fe9153372056e51 Mon Sep 17 00:00:00 2001 From: David Burg <12040431+daviburg@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:29:07 -0700 Subject: [PATCH 1/3] build: remove GitHub PAT from release templates --- eng/ci/library-release.yml | 5 + eng/templates/official/jobs/bump-version.yml | 7 +- .../official/jobs/publish-release.yml | 114 +++++------------- 3 files changed, 41 insertions(+), 85 deletions(-) diff --git a/eng/ci/library-release.yml b/eng/ci/library-release.yml index 8e1066f..3654b6a 100644 --- a/eng/ci/library-release.yml +++ b/eng/ci/library-release.yml @@ -14,6 +14,10 @@ parameters: type: string default: 'connectors-python-sdk' displayName: 'GitHub repository name' + - name: githubServiceConnection + type: string + default: '$(GitHubServiceConnection)' + displayName: 'Azure Pipelines GitHub service connection used for release operations' resources: repositories: @@ -58,3 +62,4 @@ extends: blobPath: ${{ parameters.blobPath }} githubOrg: ${{ parameters.githubOrg }} githubRepo: ${{ parameters.githubRepo }} + githubServiceConnection: ${{ parameters.githubServiceConnection }} diff --git a/eng/templates/official/jobs/bump-version.yml b/eng/templates/official/jobs/bump-version.yml index 5bd4a78..50dc990 100644 --- a/eng/templates/official/jobs/bump-version.yml +++ b/eng/templates/official/jobs/bump-version.yml @@ -19,16 +19,17 @@ jobs: image: 1es-ubuntu-22.04 os: linux steps: + - checkout: self + persistCredentials: true + - powershell: | - $githubUser = "$(GithubUser)" - $githubToken = "$(GithubPat)" $newLibraryVersion = "${{ parameters.libraryVersion }}" if($newLibraryVersion -match '^\d+\.\d+\.\d+(dev|a|b|rc)?\d*$') { # Create GitHub credential git config --global user.name "AzureConnectors" git config --global user.email "azurelogicapps@microsoft.com" - git remote set-url origin "https://${githubUser}:${githubToken}@github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" + git remote set-url origin "https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" # Heading to Artifact Repository Write-Host "Operating based on ${{ parameters.githubRepo }}" diff --git a/eng/templates/official/jobs/publish-release.yml b/eng/templates/official/jobs/publish-release.yml index ac71e3a..e53ccba 100644 --- a/eng/templates/official/jobs/publish-release.yml +++ b/eng/templates/official/jobs/publish-release.yml @@ -21,33 +21,38 @@ parameters: type: string default: 'https://dev.azure.com/azure-sdk/internal/_build?definitionId=6991' displayName: 'Azure SDK partner-release pipeline URL (used in manual PyPI publish instructions)' + - name: githubServiceConnection + type: string + default: '$(GitHubServiceConnection)' + displayName: 'Azure Pipelines GitHub service connection used for GitHub Release creation' jobs: - job: "CreateReleaseTag" displayName: 'Create Release Tag' steps: - - checkout: none + - checkout: self + persistCredentials: true - powershell: | - $githubUser = "$(GithubUser)" - $githubToken = "$(GithubPat)" $newLibraryVersion = "${{ parameters.libraryVersion }}" # Create GitHub credential git config --global user.name "AzureConnectors" git config --global user.email "azurelogicapps@microsoft.com" + git remote set-url origin "https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" - # Clone Repository - git clone --branch "release/$newLibraryVersion" --single-branch ` - "https://${githubUser}:${githubToken}@github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" . - Write-Host "Cloned ${{ parameters.githubRepo }} into local" + # Checkout the release branch created by the BumpVersion stage. + git fetch origin "release/$newLibraryVersion" + git checkout "origin/release/$newLibraryVersion" + $releaseTagCommit = git rev-parse HEAD + Write-Host "##vso[task.setvariable variable=ReleaseTagCommit]$releaseTagCommit" # Create release tag X.Y.Z Write-Host "Creating release tag $newLibraryVersion" git tag -a "$newLibraryVersion" -m "$newLibraryVersion" # Push tag to remote - git push origin $newLibraryVersion + git push origin "refs/tags/$newLibraryVersion" displayName: 'Tag and push x.y.z' - download: current @@ -58,20 +63,6 @@ jobs: $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' - $githubUser = "$(GithubUser)" - $githubToken = "$(GithubPat)" - $newLibraryVersion = "${{ parameters.libraryVersion }}" - - $credential = [System.Convert]::ToBase64String( - [System.Text.Encoding]::ASCII.GetBytes("${githubUser}:${githubToken}")) - - $apiHeaders = @{ - "Accept" = "application/vnd.github+json" - "Authorization" = "Basic $credential" - "X-GitHub-Api-Version" = "2022-11-28" - "Content-Type" = "application/json" - } - # ---- Locate and validate assets BEFORE creating the release ---- # Artifact contains dist files directly (targetPath in build-artifacts.yml is src/dist) $distFolder = Join-Path '$(Pipeline.Workspace)' '${{ parameters.artifactName }}' @@ -89,68 +80,27 @@ jobs: } Write-Host "Assets to upload:" $assetsToUpload | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" } + displayName: 'Validate GitHub release assets' - # ---- Create draft release ---- - Write-Host "Creating GitHub draft release for $newLibraryVersion" - $body = (@{tag_name="$newLibraryVersion";name="Release $newLibraryVersion";body="- Fill in Release Note Here";draft=$true} | ConvertTo-Json -Compress) - $createResponse = Invoke-WebRequest -Headers $apiHeaders -Method Post -Body "$body" ` - -Uri "https://api.github.com/repos/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}/releases" - if ($createResponse.StatusCode -ne 201) { - throw "Failed to create release. HTTP $($createResponse.StatusCode)" - } - $release = $createResponse.Content | ConvertFrom-Json - Write-Host "Draft release created: $($release.html_url)" - - # ---- Upload assets; fail hard on duplicate-name (PyPI-style) ---- - $uploadUrlBase = $release.upload_url -replace '\{\?name,label\}$', '' - $uploadHeaders = @{ - "Accept" = "application/vnd.github+json" - "Authorization" = "Basic $credential" - "X-GitHub-Api-Version" = "2022-11-28" - } - - # Wrap upload loop so any failure deletes the incomplete draft release. - # This keeps the world clean for retries: an operator can rerun the job - # without manually purging a stranded empty/partial draft. - try { - foreach ($asset in $assetsToUpload) { - $assetUploadUrl = '{0}?name={1}' -f $uploadUrlBase, [System.Uri]::EscapeDataString($asset.Name) - Write-Host "Uploading $($asset.Name)..." - try { - $uploadResponse = Invoke-WebRequest -Headers $uploadHeaders -Method Post ` - -Uri $assetUploadUrl -ContentType 'application/octet-stream' -InFile $asset.FullName - } catch { - $status = $null - if ($_.Exception.Response) { - $status = [int]$_.Exception.Response.StatusCode - } - if ($status -eq 422) { - throw "Asset '$($asset.Name)' already exists on release $newLibraryVersion. GitHub releases must be unique per filename (same policy as PyPI). If this is intentional, delete the asset from the GitHub release UI and rerun, or bump the version." - } - throw "Upload failed for $($asset.Name): HTTP $status - $($_.Exception.Message)" - } - if ($uploadResponse.StatusCode -ne 201) { - throw "Upload failed for $($asset.Name). HTTP $($uploadResponse.StatusCode)" - } - Write-Host " -> uploaded" - } - } catch { - $uploadError = $_ - if ($release -and $release.id) { - $releaseDeleteUri = "https://api.github.com/repos/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}/releases/$($release.id)" - Write-Host "##[warning]Asset upload failed. Cleaning up incomplete draft release $($release.id)..." - try { - Invoke-WebRequest -Headers $apiHeaders -Method Delete -Uri $releaseDeleteUri | Out-Null - Write-Host "Draft release $($release.id) deleted." - } catch { - Write-Host "##[warning]Failed to delete draft release $($release.id): $($_.Exception.Message). Manual cleanup required at https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}/releases" - } - } - throw $uploadError - } - - Write-Host "All assets attached to draft release: $($release.html_url)" + - task: GitHubRelease@1 displayName: 'Create GitHub release draft and attach assets' + inputs: + gitHubConnection: '${{ parameters.githubServiceConnection }}' + repositoryName: '${{ parameters.githubOrg }}/${{ parameters.githubRepo }}' + action: 'create' + target: '$(ReleaseTagCommit)' + tagSource: 'userSpecifiedTag' + tag: '${{ parameters.libraryVersion }}' + title: 'Release ${{ parameters.libraryVersion }}' + releaseNotesSource: 'inline' + releaseNotesInline: '- Fill in Release Note Here' + assets: | + $(Pipeline.Workspace)/${{ parameters.artifactName }}/*.whl + $(Pipeline.Workspace)/${{ parameters.artifactName }}/*.tar.gz + isDraft: true + isPreRelease: false + makeLatest: false + addChangeLog: false - job: "CheckGitHubRelease" dependsOn: ['CreateReleaseTag'] From dad3268c9e07681b4252940951118cca022e47a7 Mon Sep 17 00:00:00 2001 From: David Burg <12040431+daviburg@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:40:02 -0700 Subject: [PATCH 2/3] docs: clarify release git setup comments --- eng/templates/official/jobs/bump-version.yml | 2 +- eng/templates/official/jobs/publish-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/templates/official/jobs/bump-version.yml b/eng/templates/official/jobs/bump-version.yml index 93b6ee4..71e1b6b 100644 --- a/eng/templates/official/jobs/bump-version.yml +++ b/eng/templates/official/jobs/bump-version.yml @@ -26,7 +26,7 @@ jobs: $newLibraryVersion = "${{ parameters.libraryVersion }}" if($newLibraryVersion -match '^\d+\.\d+\.\d+((a|b|rc)\d+|\.dev\d+|\.post\d+|-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$') { - # Create GitHub credential + # Configure git identity and origin URL git config --global user.name "AzureConnectors" git config --global user.email "azurelogicapps@microsoft.com" git remote set-url origin "https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" diff --git a/eng/templates/official/jobs/publish-release.yml b/eng/templates/official/jobs/publish-release.yml index e53ccba..5c61b33 100644 --- a/eng/templates/official/jobs/publish-release.yml +++ b/eng/templates/official/jobs/publish-release.yml @@ -36,7 +36,7 @@ jobs: - powershell: | $newLibraryVersion = "${{ parameters.libraryVersion }}" - # Create GitHub credential + # Configure git identity and origin URL git config --global user.name "AzureConnectors" git config --global user.email "azurelogicapps@microsoft.com" git remote set-url origin "https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}.git" From 51209c25d06c940f13a8c4c46b684381469abf52 Mon Sep 17 00:00:00 2001 From: David Burg <12040431+daviburg@users.noreply.github.com> Date: Fri, 19 Jun 2026 04:32:15 -0700 Subject: [PATCH 3/3] build: require GitHub service connection parameter --- eng/ci/library-release.yml | 3 +-- eng/templates/official/jobs/publish-release.yml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/eng/ci/library-release.yml b/eng/ci/library-release.yml index e656004..7ce3b47 100644 --- a/eng/ci/library-release.yml +++ b/eng/ci/library-release.yml @@ -16,8 +16,7 @@ parameters: displayName: 'GitHub repository name' - name: githubServiceConnection type: string - default: '$(GitHubServiceConnection)' - displayName: 'Azure Pipelines GitHub service connection used for release operations' + displayName: 'Pre-created Azure Pipelines GitHub service connection used for release operations' resources: repositories: diff --git a/eng/templates/official/jobs/publish-release.yml b/eng/templates/official/jobs/publish-release.yml index 5c61b33..073daf3 100644 --- a/eng/templates/official/jobs/publish-release.yml +++ b/eng/templates/official/jobs/publish-release.yml @@ -23,8 +23,7 @@ parameters: displayName: 'Azure SDK partner-release pipeline URL (used in manual PyPI publish instructions)' - name: githubServiceConnection type: string - default: '$(GitHubServiceConnection)' - displayName: 'Azure Pipelines GitHub service connection used for GitHub Release creation' + displayName: 'Pre-created Azure Pipelines GitHub service connection used for GitHub Release creation' jobs: - job: "CreateReleaseTag"