Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
294 changes: 280 additions & 14 deletions .github/skills/tool-version-upgrade/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
---
name: tool-version-upgrade
description: >-
**WORKFLOW SKILL** — Upgrades bundled CLI tool versions (GitHub CLI or Bicep CLI) in azd.
Fetches the latest release from the upstream repo, compares with the current pinned version,
confirms with the user, creates a tracking issue, updates version references in source code
and CI workflows, and opens a PR.
**WORKFLOW SKILL** — Upgrades bundled CLI tool versions (GitHub CLI or Bicep CLI) and pinned tool versions to the latest stable upstream release in azd.
Supported targets: GitHub CLI (Go source), Bicep CLI (Go source + lint workflow), and GitHub Actions referenced in `.github/workflows/*.yml` (audit + bulk bump).
Fetches the latest release(s) upstream, compares with the current pinned version(s),
confirms with the user, creates a tracking issue, updates the references in source code, GitHub Action workflows, and CI workflows,
and opens a PR.

INVOKES: GitHub MCP tools, gh CLI, git CLI, go build, ask_user.

USE FOR: upgrade github cli, update gh cli, update github cli version,
upgrade gh to latest, bump gh cli, gh cli update, update gh tool version,
upgrade bicep cli, update bicep cli, update bicep version,
upgrade bicep to latest, bump bicep, bicep cli update, update bicep tool version,
upgrade tool version, update tool version.
upgrade tool version, update tool version,
upgrade github actions, update github actions, bump github actions,
audit github actions versions, update workflow actions, check actions versions,
upgrade actions/checkout, upgrade actions/setup-node, upgrade actions/setup-python,
upgrade actions/setup-go, upgrade actions/github-script, upgrade golangci-lint-action,
refresh workflow action versions, gh actions version bump.

DO NOT USE FOR: code review (use code-review), changelog generation (use changelog-generation),
deploying releases, publishing extensions to registry.
Expand All @@ -26,14 +32,14 @@ INVOKES: GitHub MCP tools, `gh` CLI, `git` CLI, `go build`, `ask_user`.

## Supported Tools

| Parameter | GitHub CLI | Bicep CLI |
|-----------|-----------|-----------|
| Tool name | GitHub CLI | Bicep CLI |
| Tool slug | `gh-cli` | `bicep-cli` |
| Upstream repo | `cli/cli` | `Azure/bicep` |
| Go version file | `cli/azd/pkg/tools/github/github.go` | `cli/azd/pkg/tools/bicep/bicep.go` |
| Version variable | `var Version semver.Version = semver.MustParse("{version}")` | same |
| Files to update | 1 file (see below) | 2 files (see below) |
| 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

Expand All @@ -60,6 +66,29 @@ Only **one file**:
> **⚠️ 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
Expand All @@ -71,8 +100,9 @@ If the user's request doesn't specify which tool, ask via `ask_user`:
Choices:
- **GitHub CLI**
- **Bicep CLI**
- **GitHub Actions (workflow files)**

Use the corresponding row from the **Supported Tools** table for all subsequent steps.
Use the corresponding column from the **Supported Tools** table for all subsequent steps.

### Step 2 — Fetch Latest Release

Expand Down Expand Up @@ -321,6 +351,232 @@ Present a summary to the user:

---

## GitHub Actions (workflows) — Step Overrides

When the selected tool is **GitHub Actions**, Steps 2, 3, 4, 6, 7, and 8 differ from the
single-tool flow above. Steps 1 (Identify Tool) and 5 (Final Confirmation Gate) work the
same way. The branch slug is `gh-actions-versions` (no version suffix, since this run
covers many actions at once).

### Step 2 (override) — Inventory References

Scan every workflow file:

```bash
git grep -nE '^\s*uses:\s+[^ ]+' -- '.github/workflows/*.yml'
```

Parse each line into one of the buckets in **GitHub Actions (workflows) — Files to Update**.
Deduplicate by `(owner/repo, current_ref)` so each unique reference is fetched only once.

### Step 3 (override) — Fetch Latest Stable Major per Action

