- name
- tool-version-upgrade
- description
- **WORKFLOW SKILL** — Bumps pinned upstream versions in azd for the GitHub CLI, Bicep CLI, and GitHub Actions referenced in `.github/workflows/*.yml`. Fetches the latest release, confirms with the user, opens a tracking issue, updates source and workflow references, and opens a PR.
INVOKES: GitHub MCP tools, gh CLI, git CLI, go build, ask_user.
USE FOR: upgrade github cli, bump gh cli, upgrade bicep cli, bump bicep, upgrade github actions, audit workflow action versions, upgrade tool version.
DO NOT USE FOR: code review (use code-review), changelog generation (use changelog-generation), deploying releases, publishing extensions to registry.
- license
- MIT
- metadata
- {"version":"1.0.0"}
# tool-version-upgrade
**WORKFLOW SKILL** — Upgrades a bundled CLI tool version in azd to the latest upstream release.
INVOKES: GitHub MCP tools, `gh` CLI, `git` CLI, `go build`, `ask_user`.
## Supported Tools
| Parameter | GitHub CLI | Bicep CLI | GitHub Actions (workflows) |
| ---------------- | ------------------------------------------------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------- |
| Tool name | GitHub CLI | Bicep CLI | GitHub Actions |
| Tool slug | `gh-cli` | `bicep-cli` | `gh-actions` |
| Upstream repo | `cli/cli` | `Azure/bicep` | (per-action; e.g. `actions/checkout`, `actions/setup-node`, `golangci/golangci-lint-action`) |
| Go version file | `cli/azd/pkg/tools/github/github.go` | `cli/azd/pkg/tools/bicep/bicep.go` | n/a |
| Version variable | `var Version semver.Version = semver.MustParse("{version}")` | same | n/a — versions are pinned per `uses:` line in YAML |
| Files to update | 1 file (see below) | 2 files (see below) | every `.github/workflows/*.yml` containing an outdated `uses:` reference (see below) |
### GitHub CLI — Files to Update
Only **one file**:
1. **`cli/azd/pkg/tools/github/github.go`**
- Update the `Version` variable: `var Version semver.Version = semver.MustParse("{new_version}")`
- Update the example comment on the download URL line if present (e.g., change the version in
`// example: https://github.com/cli/cli/releases/download/v{version}/gh_{version}_linux_arm64.tar.gz`)
### Bicep CLI — Files to Update
**Two files** (both must be updated together):
1. **`cli/azd/pkg/tools/bicep/bicep.go`**
- Update the `Version` variable: `var Version semver.Version = semver.MustParse("{new_version}")`
2. **`.github/workflows/lint-bicep.yml`**
- Update the download URL in the "Upgrade bicep" step:
```yaml
sudo curl -o $(which bicep) -L https://github.com/Azure/bicep/releases/download/v{new_version}/bicep-linux-x64
```
> **⚠️ Important** (Bicep only): Both files must be updated together to keep Go code and CI workflow
> in sync. Forgetting the workflow file is a common mistake — always verify both are changed.
### GitHub Actions (workflows) — Files to Update
**N files** — every `.github/workflows/*.yml` containing an outdated `uses:` reference. Scope is
limited to that directory; do not edit local actions, reusable workflows in this repo, or
devcontainer feature definitions.
For each `uses: owner/repo@ref` line, classify and act:
| Bucket | Pattern | Action |
| ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Major-tag pin | `uses: owner/repo@vN` (N is an integer) | Bump to latest stable major (`@vM`). |
| Exact-version pin | `uses: owner/repo@vX.Y.Z` or `@X.Y.Z` | Bump to latest stable major tag (`@vM`). |
| SHA pin | `uses: owner/repo@<40-hex-sha> # vN` | Resolve the SHA the latest major tag points to, replace **both** the SHA and the trailing `# vN` comment so they stay paired. **Never** demote a SHA pin to a bare tag. |
| Branch ref | `uses: owner/repo@main` (or any non-version ref) | **Skip**, list as warning. Branch refs are usually intentional. |
| Local action | `uses: ./...` | **Skip** silently. |
| Local reusable workflow | `uses: ./.github/workflows/...` | **Skip** silently. |
> **⚠️ Important** (GitHub Actions only): one run produces **one tracking issue and one PR**
> covering every outdated reference, grouped by action. Do not open one PR per action.
> **⚠️ Supply-chain hardening**: SHA-pinned references exist on purpose — typically for workflows
> that gate releases or extension approvals (e.g., `approval-ext-azure-ai-agents.yml`).
## Workflow
### Step 1 — Identify Tool
If the user's request doesn't specify which tool, ask via `ask_user`:
> Which tool would you like to upgrade?
Choices:
- **GitHub CLI**
- **Bicep CLI**
- **GitHub Actions (workflow files)**
Use the corresponding column from the **Supported Tools** table for all subsequent steps.
### Step 2 — Fetch Latest Release
```bash
gh release view --repo {upstream_repo} --json tagName,name,publishedAt,body
```
The tag format is `v{version}` (e.g., `v2.86.0` or `v0.41.2`). Strip the `v` prefix to get the semver.
After stripping the `v` prefix, **validate the version is strict semver** (no pre-release suffixes):
```bash
echo "$version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$' || { echo "Unexpected version format: $version"; exit 1; }
```
If the latest release is a pre-release (e.g., `v0.42.0-rc1`), **stop and warn the user** — do not
use pre-release versions. Suggest the user wait for the stable release or specify a version manually.
If `gh release view` fails, fall back to:
```bash
gh api repos/{upstream_repo}/releases/latest --jq '.tag_name'
```
### Step 3 — Read Current Version
```bash
grep -n 'var Version semver.Version' {go_version_file}
```
Extract the version string from the `semver.MustParse("X.Y.Z")` call.
**Bicep only** — also verify the CI workflow version matches:
```bash
grep -n 'bicep/releases/download' .github/workflows/lint-bicep.yml
```
If the two versions don't match, warn the user before proceeding.
### Step 4 — Compare & Confirm Upgrade
1. If the current version **equals** the latest release, inform the user and **stop** — no issue,
branch, or PR needed:
> ✅ {tool_name} is already at the latest version (**{version}**). No update needed.
2. If the current version is **newer** than the latest release, **stop and warn** — this likely
means the latest GitHub release is not yet stable, or the pinned version was set manually:
> ⚠️ The current {tool_name} version (**{current_version}**) is newer than the latest release
> (**{latest_version}**). This may indicate a pre-release pin or a release rollback. No action taken.
3. If the latest is newer, present the upgrade summary via `ask_user`:
> The current {tool_name} version is **{current_version}**.
> The latest release is **{latest_version}** (released {release_date}).
>
> Proceed with upgrade?
Choices:
- **Yes, upgrade to {latest_version}** _(Recommended)_
- **No, cancel**
### Step 5 — Final Confirmation Gate
> **⚠️ MANDATORY — even in autopilot / auto-approve / yolo mode.**
> This confirmation MUST use `ask_user` and MUST NOT be skipped regardless of agent autonomy settings.
> This is a safety gate to prevent false-positive upgrades (e.g., wrong version parsed, pre-release
> tag picked up).
Present a full summary via `ask_user`:
> **Ready to apply {tool_name} upgrade**
>
> - Current version: **{current_version}**
> - Target version: **{latest_version}**
> - Upstream release: {release_url}
> - Files to modify:
> {files_list_with_paths}
>
> This will:
>
> 1. Create a tracking issue in Azure/azure-dev
> 2. Create a new branch from `origin/main`
> 3. Apply the version changes
> 4. Open a PR
>
> Confirm to proceed?
Choices:
- **Yes, apply upgrade** _(Recommended)_
- **No, cancel**
If the user cancels, stop immediately — do not create the issue, branch, or PR.
### Step 6 — Create Clean Branch, Apply Changes & Build
Per [references/tool-upgrade-workflow.md](references/tool-upgrade-workflow.md) § Create Clean Branch from origin/main.
1. Verify the working tree is clean (`git status --porcelain`). If dirty, **stop** and warn:
> Your working tree has uncommitted changes. Please commit or stash them before running
> this skill, so the upgrade PR contains only the version bump.
Do NOT proceed with dirty state — do not use `git stash` automatically.
2. Delete any stale branch from a previous cancelled run, then create the branch from `origin/main`:
```bash
git fetch origin main
git branch -D update/{tool_slug}-{latest_version} 2>/dev/null || true
git checkout -b update/{tool_slug}-{latest_version} origin/main
```
3. Verify zero commits ahead of origin/main:
```bash
git --no-pager log --oneline origin/main..HEAD
```
Must produce no output. If it shows any commits, abort.
4. Apply the file edits:
**GitHub CLI**: Edit `cli/azd/pkg/tools/github/github.go`:
- Replace version in `semver.MustParse("{old}")` with the new version.
- Update any example URL comments that reference the old version.
**Bicep CLI**: Edit both files:
- `cli/azd/pkg/tools/bicep/bicep.go` — replace version in `semver.MustParse("{old}")`.
- `.github/workflows/lint-bicep.yml` — replace old version in the curl download URL.
5. Build and verify:
```bash
cd cli/azd && go build ./...
```
If the build fails, **delete the branch, report the error, and stop**.
Do NOT create an issue or PR for a broken build.
6. **Bicep only** — verify both files have the new version:
```bash
grep 'MustParse' cli/azd/pkg/tools/bicep/bicep.go | head -1
grep 'bicep/releases/download' .github/workflows/lint-bicep.yml
```
7. Stage **only** the expected files (do NOT use `git add -A`):
**GitHub CLI**:
```bash
git add cli/azd/pkg/tools/github/github.go
```
**Bicep CLI**:
```bash
git add cli/azd/pkg/tools/bicep/bicep.go .github/workflows/lint-bicep.yml
```
8. Verify nothing unexpected is staged:
```bash
git --no-pager diff --cached --stat
```
Output must show ONLY the expected files. If unexpected files appear, abort.
### Step 7 — Create Tracking Issue
> **Note**: The issue is created **after** the build succeeds to avoid orphan issues when the
> build or staging validation fails.
```bash
gh issue create \
--repo Azure/azure-dev \
--title "Update {tool_name} version to {latest_version}" \
--body "{issue_body}"
Ver en GitHub