Skip to content

fix(release): install GitHub CLI on the AzDO release agent#17478

Open
radical wants to merge 2 commits into
microsoft:mainfrom
radical:ankj/fix-publish-release-cli-assets-no-gh
Open

fix(release): install GitHub CLI on the AzDO release agent#17478
radical wants to merge 2 commits into
microsoft:mainfrom
radical:ankj/fix-publish-release-cli-assets-no-gh

Conversation

@radical
Copy link
Copy Markdown
Member

@radical radical commented May 25, 2026

The Upload CLI Assets to GitHub Release job in the release-to-NuGet pipeline (microsoft-aspire-Release-To-NuGet) failed with:

publish-release-cli-assets.ps1 : The term 'gh' is not recognized as a name
of a cmdlet, function, script file, or executable program.

The job runs on NetCore1ESPool-Internal / windows.vs2026preview.scout.amd64, which doesn't ship the GitHub CLI on PATH.

SHA512 verification and token minting completed successfully; only the final gh release upload --clobber call broke.

Install step

Add an install step to PublishReleaseAssetsJob ahead of the existing upload. It downloads gh from cli/cli's releases at a pinned version and verifies the archive against a pinned SHA256 before putting it on PATH. Bump both together when refreshing.

Direct download avoids depending on choco or winget being present on the image, so the fix doesn't churn on future image changes.

This matches the established dnceng pattern used by dotnet/dotnet-monitor and dotnet/diagnostics, plus a hash pin those scripts don't currently do.

Script changes

Tighten publish-release-cli-assets.ps1 to make a dry-run a useful smoke test of everything the live upload depends on:

  • gh --version is checked with a CommandNotFoundException catch so the missing-on-PATH case prints an actionable message instead of a raw runtime error.
  • When credentials are supplied (the pipeline always supplies them for both dry-run and live), the script mints the installation token via Get-AspireBotInstallationToken.ps1 and runs gh auth status --hostname github.com. A green CI dry-run faithfully exercises the full auth chain.
  • When credentials are absent, dry-run still verifies SHA512s and gh availability and reports what would be uploaded. This lets a release manager sanity-check the script locally without needing the App secrets.
  • Only the final destructive gh release upload --clobber is gated by -DryRun. --clobber makes live re-runs idempotent.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 25, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17478

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17478"

@radical radical force-pushed the ankj/fix-publish-release-cli-assets-no-gh branch 4 times, most recently from 8d68791 to 58fd5dc Compare May 26, 2026 00:00
@radical radical marked this pull request as ready for review May 26, 2026 00:14
@radical radical requested review from Copilot, davidfowl and joperezr May 26, 2026 00:14
@radical radical requested a review from sebastienros May 26, 2026 00:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an Azure DevOps release pipeline failure caused by the GitHub CLI (gh) not being available on the windows.vs2026preview.scout.amd64 scout image by adding a pinned, hash-verified GitHub CLI install step and tightening the upload script to validate prerequisites (including auth) even in dry-run scenarios.

Changes:

  • Add a PublishReleaseAssetsJob pipeline step that downloads a pinned gh release ZIP and verifies it against a pinned SHA256 before prepending it to PATH.
  • Update publish-release-cli-assets.ps1 to (a) explicitly verify gh availability, and (b) exercise the GitHub App token minting + gh auth status path when credentials are present, while still supporting credential-less local dry-runs.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
eng/pipelines/scripts/publish-release-cli-assets.ps1 Adds gh presence checks, improves dry-run behavior, and adds optional auth-chain verification when credentials are provided.
eng/pipelines/release-publish-nuget.yml Installs GitHub CLI on the AzDO release agent via direct download with pinned version + SHA256 verification.
Comments suppressed due to low confidence (1)

eng/pipelines/scripts/publish-release-cli-assets.ps1:213

  • The script overwrites $env:GH_TOKEN and then unconditionally removes it in finally. If the caller already had GH_TOKEN set (e.g., running locally in a shell that uses GH_TOKEN for other gh invocations), this script will clear it permanently after it exits. Consider capturing the prior value and restoring it in finally (or only removing if the script set it and it was previously unset).
