From fa715b38e5840492724348b026fe1ec1898e57f5 Mon Sep 17 00:00:00 2001 From: Rajesh Kamal Date: Mon, 11 May 2026 09:43:10 -0700 Subject: [PATCH 1/4] Add sprint-check, issue-cleanup, and hotfix-release Copilot skills Adds three engineering automation skills: - sprint-check: validates sprint readiness, checks labels/milestones/project fields, supports sprint close rollover - issue-cleanup: scans backlog for hygiene gaps, flags customer-reported issues without triage, stale milestones - hotfix-release: creates hotfix branch from release tag, cherry-picks PRs, bumps version files, generates changelog entry Partially addresses #8033 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/hotfix-release/SKILL.md | 249 +++++++++++++ .../references/version-files.md | 66 ++++ .github/skills/issue-cleanup/SKILL.md | 224 ++++++++++++ .../issue-cleanup/references/hygiene-rules.md | 65 ++++ .github/skills/sprint-check/SKILL.md | 328 ++++++++++++++++++ .../sprint-check/references/hygiene-rules.md | 64 ++++ .../references/project-mutations.md | 138 ++++++++ .vscode/cspell.misc.yaml | 10 + 8 files changed, 1144 insertions(+) create mode 100644 .github/skills/hotfix-release/SKILL.md create mode 100644 .github/skills/hotfix-release/references/version-files.md create mode 100644 .github/skills/issue-cleanup/SKILL.md create mode 100644 .github/skills/issue-cleanup/references/hygiene-rules.md create mode 100644 .github/skills/sprint-check/SKILL.md create mode 100644 .github/skills/sprint-check/references/hygiene-rules.md create mode 100644 .github/skills/sprint-check/references/project-mutations.md diff --git a/.github/skills/hotfix-release/SKILL.md b/.github/skills/hotfix-release/SKILL.md new file mode 100644 index 00000000000..3d244be9412 --- /dev/null +++ b/.github/skills/hotfix-release/SKILL.md @@ -0,0 +1,249 @@ +--- +name: hotfix-release +license: MIT +metadata: + version: "1.0" + # Bump major on breaking prompt/trigger changes; bump minor on new references or fix strategies. +description: >- + **WORKFLOW SKILL** — Creates a hotfix release branch from an existing release tag, + cherry-picks specified PRs, bumps version, updates changelog, and pushes the branch. + Interactive — handles cherry-pick conflicts with user guidance. + + INVOKES: git CLI, gh CLI, GitHub MCP tools, ask_user. + + USE FOR: create hotfix, hotfix release, cherry-pick release, patch release, + hotfix for azd, emergency release, create hotfix branch, hotfix from tag. + + DO NOT USE FOR: regular releases (use changelog-generation + ADO pipeline), + changelog only (use changelog-generation), code review (use code-review), + sprint checks (use sprint-check). +--- + +# hotfix-release + +**WORKFLOW SKILL** — Creates hotfix release branches with cherry-picked fixes. + +INVOKES: `git` CLI, `gh` CLI, GitHub MCP tools, `ask_user`. + +## Prerequisites + +| Tool | Purpose | +|------|---------| +| `git` | Git CLI — push access to Azure/azure-dev | +| `gh` | GitHub CLI — authenticated with repo access | + +## Preflight + +Verify access: + +```bash +# Check git remote +git remote -v | grep "Azure/azure-dev" + +# Check gh auth +gh auth status + +# Check write access +gh api repos/Azure/azure-dev --jq .permissions.push +``` + +If push is `false`, stop: +> You need write access to Azure/azure-dev to create hotfix branches. + +## Workflow + +### Step 1 — Parse Request + +The user provides: +- **Release version** to hotfix (e.g., "1.24.3" or "v1.24.3") +- **PR numbers** to cherry-pick (e.g., "#8001, #8002" or "8001 8002") + +Example prompts: +- "create hotfix for v1.24.3 with PRs #8001, #8002" +- "hotfix 1.24.3 cherry-pick 8001 8002" +- "patch release for 1.24.3" + +If either is missing, ask via `ask_user`. + +**Version**: ask for the base release version to hotfix: +> Which release version should I create the hotfix from? + +**PRs**: ask which PRs to cherry-pick: +> Which merged PRs should be included in the hotfix? (comma-separated numbers) + +### Step 2 — Validate Inputs + +**Validate the release tag exists:** + +```bash +git fetch --tags +git tag -l "azure-dev-cli_VERSION" +``` + +The tag format is `azure-dev-cli_X.Y.Z` (e.g., `azure-dev-cli_1.24.3`). +If not found, list recent release tags and ask the user to pick: + +```bash +git tag -l "azure-dev-cli_*" --sort=-version:refname | head -10 +``` + +**Validate each PR is merged:** + +```bash +gh pr view PR_NUMBER --repo Azure/azure-dev --json state,mergeCommit,mergedAt +``` + +For each PR: +- Must be `state: "MERGED"` +- Record `mergeCommit.oid` — this is what we cherry-pick +- If PR is not merged, warn and skip it + +**Determine merge strategy per PR:** + +```bash +gh pr view PR_NUMBER --repo Azure/azure-dev --json commits +``` + +- If `commits` count is 1 → squash merge (cherry-pick the merge commit directly) +- If `commits` count > 1 → could be merge commit (use `git cherry-pick -m 1 MERGE_SHA`) + +**Compute hotfix version:** +- Parse base version X.Y.Z → hotfix version X.Y.(Z+1) +- e.g., 1.24.3 → 1.24.4 +- Confirm with user: + > Hotfix version will be **1.24.4**. Is that correct? + +### Step 3 — Create Hotfix Branch + +```bash +# Ensure we're up to date +git fetch origin + +# Create branch from the release tag +git checkout -b hotfix/azd-HOTFIX_VERSION azure-dev-cli_BASE_VERSION +``` + +Example: `git checkout -b hotfix/azd-1.24.4 azure-dev-cli_1.24.3` + +### Step 4 — Cherry-Pick PRs + +For each PR, in the order specified by the user: + +```bash +# For squash merges (single commit) +git cherry-pick MERGE_COMMIT_SHA + +# For merge commits (multiple commits) +git cherry-pick -m 1 MERGE_COMMIT_SHA +``` + +**If cherry-pick succeeds**: log success and continue. + +**If cherry-pick has conflicts**: +1. Show the conflicting files: + ```bash + git diff --name-only --diff-filter=U + ``` +2. Show the conflict content for each file +3. Ask the user via `ask_user`: + > Cherry-pick of PR #NNNN has conflicts in these files: + > - path/to/file1.go + > - path/to/file2.go + > + > How should I proceed? + + Choices: + - **Show conflicts** — I'll display the diff and help resolve + - **Skip this PR** — abort this cherry-pick, continue with others + - **Abort hotfix** — cancel the entire hotfix + +4. If resolving: help the user edit the conflicting files, then: + ```bash + git add . + git cherry-pick --continue + ``` + +**After each cherry-pick**, verify the build still compiles: +```bash +cd cli/azd && go build ./... 2>&1 | head -20 +``` + +If build fails, warn the user and offer to continue or stop. + +### Step 5 — Bump Version + +Update version files per [references/version-files.md](references/version-files.md): + +{{ references/version-files.md }} + +### Step 6 — Update Changelog + +Add a hotfix section to `cli/azd/CHANGELOG.md`: + +```markdown +## X.Y.Z (YYYY-MM-DD) — Hotfix + +### Bugs Fixed + +- Description from PR #NNNN title [[#NNNN]](https://github.com/Azure/azure-dev/pull/NNNN) +- Description from PR #MMMM title [[#MMMM]](https://github.com/Azure/azure-dev/pull/MMMM) +``` + +- Use PR titles as entry descriptions +- Place the new section **above** the previous release section +- Use today's date +- Mark as "Hotfix" in the header + +Present the changelog entry to the user for review before writing: +> Here's the changelog entry I'll add. Look good? + +### Step 7 — Commit & Push + +```bash +git add -A +git commit -m "Release hotfix azd X.Y.Z + +Cherry-picked fixes: +- PR #NNNN: +- PR #MMMM: <title> + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" + +git push origin hotfix/azd-HOTFIX_VERSION +``` + +### Step 8 — Summary + +Print a summary with next steps: + +``` +✅ Hotfix branch created and pushed! + + Branch: hotfix/azd-1.24.4 + Compare: https://github.com/Azure/azure-dev/compare/azure-dev-cli_1.24.3...hotfix/azd-1.24.4 + Version: 1.24.4 + + Cherry-picked PRs: + ✅ #8001 — "Fix auth token refresh" + ✅ #8002 — "Handle nil pointer in deploy" + + Next steps: + 1. Review the branch: git log --oneline azure-dev-cli_1.24.3..hotfix/azd-1.24.4 + 2. Trigger the ADO release pipeline targeting branch: hotfix/azd-1.24.4 + 3. After release, tag the commit: git tag azure-dev-cli_1.24.4 + 4. Push the tag: git push origin azure-dev-cli_1.24.4 +``` + +**Do NOT** create a PR to main. The hotfix branch is released directly via the ADO pipeline. + +--- + +## Error Handling + +- Tag not found → list recent tags, let user pick +- PR not merged → warn, skip, continue with others +- Cherry-pick conflict → interactive resolution (Step 4) +- Build failure after cherry-pick → warn, offer to continue or abort +- Push rejected → suggest `git push --force-with-lease` if branch already exists (with user confirmation) +- `gh` not authenticated → stop, tell user to run `gh auth login` +- No write access → stop, explain requirement diff --git a/.github/skills/hotfix-release/references/version-files.md b/.github/skills/hotfix-release/references/version-files.md new file mode 100644 index 00000000000..8fd14bbfbb5 --- /dev/null +++ b/.github/skills/hotfix-release/references/version-files.md @@ -0,0 +1,66 @@ +# Version Files — Hotfix Update + +When creating a hotfix release, three files must be updated to the new version. + +## 1. `cli/version.txt` + +Contains the bare version string (no `v` prefix): + +``` +1.24.4 +``` + +Update: +```bash +echo "HOTFIX_VERSION" > cli/version.txt +``` + +## 2. `cli/azd/pkg/azdext/version.go` + +Contains the `Version` constant. Find and update the line: + +```go +const Version = "1.24.3" +``` + +Change to: + +```go +const Version = "1.24.4" +``` + +Use `sed` or direct file edit. Verify: +```bash +grep 'const Version' cli/azd/pkg/azdext/version.go +``` + +## 3. `cli/azd/CHANGELOG.md` + +Add a new release section at the top (below the `# Changelog` header and any `## Unreleased` section): + +```markdown +## 1.24.4 (2026-05-07) — Hotfix + +### Bugs Fixed + +- PR title here [[#NNNN]](https://github.com/Azure/azure-dev/pull/NNNN) +``` + +Place **above** the previous release entry (e.g., above `## 1.24.3`). + +## Validation + +After updating all three files, verify consistency: + +```bash +VERSION_TXT=$(cat cli/version.txt | tr -d '\n') +VERSION_GO=$(grep 'const Version' cli/azd/pkg/azdext/version.go | grep -oP '"[^"]*"' | tr -d '"') +echo "version.txt: $VERSION_TXT" +echo "version.go: $VERSION_GO" + +if [ "$VERSION_TXT" != "$VERSION_GO" ]; then + echo "❌ Version mismatch!" +else + echo "✅ Versions match: $VERSION_TXT" +fi +``` diff --git a/.github/skills/issue-cleanup/SKILL.md b/.github/skills/issue-cleanup/SKILL.md new file mode 100644 index 00000000000..f636880554f --- /dev/null +++ b/.github/skills/issue-cleanup/SKILL.md @@ -0,0 +1,224 @@ +--- +name: issue-cleanup +license: MIT +metadata: + version: "1.0" + # Bump major on breaking prompt/trigger changes; bump minor on new references or fix strategies. +description: >- + **WORKFLOW SKILL** — Scans the issue backlog for hygiene problems: missing labels, + missing milestones, customer-reported issues without triage, stale milestone assignments. + Reports findings grouped by severity and offers interactive fixes. + + INVOKES: gh CLI, GitHub MCP tools, ask_user. + + USE FOR: cleanup check, issue cleanup, backlog cleanup, check issue hygiene, + backlog scan, find unlabeled issues, find issues without milestones, customer-reported check, + triage check, orphan issues, stale milestone check. + + DO NOT USE FOR: sprint readiness (use sprint-check), changelog (use changelog-generation), + code quality (use azd-preflight), hotfix (use hotfix-release). +--- + +# issue-cleanup + +**WORKFLOW SKILL** — Scans the issue backlog for hygiene problems and offers interactive fixes. + +INVOKES: `gh` CLI, GitHub MCP tools, `ask_user`. + +## Prerequisites + +| Tool | Purpose | +|------|---------| +| `gh` | GitHub CLI — authenticated with repo access | + +## Preflight + +Verify `gh` is authenticated and has access to the repo: + +```bash +gh auth status +gh repo view Azure/azure-dev --json name -q .name +``` + +If project field checks are needed (e.g., sprint-check crossover), also verify `project` scope per sprint-check preflight. + +## Workflow + +### Step 1 — Determine Scope + +Parse the user's request: + +| User says | Scope | What to query | +|-----------|-------|---------------| +| "cleanup check" | **Full backlog** | All open issues | +| "cleanup check for May 2026" | **Milestone** | Issues in that milestone | +| "cleanup check for customer-reported" | **Label** | Issues with `customer-reported` label | +| "cleanup check for area/provisioning" | **Area** | Issues with that area label | +| "find issues without milestones" | **Specific** | Open issues with no milestone | +| "find unlabeled issues" | **Specific** | Open issues with no area/* label | + +If scope is unclear, ask via `ask_user`: +> What would you like me to scan? + +Choices: +- **Full backlog** (all open issues) +- **Customer-reported issues** (Recommended — highest priority) +- **Specific milestone** (I'll ask which one) +- **Specific area label** (I'll ask which one) + +### Step 2 — Query Issues + +Use `gh` CLI to fetch issues based on scope. + +**Full backlog:** +```bash +gh issue list --repo Azure/azure-dev --state open --limit 500 \ + --json number,title,labels,milestone,assignees,createdAt,updatedAt +``` + +**Customer-reported:** +```bash +gh issue list --repo Azure/azure-dev --state open --label "customer-reported" --limit 200 \ + --json number,title,labels,milestone,assignees,createdAt,updatedAt +``` + +**Specific milestone:** +```bash +gh issue list --repo Azure/azure-dev --state open --milestone "May 2026" --limit 200 \ + --json number,title,labels,milestone,assignees,createdAt,updatedAt +``` + +**No milestone:** +```bash +gh issue list --repo Azure/azure-dev --state open --milestone "" --limit 500 \ + --json number,title,labels,milestone,assignees,createdAt,updatedAt +``` + +For large result sets (500+), paginate and warn the user about volume. + +### Step 3 — Analyze Issues + +Apply hygiene rules from [references/hygiene-rules.md](references/hygiene-rules.md) (shared with sprint-check). + +**Note**: issue-cleanup uses the **full hygiene rules** but applies tier-appropriate checks. An issue in "Future" only needs labels + milestone, while one in "On Deck" needs everything. + +For each issue, produce a finding if ANY rule is violated. + +### Step 4 — Special: Customer-Reported Triage Check + +Customer-reported issues get special treatment: + +**🔴 CRITICAL — Customer-reported with no milestone:** +These are customer issues that landed but were never triaged into the planning process. +- Flag as critical +- Offer to set milestone to current month (treat as triage inbox) +- Offer to add `needs-triage` label if not present + +**🔴 CRITICAL — Customer-reported with no area label:** +These can't be routed to the right team member. +- Flag as critical +- Present area label list, let user pick + +**🟡 WARNING — Customer-reported in past milestone:** +Issue had a milestone assigned but the milestone has passed and issue is still open. +- The work was planned but not completed +- Offer to move to current milestone or On Deck + +**Flow for pulling customer-reported into current sprint:** +``` +Customer opens issue + → fabricbot: +customer-reported +question (instant) + → cleanup-check finds it: "no milestone, no area label" + → user confirms: set milestone to "May 2026" + → user picks: area/provisioning + → team sees it in current milestone during sprint planning + → team triages: keep in sprint, move to On Deck, or move to Backlog +``` + +### Step 5 — Report Findings + +Group by severity, then by finding type: + +``` +📋 Issue Cleanup Report — Customer-Reported Issues +═══════════════════════════════════════════════════ + +🔴 Critical (5 issues — need immediate attention): + + No milestone + no area label: + #7926 "Feedback after creating Go extension" (created Apr 25) + #7894 "Product exited" (created Apr 23) + + No milestone (has area label): + #7507 "Bug: Remote invoke for invocations-protocol..." (created Apr 5) + #7339 "Azure Extension Crashing" (created Mar 26, area/vscode) + #7244 "[Issue] AZD should support custom clouds" (created Mar 23) + +🟡 Warning (3 issues): + + Past milestone (still open): + #7564 "agent.yaml not in docs" (April 2026 milestone, due May 6) + + Missing area label: + #6612 "[Feature request] Add deployment targets" (On Deck) + +✅ Clean (12 issues) + +Summary: 5 critical, 3 warnings, 12 clean out of 20 issues +``` + +### Step 6 — Fix Interactively + +After the report, offer to fix: + +> Found 5 critical issues. Would you like me to fix them? + +Choices: +- **Fix all critical issues** (I'll ask for each field choice) +- **Fix one at a time** (I'll go through each issue) +- **Just the report** (no changes) + +For each issue being fixed: + +1. **Set milestone**: default to current month milestone, confirm via `ask_user` + ```bash + gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026" + ``` + +2. **Add area label**: present area label list, let user pick + ```bash + gh issue edit NUMBER --repo Azure/azure-dev --add-label "area/core-cli" + ``` + +3. **Add needs-triage**: if not already present + ```bash + gh issue edit NUMBER --repo Azure/azure-dev --add-label "needs-triage" + ``` + +4. **Assign**: offer to assign to the user or someone else + ```bash + gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "rajeshkamal5050" + ``` + +### Step 7 — Stale Milestone Check + +Find issues in past milestones that are still open: + +```bash +# Get all milestones with due dates +gh api repos/Azure/azure-dev/milestones --jq '.[] | select(.due_on != null and .open_issues > 0) | "\(.number) \(.title) \(.due_on) \(.open_issues)"' +``` + +For each past-due milestone with open issues: +- List the issues +- Offer to move them to current milestone, On Deck, or Backlog + +--- + +## Error Handling + +- `gh` not authenticated → stop, tell user to run `gh auth login` +- Too many issues (>500) → warn, suggest narrowing scope +- Rate limiting → wait and retry with backoff +- Issue edit fails → log error, continue with next issue +- Milestone not found → list available milestones, let user pick diff --git a/.github/skills/issue-cleanup/references/hygiene-rules.md b/.github/skills/issue-cleanup/references/hygiene-rules.md new file mode 100644 index 00000000000..befc3302d4a --- /dev/null +++ b/.github/skills/issue-cleanup/references/hygiene-rules.md @@ -0,0 +1,65 @@ +# Issue Hygiene Rules + +Shared validation rules used by both sprint-check and issue-cleanup skills. + +## Required Fields by Milestone Tier + +| Milestone tier | Must have | +|---|---| +| Future, Backlog, Backlog Candidates | labels (at least one `area/*`), milestone | +| On Deck, current/upcoming month | labels, milestone, Priority (project), Initiative (project), EPIC parent (if quarterly initiative) | +| Current Sprint | all above + assigned to someone | + +## Field Checks + +### 1. Labels +- **Rule**: every issue must have at least one `area/*` label +- **Check**: `labels` contains at least one label starting with `area/` +- **Fix**: present the area label list, let user pick +- **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required + +### 2. Milestone +- **Rule**: every issue in the current sprint should have the current month's milestone +- **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. +- **Check**: `milestone.title` matches current month +- **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026"` + +### 3. Priority (Project Field) +- **Rule**: issues in On Deck or current sprint must have Priority set +- **Check**: `fieldValueByName(name: "Priority")` is not null +- **Fix**: present Priority options, let user pick, then mutate via GraphQL + +### 4. Initiative (Project Field) +- **Rule**: issues in On Deck or current sprint must have Initiative set +- **Check**: `fieldValueByName(name: "Initiative")` is not null +- **Fix**: present Initiative options, let user pick, then mutate via GraphQL +- **Special**: 🛡️ Ongoing initiative allows direct issues (no EPIC parent needed) + +### 5. EPIC Parent +- **Rule**: if initiative is a quarterly initiative (not 🛡️ Ongoing), the issue should have an EPIC parent +- **Check**: `parent` field is not null (GitHub sub-issues) +- **Note**: this is a warning, not a blocker — some standalone items under quarterly initiatives are valid +- **Fix**: cannot auto-fix, suggest to user which EPICs exist under that initiative + +### 6. Assignment +- **Rule**: issues in the current sprint must be assigned to someone +- **Check**: `assignees` is not empty +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me"` or ask who + +## Customer-Reported Special Rules + +Customer-reported issues (`customer-reported` label) get elevated priority in checks: +- **No milestone** → 🔴 Critical (should be triaged into current milestone) +- **No area label** → 🔴 Critical (can't route to the right team) +- **Has `needs-triage`** → expected, not a problem (pending triage) +- **Has `needs-team-attention`** → expected after milestone is set +- **Past-due milestone** → 🟡 Warning (work planned but not completed) + +## Classification Order (for suggesting placement) + +When an issue has no milestone or initiative, suggest placement: +1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there +2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing +3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing +4. **None of the above** → Backlog, Backlog Candidates, or Future diff --git a/.github/skills/sprint-check/SKILL.md b/.github/skills/sprint-check/SKILL.md new file mode 100644 index 00000000000..e30ffc2344a --- /dev/null +++ b/.github/skills/sprint-check/SKILL.md @@ -0,0 +1,328 @@ +--- +name: sprint-check +license: MIT +metadata: + version: "1.0" + # Bump major on breaking prompt/trigger changes; bump minor on new references or fix strategies. +description: >- + **WORKFLOW SKILL** — Validates sprint readiness for issues and PRs. + Checks labels, milestones, project fields (Sprint, Priority, Initiative), + EPIC parents, and assignments. Can fix fields interactively with user confirmation. + + INVOKES: gh CLI, GitHub MCP tools, ask_user. + + USE FOR: sprint check, sprint-check, check sprint readiness, check my sprint, + sprint check for the team, sprint planning, mid-sprint check, sprint close check, + prepare issue for sprint, make issue sprint ready, pull issue into sprint. + + DO NOT USE FOR: backlog cleanup (use issue-cleanup), changelog (use changelog-generation), + code quality checks (use azd-preflight), release (use hotfix-release). +--- + +# sprint-check + +**WORKFLOW SKILL** — Validates sprint readiness for issues and PRs in the current sprint. + +INVOKES: `gh` CLI, GitHub MCP tools, `ask_user`. + +## Prerequisites + +| Tool | Purpose | +|------|---------| +| `gh` | GitHub CLI — authenticated with `project` scope | + +## Preflight + +Before any operation, verify access: + +```bash +gh auth status +``` + +**Check for `project` scope.** If missing, tell the user: +> Your `gh` token needs the `project` scope to read/write project fields. +> Run: `gh auth refresh --scopes project` + +Then verify project access: +```bash +gh api graphql -f query='{ + organization(login: "Azure") { + projectV2(number: 182) { title } + } +}' +``` + +If this fails, stop and report the error. + +## Workflow + +### Step 1 — Determine Scope + +Parse the user's request to determine scope: + +| User says | Scope | What to query | +|-----------|-------|---------------| +| "sprint-check" / "check my sprint" | **Personal** | Issues assigned to the current `gh` user in the current sprint | +| "sprint-check for the team" | **Team** | All issues in the current sprint | +| "sprint-check for @username" | **User** | Issues assigned to `@username` in the current sprint | +| "check issue #1234 for sprint" | **Single issue** | Validate one issue for sprint readiness | +| "pull #1234 into this sprint" | **Single issue + fix** | Validate + fix all fields | + +If ambiguous, ask via `ask_user`. + +### Step 2 — Get Current Sprint + +Query the current sprint iteration from Project #182: + +```bash +gh api graphql -f query='{ + organization(login: "Azure") { + projectV2(number: 182) { + field(name: "Sprint") { + ... on ProjectV2IterationField { + id + configuration { + iterations { id title startDate duration } + } + } + } + } + } +}' +``` + +Find the iteration where `today >= startDate && today < startDate + duration`. +Store the sprint `id`, `title`, and the field `id` for later mutations. + +### Step 3 — Query Sprint Issues + +**For team/personal scope** — query all project items in the current sprint: + +```bash +gh api graphql --paginate -f query=' +query($cursor: String) { + organization(login: "Azure") { + projectV2(number: 182) { + items(first: 100, after: $cursor) { + pageInfo { hasNextPage endCursor } + nodes { + content { + ... on Issue { + number + title + state + assignees(first: 10) { nodes { login } } + labels(first: 20) { nodes { name } } + milestone { title } + parent { number title } + } + } + fieldValueByName(name: "Sprint") { + ... on ProjectV2ItemFieldIterationValue { title iterationId } + } + fieldValueByName(name: "Priority") { + ... on ProjectV2ItemFieldSingleSelectValue { name optionId } + } + fieldValueByName(name: "Initiative") { + ... on ProjectV2ItemFieldSingleSelectValue { name optionId } + } + } + } + } + } +}' +``` + +Filter items where Sprint title matches the current sprint. +For personal scope, further filter by assignee matching the `gh` user. + +**For single-issue scope** — query the specific issue: + +```bash +gh api graphql -f query='{ + repository(owner: "Azure", name: "azure-dev") { + issue(number: ISSUE_NUMBER) { + number title state + assignees(first: 10) { nodes { login } } + labels(first: 20) { nodes { name } } + milestone { title number } + parent { number title } + projectItems(first: 10) { + nodes { + project { number } + id + fieldValueByName(name: "Sprint") { + ... on ProjectV2ItemFieldIterationValue { title iterationId } + } + fieldValueByName(name: "Priority") { + ... on ProjectV2ItemFieldSingleSelectValue { name optionId } + } + fieldValueByName(name: "Initiative") { + ... on ProjectV2ItemFieldSingleSelectValue { name optionId } + } + } + } + } + } +}' +``` + +### Step 4 — Validate Each Issue + +Apply the hygiene rules from [references/hygiene-rules.md](references/hygiene-rules.md). + +For each issue, check: + +{{ references/hygiene-rules.md }} + +### Step 5 — Report Findings + +Group findings by severity: + +**🔴 Critical** (blocks sprint work): +- No assignee +- No milestone +- No area/* label + +**🟡 Warning** (should fix): +- No Priority set (project field) +- No Initiative set (project field) +- Missing EPIC parent (if initiative is quarterly, not 🛡️ Ongoing) +- Milestone doesn't match current month +- Customer-reported without `needs-triage` removed (still pending triage) + +**🟢 Info**: +- Multiple area labels (fine, just note it) +- Has `needs-team-attention` (expected for customer-reported) + +Present as a table: + +``` +Sprint: May 2026 - Sprint 2 (May 5 – May 16) + +🔴 Critical (3 issues): + #7926 "Feedback after creating Go extension" — no assignee, no milestone, no area label + #7894 "Product exited" — no assignee, no milestone, no area label + #8033 "Create skills..." — no labels, no milestone + +🟡 Warning (2 issues): + #7248 "Handle DeploymentActive..." — no Priority, no Initiative + #7712 "Emergency hotfix release..." — no Initiative + +✅ Clean (4 issues): + #8026, #7680, #7317, #435 + +Summary: 3 critical, 2 warnings, 4 clean out of 9 issues +``` + +### Step 6 — Fix Interactively + +After reporting, offer to fix issues: + +> Found 3 issues with critical problems. Would you like me to fix them? + +For each fixable field, apply the rules: + +**Deterministic fixes** (apply with confirmation): +- **Add to project**: if issue not in project #182, add it first via `addProjectV2ItemById` +- **Set Sprint**: set to current sprint iteration +- **Set Milestone**: set to current month milestone +- **Assign**: assign to the user running the skill (or ask who) + +**Require user choice** (present options via `ask_user`): +- **Area label**: present the list of `area/*` labels, let user pick +- **Priority**: present Priority options from the project field +- **Initiative**: present Initiative options from the project field + +For project field mutations, see [references/project-mutations.md](references/project-mutations.md). + +For milestone/label fixes via `gh` CLI: + +```bash +# Set milestone +gh issue edit ISSUE_NUMBER --repo Azure/azure-dev --milestone "May 2026" + +# Add label +gh issue edit ISSUE_NUMBER --repo Azure/azure-dev --add-label "area/core-cli" + +# Assign +gh issue edit ISSUE_NUMBER --repo Azure/azure-dev --add-assignee "@me" +``` + +### Step 7 — Pull Issue Into Sprint (single-issue mode) + +When the user says "pull #1234 into this sprint" or "make #1234 sprint ready": + +1. Query the issue (Step 3, single-issue) +2. Validate (Step 4) +3. For each missing field, ask the user what value to set +4. Apply all fixes +5. Confirm: "Issue #1234 is now sprint-ready ✅" + +This is the "given an issue being pulled into this sprint, make it ready" flow. + +### Step 8 — Sprint Close / Rollover + +**Trigger**: This step activates when: +- The user says "sprint close check" or similar +- OR today is within 1 day of the current sprint's end date (auto-detected) + +**Workflow**: + +1. **Detect sprint end proximity** — from Step 2, calculate `sprint_end = startDate + duration`. If `today >= sprint_end - 1 day`, this step activates automatically after the normal report. + +2. **Identify the next sprint** — from the iterations list (Step 2), find the iteration whose `startDate` is immediately after the current sprint's end date. Store its `id` and `title`. + +3. **Classify open issues** — for each open issue still in the current sprint, present: + +``` +Sprint closing: May 04 - May 10 → Next: May 11 - May 17 + +Open issues to resolve: + #8033 — Create skills for weekly reports... → Move to May 11-17? [Y/n] + #8026 — RBAC propagation race causes 403... → Move to May 11-17? [Y/n] + #7712 — Emergency hotfix release process... → Move to May 11-17? [Y/n] +``` + +4. **Ask user for each issue** via `ask_user`: + - **Move to next sprint** (default) — update Sprint field to next iteration + - **Keep in current sprint** — leave as-is (will show as overdue) + - **Remove from sprint** — clear Sprint field (back to backlog) + +5. **Apply moves** — for issues the user confirms, update the Sprint iteration field: + +```bash +gh api graphql -f query=' +mutation { + updateProjectV2ItemFieldValue(input: { + projectId: "PROJECT_ID" + itemId: "ITEM_ID" + fieldId: "SPRINT_FIELD_ID" + value: { iterationId: "NEXT_SPRINT_ITERATION_ID" } + }) { + projectV2Item { id } + } +}' +``` + +See [references/project-mutations.md](references/project-mutations.md) for full mutation details. + +6. **Summary** — after all moves: + +``` +Sprint rollover complete: + ✅ 3 issues moved to May 11 - May 17 + ⏸️ 1 issue kept in May 04 - May 10 + 📋 0 issues removed from sprint +``` + +--- + +## Error Handling + +- `gh` not authenticated → stop, tell user to run `gh auth login` +- Project access denied → stop, explain `project` scope requirement +- Issue not in project → offer to add it via `addProjectV2ItemById` +- Sprint field not found → warn, skip sprint-related checks +- Rate limiting → wait and retry with backoff +- Issue is closed → skip, note in report diff --git a/.github/skills/sprint-check/references/hygiene-rules.md b/.github/skills/sprint-check/references/hygiene-rules.md new file mode 100644 index 00000000000..86cfbe03106 --- /dev/null +++ b/.github/skills/sprint-check/references/hygiene-rules.md @@ -0,0 +1,64 @@ +# Issue Hygiene Rules + +Shared validation rules for sprint-check and issue-cleanup skills. + +## Required Fields by Milestone Tier + +| Milestone tier | Must have | +|---|---| +| Future, Backlog, Backlog Candidates | labels (at least one `area/*`), milestone | +| On Deck, current/upcoming month | labels, milestone, Priority (project), Initiative (project), EPIC parent (if quarterly initiative) | +| Current Sprint | all above + assigned to someone | + +## Field Checks + +### 1. Labels +- **Rule**: every issue must have at least one `area/*` label +- **Check**: `labels.nodes` contains at least one label starting with `area/` +- **Fix**: present the area label list, let user pick +- **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required + +### 2. Milestone +- **Rule**: every issue in the current sprint should have the current month's milestone +- **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. +- **Check**: `milestone.title` matches current month +- **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) +- **Fix**: `gh issue edit NUMBER --milestone "May 2026"` + +### 3. Priority (Project Field) +- **Rule**: issues in On Deck or current sprint must have Priority set +- **Check**: `fieldValueByName(name: "Priority")` is not null +- **Fix**: present Priority options, let user pick, then mutate via GraphQL + +### 4. Initiative (Project Field) +- **Rule**: issues in On Deck or current sprint must have Initiative set +- **Check**: `fieldValueByName(name: "Initiative")` is not null +- **Fix**: present Initiative options, let user pick, then mutate via GraphQL +- **Special**: 🛡️ Ongoing initiative allows direct issues (no EPIC parent needed) + +### 5. EPIC Parent +- **Rule**: if initiative is a quarterly initiative (not 🛡️ Ongoing), the issue should have an EPIC parent +- **Check**: `parent` field is not null (GitHub sub-issues) +- **Note**: this is a warning, not a blocker — some standalone items under quarterly initiatives are valid +- **Fix**: cannot auto-fix, suggest to user which EPICs exist under that initiative + +### 6. Assignment +- **Rule**: issues in the current sprint must be assigned to someone +- **Check**: `assignees.nodes` is not empty +- **Fix**: `gh issue edit NUMBER --add-assignee "@me"` or ask who to assign + +## Customer-Reported Special Rules + +Customer-reported issues (`customer-reported` label) get elevated priority: +- **No milestone** → 🔴 Critical (should be triaged into current milestone) +- **No area label** → 🔴 Critical (can't route to the right team) +- **Has `needs-triage`** → expected, not a problem (pending triage) +- **Has `needs-team-attention`** → expected after milestone is set + +## Classification Order (for suggesting placement) + +When an issue has no milestone or initiative: +1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there +2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing +3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing +4. **None of the above** → Backlog, Backlog Candidates, or Future diff --git a/.github/skills/sprint-check/references/project-mutations.md b/.github/skills/sprint-check/references/project-mutations.md new file mode 100644 index 00000000000..0e6e813e35a --- /dev/null +++ b/.github/skills/sprint-check/references/project-mutations.md @@ -0,0 +1,138 @@ +# Project V2 GraphQL Mutations + +Reference for reading and writing GitHub Projects V2 fields. + +## Project Info + +- **Organization**: Azure +- **Project number**: 182 +- **Key fields**: Sprint (iteration), Priority (single select), Initiative (single select) + +## Prerequisites + +The `gh` CLI must be authenticated with `project` scope: +```bash +gh auth refresh --scopes project +``` + +## Reading Field Options + +Before setting a field value, you need the field ID and option IDs. + +### Get all field IDs and options + +```bash +gh api graphql -f query='{ + organization(login: "Azure") { + projectV2(number: 182) { + id + field(name: "Priority") { + ... on ProjectV2FieldCommon { id name } + ... on ProjectV2SingleSelectField { + id name + options { id name } + } + } + } + } +}' +``` + +Repeat for "Initiative" and "Sprint" fields. + +### Get Sprint iterations + +```bash +gh api graphql -f query='{ + organization(login: "Azure") { + projectV2(number: 182) { + field(name: "Sprint") { + ... on ProjectV2IterationField { + id + configuration { + iterations { id title startDate duration } + completedIterations { id title startDate duration } + } + } + } + } + } +}' +``` + +## Adding an Issue to the Project + +Before setting fields, the issue must be a project item. + +```bash +# Get the issue's node ID +gh api graphql -f query='{ + repository(owner: "Azure", name: "azure-dev") { + issue(number: ISSUE_NUMBER) { id } + } +}' +``` + +```bash +# Add to project (returns the project item ID) +gh api graphql -f query=' +mutation { + addProjectV2ItemById(input: { + projectId: "PROJECT_ID" + contentId: "ISSUE_NODE_ID" + }) { + item { id } + } +}' +``` + +Store the returned `item.id` — you need it for field mutations. + +## Setting Field Values + +### Set Priority (single select) + +```bash +gh api graphql -f query=' +mutation { + updateProjectV2ItemFieldValue(input: { + projectId: "PROJECT_ID" + itemId: "ITEM_ID" + fieldId: "PRIORITY_FIELD_ID" + value: { singleSelectOptionId: "OPTION_ID" } + }) { + projectV2Item { id } + } +}' +``` + +### Set Initiative (single select) + +Same mutation shape as Priority, with Initiative field ID and option ID. + +### Set Sprint (iteration) + +```bash +gh api graphql -f query=' +mutation { + updateProjectV2ItemFieldValue(input: { + projectId: "PROJECT_ID" + itemId: "ITEM_ID" + fieldId: "SPRINT_FIELD_ID" + value: { iterationId: "ITERATION_ID" } + }) { + projectV2Item { id } + } +}' +``` + +## Common Workflow + +1. **Get project ID**: from the initial project query +2. **Get field IDs**: Priority field ID, Initiative field ID, Sprint field ID +3. **Get option IDs**: for Priority → list options, for Initiative → list options, for Sprint → list iterations +4. **Check if issue is in project**: query issue's `projectItems` +5. **If not in project**: add via `addProjectV2ItemById` +6. **Set fields**: use `updateProjectV2ItemFieldValue` for each field + +Cache the project ID and field IDs across operations — they don't change within a session. diff --git a/.vscode/cspell.misc.yaml b/.vscode/cspell.misc.yaml index 043e51e8def..0e07a8ed1e7 100644 --- a/.vscode/cspell.misc.yaml +++ b/.vscode/cspell.misc.yaml @@ -103,3 +103,13 @@ overrides: - Buildpacks - containerapp - staticwebapp + - filename: .github/skills/hotfix-release/**/*.md + words: + - azdext + - filename: .github/skills/issue-cleanup/**/*.md + words: + - engsys + - fabricbot + - filename: .github/skills/sprint-check/**/*.md + words: + - engsys From c11b034ddc72e3b16119b26cd1553ed0a90a1a27 Mon Sep 17 00:00:00 2001 From: Rajesh Kamal <rajeshkamal@microsoft.com> Date: Fri, 15 May 2026 11:48:34 -0700 Subject: [PATCH 2/4] Improve skills: ADO pipeline guidance, review fixes, sprint rollover hotfix-release: - Add Triggering the Release section with ADO pipeline link and steps - Add Post-Release section (changelog merge-back, no version file merge) - Fix tags guidance: pipeline creates tags, not manual - Add Go as optional prerequisite (build verification) - Remove changelog from version-files.md (avoid Step 5/6 overlap) - Fix grep -oP to sed for macOS compatibility sprint-check: - Add Step 8: Sprint Close / Rollover with bulk move option - Fix --paginate to manual cursor pagination (tested, doesn't work) - Sync hygiene-rules.md with issue-cleanup (was drifting) issue-cleanup: - Fix hardcoded assignee example to @me - Fix --milestone "" to --search "no:milestone" Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/hotfix-release/SKILL.md | 32 +++++++++++++++++-- .../references/version-files.md | 20 ++---------- .github/skills/issue-cleanup/SKILL.md | 4 +-- .github/skills/sprint-check/SKILL.md | 25 +++++++++++---- .../sprint-check/references/hygiene-rules.md | 15 +++++---- 5 files changed, 60 insertions(+), 36 deletions(-) diff --git a/.github/skills/hotfix-release/SKILL.md b/.github/skills/hotfix-release/SKILL.md index 3d244be9412..0699162ced7 100644 --- a/.github/skills/hotfix-release/SKILL.md +++ b/.github/skills/hotfix-release/SKILL.md @@ -31,6 +31,7 @@ INVOKES: `git` CLI, `gh` CLI, GitHub MCP tools, `ask_user`. |------|---------| | `git` | Git CLI — push access to Azure/azure-dev | | `gh` | GitHub CLI — authenticated with repo access | +| `go` | Go toolchain — to verify build after cherry-pick (optional) | ## Preflight @@ -229,13 +230,38 @@ Print a summary with next steps: Next steps: 1. Review the branch: git log --oneline azure-dev-cli_1.24.3..hotfix/azd-1.24.4 - 2. Trigger the ADO release pipeline targeting branch: hotfix/azd-1.24.4 - 3. After release, tag the commit: git tag azure-dev-cli_1.24.4 - 4. Push the tag: git push origin azure-dev-cli_1.24.4 + 2. Trigger the release pipeline (see "Triggering the Release" below) + 3. After release, add the hotfix changelog entry to main's CHANGELOG.md ``` **Do NOT** create a PR to main. The hotfix branch is released directly via the ADO pipeline. +**Do NOT** create tags manually. The release pipeline creates both `azure-dev-cli_X.Y.Z` and `cli/azd/vX.Y.Z` tags automatically. + +--- + +## Triggering the Release + +Open the [azure-dev - cli](https://dev.azure.com/azure-sdk/internal/_build?definitionId=4643) pipeline in ADO: + +1. Click **Run pipeline** +2. Select the `hotfix/*` branch (e.g., `hotfix/azd-1.24.4`) +3. ✅ Check **"Check to run a release build"** +4. Leave Azure Record Mode as **live** (default) +5. Click **Run** + +The pipeline builds, signs, and publishes the release — including GitHub release, tags, storage upload, Chocolatey, WinGet, and Homebrew. + +> **Tip**: Set the pipeline variable `Skip.IncrementVersion = true` before running. The default increment job creates a version-bump PR targeting the source branch, which is unnecessary for a hotfix branch. + +--- + +## Post-Release + +1. Add the hotfix changelog section (e.g., `## 1.24.4`) to `main`'s CHANGELOG.md so the release history is complete +2. Do **not** merge version file changes back — main's version is already ahead +3. The hotfix branch can be kept for reference or deleted per team preference + --- ## Error Handling diff --git a/.github/skills/hotfix-release/references/version-files.md b/.github/skills/hotfix-release/references/version-files.md index 8fd14bbfbb5..abc18303b91 100644 --- a/.github/skills/hotfix-release/references/version-files.md +++ b/.github/skills/hotfix-release/references/version-files.md @@ -1,6 +1,6 @@ # Version Files — Hotfix Update -When creating a hotfix release, three files must be updated to the new version. +When creating a hotfix release, two version files must be updated. ## 1. `cli/version.txt` @@ -34,27 +34,13 @@ Use `sed` or direct file edit. Verify: grep 'const Version' cli/azd/pkg/azdext/version.go ``` -## 3. `cli/azd/CHANGELOG.md` - -Add a new release section at the top (below the `# Changelog` header and any `## Unreleased` section): - -```markdown -## 1.24.4 (2026-05-07) — Hotfix - -### Bugs Fixed - -- PR title here [[#NNNN]](https://github.com/Azure/azure-dev/pull/NNNN) -``` - -Place **above** the previous release entry (e.g., above `## 1.24.3`). - ## Validation -After updating all three files, verify consistency: +After updating both files, verify consistency: ```bash VERSION_TXT=$(cat cli/version.txt | tr -d '\n') -VERSION_GO=$(grep 'const Version' cli/azd/pkg/azdext/version.go | grep -oP '"[^"]*"' | tr -d '"') +VERSION_GO=$(grep 'const Version' cli/azd/pkg/azdext/version.go | sed 's/.*"\(.*\)".*/\1/') echo "version.txt: $VERSION_TXT" echo "version.go: $VERSION_GO" diff --git a/.github/skills/issue-cleanup/SKILL.md b/.github/skills/issue-cleanup/SKILL.md index f636880554f..9c22474cdfa 100644 --- a/.github/skills/issue-cleanup/SKILL.md +++ b/.github/skills/issue-cleanup/SKILL.md @@ -90,7 +90,7 @@ gh issue list --repo Azure/azure-dev --state open --milestone "May 2026" --limit **No milestone:** ```bash -gh issue list --repo Azure/azure-dev --state open --milestone "" --limit 500 \ +gh issue list --repo Azure/azure-dev --state open --search "no:milestone" --limit 500 \ --json number,title,labels,milestone,assignees,createdAt,updatedAt ``` @@ -197,7 +197,7 @@ For each issue being fixed: 4. **Assign**: offer to assign to the user or someone else ```bash - gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "rajeshkamal5050" + gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me" ``` ### Step 7 — Stale Milestone Check diff --git a/.github/skills/sprint-check/SKILL.md b/.github/skills/sprint-check/SKILL.md index e30ffc2344a..162092ecd79 100644 --- a/.github/skills/sprint-check/SKILL.md +++ b/.github/skills/sprint-check/SKILL.md @@ -96,10 +96,12 @@ Store the sprint `id`, `title`, and the field `id` for later mutations. ### Step 3 — Query Sprint Issues -**For team/personal scope** — query all project items in the current sprint: +**For team/personal scope** — query all project items in the current sprint. + +**Note**: `--paginate` does not work reliably for this query. Use manual cursor-based pagination — fetch 100 items at a time, pass the `endCursor` to the next query until `hasNextPage` is false. ```bash -gh api graphql --paginate -f query=' +gh api graphql -f query=' query($cursor: String) { organization(login: "Azure") { projectV2(number: 182) { @@ -278,13 +280,22 @@ This is the "given an issue being pulled into this sprint, make it ready" flow. ``` Sprint closing: May 04 - May 10 → Next: May 11 - May 17 -Open issues to resolve: - #8033 — Create skills for weekly reports... → Move to May 11-17? [Y/n] - #8026 — RBAC propagation race causes 403... → Move to May 11-17? [Y/n] - #7712 — Emergency hotfix release process... → Move to May 11-17? [Y/n] +Open issues to resolve (5 issues): + #8033 — Create skills for weekly reports... + #8026 — RBAC propagation race causes 403... + #7712 — Emergency hotfix release process... + #7680 — Add extension telemetry... + #7317 — Improve error messages... ``` -4. **Ask user for each issue** via `ask_user`: +4. **Ask user how to handle** via `ask_user`: + +Choices: + - **Move all to next sprint** (Recommended) — bulk move everything + - **Decide per issue** — go through each one individually + - **Skip** — leave everything as-is + +If "Decide per issue", for each issue ask: - **Move to next sprint** (default) — update Sprint field to next iteration - **Keep in current sprint** — leave as-is (will show as overdue) - **Remove from sprint** — clear Sprint field (back to backlog) diff --git a/.github/skills/sprint-check/references/hygiene-rules.md b/.github/skills/sprint-check/references/hygiene-rules.md index 86cfbe03106..befc3302d4a 100644 --- a/.github/skills/sprint-check/references/hygiene-rules.md +++ b/.github/skills/sprint-check/references/hygiene-rules.md @@ -1,6 +1,6 @@ # Issue Hygiene Rules -Shared validation rules for sprint-check and issue-cleanup skills. +Shared validation rules used by both sprint-check and issue-cleanup skills. ## Required Fields by Milestone Tier @@ -14,7 +14,7 @@ Shared validation rules for sprint-check and issue-cleanup skills. ### 1. Labels - **Rule**: every issue must have at least one `area/*` label -- **Check**: `labels.nodes` contains at least one label starting with `area/` +- **Check**: `labels` contains at least one label starting with `area/` - **Fix**: present the area label list, let user pick - **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required @@ -23,7 +23,7 @@ Shared validation rules for sprint-check and issue-cleanup skills. - **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. - **Check**: `milestone.title` matches current month - **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) -- **Fix**: `gh issue edit NUMBER --milestone "May 2026"` +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026"` ### 3. Priority (Project Field) - **Rule**: issues in On Deck or current sprint must have Priority set @@ -44,20 +44,21 @@ Shared validation rules for sprint-check and issue-cleanup skills. ### 6. Assignment - **Rule**: issues in the current sprint must be assigned to someone -- **Check**: `assignees.nodes` is not empty -- **Fix**: `gh issue edit NUMBER --add-assignee "@me"` or ask who to assign +- **Check**: `assignees` is not empty +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me"` or ask who ## Customer-Reported Special Rules -Customer-reported issues (`customer-reported` label) get elevated priority: +Customer-reported issues (`customer-reported` label) get elevated priority in checks: - **No milestone** → 🔴 Critical (should be triaged into current milestone) - **No area label** → 🔴 Critical (can't route to the right team) - **Has `needs-triage`** → expected, not a problem (pending triage) - **Has `needs-team-attention`** → expected after milestone is set +- **Past-due milestone** → 🟡 Warning (work planned but not completed) ## Classification Order (for suggesting placement) -When an issue has no milestone or initiative: +When an issue has no milestone or initiative, suggest placement: 1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there 2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing 3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing From 7d9b3f3baf848dcfeaef930924bc2a0db9b9224e Mon Sep 17 00:00:00 2001 From: Rajesh Kamal <rajeshkamal@microsoft.com> Date: Fri, 15 May 2026 12:16:43 -0700 Subject: [PATCH 3/4] Address Copilot review: fix merge detection, placeholders, query limits, description Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/hotfix-release/SKILL.md | 13 ++++++++----- .github/skills/sprint-check/SKILL.md | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/skills/hotfix-release/SKILL.md b/.github/skills/hotfix-release/SKILL.md index 0699162ced7..21fb57d4dbd 100644 --- a/.github/skills/hotfix-release/SKILL.md +++ b/.github/skills/hotfix-release/SKILL.md @@ -78,7 +78,7 @@ If either is missing, ask via `ask_user`. ```bash git fetch --tags -git tag -l "azure-dev-cli_VERSION" +git tag -l "azure-dev-cli_${BASE_VERSION}" ``` The tag format is `azure-dev-cli_X.Y.Z` (e.g., `azure-dev-cli_1.24.3`). @@ -99,14 +99,17 @@ For each PR: - Record `mergeCommit.oid` — this is what we cherry-pick - If PR is not merged, warn and skip it -**Determine merge strategy per PR:** +**Determine if merge commit:** + +After fetching, check the parent count of the merge commit SHA: ```bash -gh pr view PR_NUMBER --repo Azure/azure-dev --json commits +git fetch origin MERGE_SHA +git show --no-patch --pretty=%P MERGE_SHA ``` -- If `commits` count is 1 → squash merge (cherry-pick the merge commit directly) -- If `commits` count > 1 → could be merge commit (use `git cherry-pick -m 1 MERGE_SHA`) +- If 1 parent → squash merge (cherry-pick directly) +- If 2+ parents → merge commit (use `git cherry-pick -m 1 MERGE_SHA`) **Compute hotfix version:** - Parse base version X.Y.Z → hotfix version X.Y.(Z+1) diff --git a/.github/skills/sprint-check/SKILL.md b/.github/skills/sprint-check/SKILL.md index 162092ecd79..f75cdd1f342 100644 --- a/.github/skills/sprint-check/SKILL.md +++ b/.github/skills/sprint-check/SKILL.md @@ -5,7 +5,7 @@ metadata: version: "1.0" # Bump major on breaking prompt/trigger changes; bump minor on new references or fix strategies. description: >- - **WORKFLOW SKILL** — Validates sprint readiness for issues and PRs. + **WORKFLOW SKILL** — Validates sprint readiness for issues. Checks labels, milestones, project fields (Sprint, Priority, Initiative), EPIC parents, and assignments. Can fix fields interactively with user confirmation. @@ -149,7 +149,7 @@ gh api graphql -f query='{ labels(first: 20) { nodes { name } } milestone { title number } parent { number title } - projectItems(first: 10) { + projectItems(first: 100) { nodes { project { number } id From b7b9636b09d86e07af98c50cf02d97d19a756e0c Mon Sep 17 00:00:00 2001 From: Rajesh Kamal <rajeshkamal@microsoft.com> Date: Wed, 20 May 2026 08:41:07 -0700 Subject: [PATCH 4/4] fix: address review feedback on engsys skills - Fix sprint-check heading to say 'issues' not 'issues and PRs' - Deduplicate hygiene-rules.md into _shared/ with symlinks - Hotfix-release: prefer git pull --rebase before force-push - Hotfix-release: validate PRs were merged into main, not feature branches Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/_shared/hygiene-rules.md | 65 ++++++++++++++++++ .github/skills/hotfix-release/SKILL.md | 7 +- .../issue-cleanup/references/hygiene-rules.md | 66 +------------------ .github/skills/sprint-check/SKILL.md | 2 +- .../sprint-check/references/hygiene-rules.md | 66 +------------------ 5 files changed, 73 insertions(+), 133 deletions(-) create mode 100644 .github/skills/_shared/hygiene-rules.md mode change 100644 => 120000 .github/skills/issue-cleanup/references/hygiene-rules.md mode change 100644 => 120000 .github/skills/sprint-check/references/hygiene-rules.md diff --git a/.github/skills/_shared/hygiene-rules.md b/.github/skills/_shared/hygiene-rules.md new file mode 100644 index 00000000000..befc3302d4a --- /dev/null +++ b/.github/skills/_shared/hygiene-rules.md @@ -0,0 +1,65 @@ +# Issue Hygiene Rules + +Shared validation rules used by both sprint-check and issue-cleanup skills. + +## Required Fields by Milestone Tier + +| Milestone tier | Must have | +|---|---| +| Future, Backlog, Backlog Candidates | labels (at least one `area/*`), milestone | +| On Deck, current/upcoming month | labels, milestone, Priority (project), Initiative (project), EPIC parent (if quarterly initiative) | +| Current Sprint | all above + assigned to someone | + +## Field Checks + +### 1. Labels +- **Rule**: every issue must have at least one `area/*` label +- **Check**: `labels` contains at least one label starting with `area/` +- **Fix**: present the area label list, let user pick +- **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required + +### 2. Milestone +- **Rule**: every issue in the current sprint should have the current month's milestone +- **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. +- **Check**: `milestone.title` matches current month +- **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026"` + +### 3. Priority (Project Field) +- **Rule**: issues in On Deck or current sprint must have Priority set +- **Check**: `fieldValueByName(name: "Priority")` is not null +- **Fix**: present Priority options, let user pick, then mutate via GraphQL + +### 4. Initiative (Project Field) +- **Rule**: issues in On Deck or current sprint must have Initiative set +- **Check**: `fieldValueByName(name: "Initiative")` is not null +- **Fix**: present Initiative options, let user pick, then mutate via GraphQL +- **Special**: 🛡️ Ongoing initiative allows direct issues (no EPIC parent needed) + +### 5. EPIC Parent +- **Rule**: if initiative is a quarterly initiative (not 🛡️ Ongoing), the issue should have an EPIC parent +- **Check**: `parent` field is not null (GitHub sub-issues) +- **Note**: this is a warning, not a blocker — some standalone items under quarterly initiatives are valid +- **Fix**: cannot auto-fix, suggest to user which EPICs exist under that initiative + +### 6. Assignment +- **Rule**: issues in the current sprint must be assigned to someone +- **Check**: `assignees` is not empty +- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me"` or ask who + +## Customer-Reported Special Rules + +Customer-reported issues (`customer-reported` label) get elevated priority in checks: +- **No milestone** → 🔴 Critical (should be triaged into current milestone) +- **No area label** → 🔴 Critical (can't route to the right team) +- **Has `needs-triage`** → expected, not a problem (pending triage) +- **Has `needs-team-attention`** → expected after milestone is set +- **Past-due milestone** → 🟡 Warning (work planned but not completed) + +## Classification Order (for suggesting placement) + +When an issue has no milestone or initiative, suggest placement: +1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there +2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing +3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing +4. **None of the above** → Backlog, Backlog Candidates, or Future diff --git a/.github/skills/hotfix-release/SKILL.md b/.github/skills/hotfix-release/SKILL.md index 21fb57d4dbd..fe65a126577 100644 --- a/.github/skills/hotfix-release/SKILL.md +++ b/.github/skills/hotfix-release/SKILL.md @@ -91,13 +91,16 @@ git tag -l "azure-dev-cli_*" --sort=-version:refname | head -10 **Validate each PR is merged:** ```bash -gh pr view PR_NUMBER --repo Azure/azure-dev --json state,mergeCommit,mergedAt +gh pr view PR_NUMBER --repo Azure/azure-dev --json state,mergeCommit,mergedAt,baseRefName ``` For each PR: - Must be `state: "MERGED"` +- Must have `baseRefName: "main"` — reject PRs merged into feature branches (they may contain unrelated changes) - Record `mergeCommit.oid` — this is what we cherry-pick - If PR is not merged, warn and skip it +- If PR was merged into a non-main branch, warn: + > PR #NNNN was merged into `BRANCH`, not `main`. Cherry-picking its merge commit may include unrelated changes. Skip this PR? **Determine if merge commit:** @@ -273,6 +276,6 @@ The pipeline builds, signs, and publishes the release — including GitHub relea - PR not merged → warn, skip, continue with others - Cherry-pick conflict → interactive resolution (Step 4) - Build failure after cherry-pick → warn, offer to continue or abort -- Push rejected → suggest `git push --force-with-lease` if branch already exists (with user confirmation) +- Push rejected → first try `git pull --rebase origin BRANCH` to incorporate any remote commits, then retry `git push`. Only suggest `git push --force-with-lease` as a last resort if rebase also fails, and warn the user that force-pushing may overwrite others' work on the branch - `gh` not authenticated → stop, tell user to run `gh auth login` - No write access → stop, explain requirement diff --git a/.github/skills/issue-cleanup/references/hygiene-rules.md b/.github/skills/issue-cleanup/references/hygiene-rules.md deleted file mode 100644 index befc3302d4a..00000000000 --- a/.github/skills/issue-cleanup/references/hygiene-rules.md +++ /dev/null @@ -1,65 +0,0 @@ -# Issue Hygiene Rules - -Shared validation rules used by both sprint-check and issue-cleanup skills. - -## Required Fields by Milestone Tier - -| Milestone tier | Must have | -|---|---| -| Future, Backlog, Backlog Candidates | labels (at least one `area/*`), milestone | -| On Deck, current/upcoming month | labels, milestone, Priority (project), Initiative (project), EPIC parent (if quarterly initiative) | -| Current Sprint | all above + assigned to someone | - -## Field Checks - -### 1. Labels -- **Rule**: every issue must have at least one `area/*` label -- **Check**: `labels` contains at least one label starting with `area/` -- **Fix**: present the area label list, let user pick -- **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required - -### 2. Milestone -- **Rule**: every issue in the current sprint should have the current month's milestone -- **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. -- **Check**: `milestone.title` matches current month -- **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) -- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026"` - -### 3. Priority (Project Field) -- **Rule**: issues in On Deck or current sprint must have Priority set -- **Check**: `fieldValueByName(name: "Priority")` is not null -- **Fix**: present Priority options, let user pick, then mutate via GraphQL - -### 4. Initiative (Project Field) -- **Rule**: issues in On Deck or current sprint must have Initiative set -- **Check**: `fieldValueByName(name: "Initiative")` is not null -- **Fix**: present Initiative options, let user pick, then mutate via GraphQL -- **Special**: 🛡️ Ongoing initiative allows direct issues (no EPIC parent needed) - -### 5. EPIC Parent -- **Rule**: if initiative is a quarterly initiative (not 🛡️ Ongoing), the issue should have an EPIC parent -- **Check**: `parent` field is not null (GitHub sub-issues) -- **Note**: this is a warning, not a blocker — some standalone items under quarterly initiatives are valid -- **Fix**: cannot auto-fix, suggest to user which EPICs exist under that initiative - -### 6. Assignment -- **Rule**: issues in the current sprint must be assigned to someone -- **Check**: `assignees` is not empty -- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me"` or ask who - -## Customer-Reported Special Rules - -Customer-reported issues (`customer-reported` label) get elevated priority in checks: -- **No milestone** → 🔴 Critical (should be triaged into current milestone) -- **No area label** → 🔴 Critical (can't route to the right team) -- **Has `needs-triage`** → expected, not a problem (pending triage) -- **Has `needs-team-attention`** → expected after milestone is set -- **Past-due milestone** → 🟡 Warning (work planned but not completed) - -## Classification Order (for suggesting placement) - -When an issue has no milestone or initiative, suggest placement: -1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there -2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing -3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing -4. **None of the above** → Backlog, Backlog Candidates, or Future diff --git a/.github/skills/issue-cleanup/references/hygiene-rules.md b/.github/skills/issue-cleanup/references/hygiene-rules.md new file mode 120000 index 00000000000..b43e4060b33 --- /dev/null +++ b/.github/skills/issue-cleanup/references/hygiene-rules.md @@ -0,0 +1 @@ +../../_shared/hygiene-rules.md \ No newline at end of file diff --git a/.github/skills/sprint-check/SKILL.md b/.github/skills/sprint-check/SKILL.md index f75cdd1f342..dfd951ba632 100644 --- a/.github/skills/sprint-check/SKILL.md +++ b/.github/skills/sprint-check/SKILL.md @@ -21,7 +21,7 @@ description: >- # sprint-check -**WORKFLOW SKILL** — Validates sprint readiness for issues and PRs in the current sprint. +**WORKFLOW SKILL** — Validates sprint readiness for issues in the current sprint. INVOKES: `gh` CLI, GitHub MCP tools, `ask_user`. diff --git a/.github/skills/sprint-check/references/hygiene-rules.md b/.github/skills/sprint-check/references/hygiene-rules.md deleted file mode 100644 index befc3302d4a..00000000000 --- a/.github/skills/sprint-check/references/hygiene-rules.md +++ /dev/null @@ -1,65 +0,0 @@ -# Issue Hygiene Rules - -Shared validation rules used by both sprint-check and issue-cleanup skills. - -## Required Fields by Milestone Tier - -| Milestone tier | Must have | -|---|---| -| Future, Backlog, Backlog Candidates | labels (at least one `area/*`), milestone | -| On Deck, current/upcoming month | labels, milestone, Priority (project), Initiative (project), EPIC parent (if quarterly initiative) | -| Current Sprint | all above + assigned to someone | - -## Field Checks - -### 1. Labels -- **Rule**: every issue must have at least one `area/*` label -- **Check**: `labels` contains at least one label starting with `area/` -- **Fix**: present the area label list, let user pick -- **Note**: type labels (`bug`, `enhancement`, `feature`) are nice-to-have, not required - -### 2. Milestone -- **Rule**: every issue in the current sprint should have the current month's milestone -- **Current month milestone**: derive from today's date → "May 2026", "June 2026", etc. -- **Check**: `milestone.title` matches current month -- **Allowed exceptions**: On Deck, Backlog (for items being tracked but not committed this month) -- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --milestone "May 2026"` - -### 3. Priority (Project Field) -- **Rule**: issues in On Deck or current sprint must have Priority set -- **Check**: `fieldValueByName(name: "Priority")` is not null -- **Fix**: present Priority options, let user pick, then mutate via GraphQL - -### 4. Initiative (Project Field) -- **Rule**: issues in On Deck or current sprint must have Initiative set -- **Check**: `fieldValueByName(name: "Initiative")` is not null -- **Fix**: present Initiative options, let user pick, then mutate via GraphQL -- **Special**: 🛡️ Ongoing initiative allows direct issues (no EPIC parent needed) - -### 5. EPIC Parent -- **Rule**: if initiative is a quarterly initiative (not 🛡️ Ongoing), the issue should have an EPIC parent -- **Check**: `parent` field is not null (GitHub sub-issues) -- **Note**: this is a warning, not a blocker — some standalone items under quarterly initiatives are valid -- **Fix**: cannot auto-fix, suggest to user which EPICs exist under that initiative - -### 6. Assignment -- **Rule**: issues in the current sprint must be assigned to someone -- **Check**: `assignees` is not empty -- **Fix**: `gh issue edit NUMBER --repo Azure/azure-dev --add-assignee "@me"` or ask who - -## Customer-Reported Special Rules - -Customer-reported issues (`customer-reported` label) get elevated priority in checks: -- **No milestone** → 🔴 Critical (should be triaged into current milestone) -- **No area label** → 🔴 Critical (can't route to the right team) -- **Has `needs-triage`** → expected, not a problem (pending triage) -- **Has `needs-team-attention`** → expected after milestone is set -- **Past-due milestone** → 🟡 Warning (work planned but not completed) - -## Classification Order (for suggesting placement) - -When an issue has no milestone or initiative, suggest placement: -1. **Planned priorities** — fits a current quarter initiative/EPIC? → parent it there -2. **Customer-reported / regression** → current milestone + 🛡️ Ongoing -3. **One-off items** (engsys, pipeline, test) → current milestone + 🛡️ Ongoing -4. **None of the above** → Backlog, Backlog Candidates, or Future diff --git a/.github/skills/sprint-check/references/hygiene-rules.md b/.github/skills/sprint-check/references/hygiene-rules.md new file mode 120000 index 00000000000..b43e4060b33 --- /dev/null +++ b/.github/skills/sprint-check/references/hygiene-rules.md @@ -0,0 +1 @@ +../../_shared/hygiene-rules.md \ No newline at end of file