For each unique `owner/repo`:

```bash
gh release view --repo {owner}/{repo} --json tagName,name,publishedAt,isPrerelease
```

Treat the leading integer of `tagName` as the latest **major** (e.g., `v6.0.1` → `v6`).
If the latest release is a pre-release (`isPrerelease: true`), fall back to:

```bash
gh release list --repo {owner}/{repo} --limit 20 --json tagName,isPrerelease \
| jq -r '[.[] | select(.isPrerelease==false)][0].tagName'
```

If the tag does not match `v[0-9]+(\.[0-9]+\.[0-9]+)?`, **skip** this action and add it
to the warnings list — do not guess.

For SHA-pinned references, additionally resolve the commit SHA the major tag currently
points to:

```bash
gh api repos/{owner}/{repo}/git/refs/tags/v{major} --jq '.object.sha'
```

If `.object.type == "tag"` (annotated tag), follow once:

```bash
gh api repos/{owner}/{repo}/git/tags/{sha} --jq '.object.sha'
```

### Step 4 (override) — Compute Diff & Compare

For each parsed reference, compute the desired new value per the buckets table. If
`new == current`, drop from the change list.

If the change list is **empty** after this step, inform the user and **stop** — no
issue, branch, or PR needed:

> ✅ All GitHub Actions references are already at the latest stable major. No updates needed.

If any reference has a cross-major jump (e.g., `v4 → v6` skipping `v5`), record a
**breaking-change advisory** for the Step 5 confirmation prompt so the user can
spot-check release notes before approving.

### Step 5 (Final Confirmation Gate — adapted)

Use the standard gate, but the summary must show:

- Outdated references grouped by action with `current → new` and the affected file count.
- Skipped entries (branch refs, unparseable tags, pre-release-only repos).
- Cross-major-jump advisories.
- The full list of files that will be modified.

Example summary body:

> **GitHub Actions upgrade — ready to apply**
>
> | Action | Current | New | Files |
> |---|---|---|---|
> | actions/checkout | v4 | v6 | 14 |
> | actions/setup-node | v4 | v6 | 7 |
> | actions/github-script | v7 (SHA-pinned) | v9 (SHA-pinned) | 1 |
>
> Skipped (branch refs): `actions/stale@main` in `stale-issues.yml`
>
> ⚠️ Cross-major jumps: `actions/checkout v4 → v6` (skips v5).

### Step 6 (override) — Branch & Apply Edits

Use the standard clean-branch flow but with a fixed slug:

```bash
git fetch origin main
git branch -D update/gh-actions-versions 2>/dev/null || true
git checkout -b update/gh-actions-versions origin/main
git --no-pager log --oneline origin/main..HEAD # must be empty
```

Apply edits with these constraints:

- Replace **only** on the parsed `uses:` lines. Never use a project-wide find-and-replace.
- For SHA-pinned references, replace **both** the SHA and the trailing `# vN` comment in
a single edit so they stay paired.
- Preserve indentation and surrounding YAML exactly.

After all edits, sanity-check the diff for accidental SHA-pin demotion:

```bash
git --no-pager diff -- '.github/workflows/*.yml' | grep -E '^[-+].*uses:'
```

If a `-uses: owner/repo@<sha> # vN` line appears paired with a `+uses: owner/repo@vM`
**without** an SHA, **abort** and report.

### Step 7 (override) — Validation & Staging

There is no Go build for workflow-only edits. Validate YAML parses:

```bash
for f in .github/workflows/*.yml; do
python -c "import sys, yaml; yaml.safe_load(open(sys.argv[1]))" "$f"
done
```

If any file fails to parse, **abort and revert** the edits to that file. If every
file fails, abort the whole run.

If `actionlint` happens to be installed locally, run it as an extra check:

```bash
actionlint .github/workflows/*.yml || true
```

Do NOT install `actionlint` automatically — the project's own lint workflows will
catch issues on the PR.

Stage explicitly — never `git add -A`:

```bash
git add .github/workflows/*.yml
git --no-pager diff --cached --stat
```

The diff stat must contain ONLY paths under `.github/workflows/`. If anything else
is staged, **abort**.

### Step 8 (override) — Issue, Commit & PR

**Issue title:** `Update GitHub Actions to latest stable versions`

**Issue body:**

```markdown
Audit and bump GitHub Actions referenced in `.github/workflows/*.yml` to the latest
stable major versions.

### Upgrades

{table_of_action_to_current_to_new_to_file_count}

### Skipped

{list_of_skipped_branch_refs_or_unparseable_tags}

### Files modified

{bullet_list_of_workflow_files}
```

**Commit & push:**

```bash
git commit -m "Update GitHub Actions to latest stable versions" \
-m "Fixes #{issue_number}"
git push -u origin update/gh-actions-versions
gh pr create \
--repo Azure/azure-dev \
--title "Update GitHub Actions to latest stable versions" \
--body "{pr_body}" \
--base main
```

**PR body:**

```markdown
Bump all GitHub Actions referenced in workflow files to their latest stable major versions.

Fixes #{issue_number}

## Upgrades

{table_of_action_to_current_to_new_to_file_count}

## Notes

- Major-tag pins (`@vN`) preserved.
- SHA pins (`@<sha> # vN`) preserved as SHA pins, with both the SHA and the `# vN`
comment updated together to stay in sync.
- Branch refs (e.g., `@main`) intentionally skipped.
- Cross-major jumps (where applicable) called out below; release notes should be
reviewed before merge.

{breaking_change_callouts_if_any}
```

### Post-Creation (GitHub Actions)

> ✅ Done!
> - Issue: #{issue_number} — {issue_url}
> - PR: #{pr_number} — {pr_url}
> - Actions bumped: {count}
> - Files modified: {file_count}

### Out of Scope (GitHub Actions)

- Pinning previously unpinned actions to SHAs. (Use the existing convention: bare
major tags by default; SHAs only where the file already SHA-pins.)
- Bumping the Go toolchain inside `setup-go` `with: go-version:` — that's a separate
workflow (`validate-go-version`).
- Bumping Node / Python / Bicep tool *runtime* versions inside `setup-*` `with:` blocks.
- Updating actions used outside `.github/workflows/` (e.g., devcontainer features).

If the user asks for any of the above, tell them this skill does not cover it.

---

## Error Handling

- `gh release view` fails → fall back to `gh api repos/{upstream_repo}/releases/latest`
Expand All @@ -330,3 +586,13 @@ Present a summary to the user:
- Version mismatch between `bicep.go` and `lint-bicep.yml` before upgrade → warn user, ask which to use as baseline
- Unexpected files staged → abort, report what was found
- Issue or PR creation fails → report error, provide manual commands
- **GitHub Actions only** — `gh release view` fails for an action → fall back to
`gh release list` and pick the newest non-prerelease; if still none, skip the action
and add it to warnings
- **GitHub Actions only** — YAML parse failure after edits → revert that file, drop
it from the change list, continue with the rest. If every file fails, abort the run.
- **GitHub Actions only** — a SHA pin demoted to a bare tag pin detected in the diff
→ abort, report the file/line, do not commit
- **GitHub Actions only** — a major tag (e.g., `@v3`) no longer exists upstream because
the action was renamed/archived → skip and add to warnings; never silently rewrite to
a different `owner/repo`
4 changes: 2 additions & 2 deletions .github/workflows/approval-ext-azure-ai-agents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Check for required team approval
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
uses: actions/github-script@v9
Comment thread
hemarina marked this conversation as resolved.
with:
script: |
const script = require('./.github/scripts/approval-ext-azure-ai-agents.js');
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/cli-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ jobs:
cspell-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- run: npm install -g cspell@8.13.1
Expand All @@ -38,7 +38,7 @@ jobs:
Copyright-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Copyright check
run: ./eng/scripts/copyright-check.sh ./cli/azd

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
# Fetch full history for writing changelogs
fetch-depth: 0
Expand All @@ -41,7 +41,7 @@ jobs:
go-version-file: cli/azd/go.mod

- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: "20"

Expand Down
Loading
Loading