# Hand the token to gh via GH_TOKEN. --clobber on the live upload makes
# re-runs idempotent. The try/finally spans both the auth check and the
# live upload so the token is scrubbed from the environment even if we
# exit early.
$env:GH_TOKEN = $installationToken
try {
    Write-Host ""
    Write-Host "Verifying gh can authenticate to github.com..."
    & gh auth status --hostname github.com
    if ($LASTEXITCODE -ne 0) {
        Write-Error "gh auth status failed with exit code $LASTEXITCODE."
        exit $LASTEXITCODE
    }

    if ($DryRun) {
        Write-Host ""
        Write-Host "🔍 [DRY RUN] Would upload the following to release $Tag in ${Owner}/${Repo}:"
        foreach ($f in $allFiles) {
            $sizeMB = [math]::Round($f.Length / 1MB, 2)
            Write-Host "  - $($f.Name) ($sizeMB MB)"
        }
        Write-Host ""
        Write-Host "[DRY RUN] Skipping gh release upload."
        # Exit inside the try block; PowerShell still runs the finally
        # so the token gets cleared from the environment.
        exit 0
    }

    Write-Host ""
    Write-Host "Uploading $($allFiles.Count) asset(s) to release $Tag..."
    $filePaths = $allFiles | ForEach-Object { $_.FullName }
    & gh release upload $Tag @filePaths --repo "$Owner/$Repo" --clobber
    if ($LASTEXITCODE -ne 0) {
        Write-Error "gh release upload failed with exit code $LASTEXITCODE"
        exit $LASTEXITCODE
    }
    Write-Host "✓ Uploaded $($allFiles.Count) asset(s) to $Tag."
}
finally {
    # Don't leave the token in the environment after this script returns.
    Remove-Item Env:\GH_TOKEN -ErrorAction SilentlyContinue
}

Comment thread eng/pipelines/scripts/publish-release-cli-assets.ps1 Outdated
@radical radical force-pushed the ankj/fix-publish-release-cli-assets-no-gh branch from 58fd5dc to bc9b53f Compare May 26, 2026 00:28
radical and others added 2 commits May 25, 2026 20:32
The `Upload CLI Assets to GitHub Release` job in the release-to-NuGet
pipeline (`microsoft-aspire-Release-To-NuGet`) failed with:

```
publish-release-cli-assets.ps1 : The term 'gh' is not recognized as a name
of a cmdlet, function, script file, or executable program.
```

The job runs on `NetCore1ESPool-Internal` /
`windows.vs2026preview.scout.amd64`, which doesn't ship the GitHub CLI on
PATH.

SHA512 verification and token minting completed successfully; only the
final `gh release upload --clobber` call broke.

Install step
------------

Add an install step to `PublishReleaseAssetsJob` ahead of the existing
upload. It downloads gh from cli/cli's releases at a pinned version and
verifies the archive against a pinned SHA256 before putting it on PATH.
Bump both together when refreshing.

Direct download avoids depending on choco or winget being present on the
image, so the fix doesn't churn on future image changes.

This matches the established dnceng pattern used by dotnet/dotnet-monitor
and dotnet/diagnostics, plus a hash pin those scripts don't currently do.

Script changes
--------------

Tighten `publish-release-cli-assets.ps1` to make a dry-run a useful
smoke test of everything the live upload depends on:

- `gh --version` is checked with a `CommandNotFoundException` catch so
  the missing-on-PATH case prints an actionable message instead of a
  raw runtime error.
- When credentials are supplied (the pipeline always supplies them for
  both dry-run and live), the script mints the installation token via
  `Get-AspireBotInstallationToken.ps1` and runs `gh auth status
  --hostname github.com`. A green CI dry-run faithfully exercises the
  full auth chain.
- When credentials are absent, dry-run still verifies SHA512s and gh
  availability and reports what would be uploaded. This lets a release
  manager sanity-check the script locally without needing the App
  secrets.
- Only the final destructive `gh release upload --clobber` is gated by
  `-DryRun`. `--clobber` makes live re-runs idempotent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@radical radical force-pushed the ankj/fix-publish-release-cli-assets-no-gh branch from bc9b53f to 2b6ac73 Compare May 26, 2026 00:32
@radical radical requested review from JamesNK and mitchdenny May 26, 2026 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants