Skip to content

Commit 63761c7

Browse files
CopilotPureWeen
andauthored
Add issue-triage skill from PureWeen/maui PR #9 (#33327)
Adds the issue-triage skill from PureWeen#9 to help triage open GitHub issues that need milestones, labels, or investigation. ## Changes - **`.github/skills/issue-triage/SKILL.md`** - Skill definition with workflow, trigger phrases, and milestone suggestion logic - **`scripts/init-triage-session.ps1`** - Initializes session with current milestones and labels from dotnet/maui - **`scripts/query-issues.ps1`** - Queries open issues with platform/area/age filters, fetches linked PRs, suggests milestones dynamically - **`scripts/record-triage.ps1`** - Tracks triaged issues in session file - **`.github/copilot-instructions.md`** - Added "Reusable Skills" section documenting the new skill ## Dynamic Milestone Detection Milestones are queried dynamically from dotnet/maui rather than being hardcoded (since SR milestones change monthly): - **SR milestones**: Identified by pattern `\.NET.*SR\d+`, sorted by due date to determine current/next SR - **Servicing milestone**: Identified by pattern `\.NET.*Servicing` - Suggestions use the dynamically discovered milestones based on issue characteristics (regressions → current SR, PRs → Servicing, etc.) ## Usage ```bash # Initialize triage session pwsh .github/skills/issue-triage/scripts/init-triage-session.ps1 # Query Android issues needing triage pwsh .github/skills/issue-triage/scripts/query-issues.ps1 -Platform android -Limit 20 # Record a triage decision pwsh .github/skills/issue-triage/scripts/record-triage.ps1 -IssueNumber 33272 -Milestone "Backlog" ``` Trigger phrases: "find issues to triage", "triage Android issues", "what issues need attention" <!-- START COPILOT CODING AGENT SUFFIX --> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Create a PR for an issue-triage skill that uses the skill from here PureWeen#9. Just grab the issue-triage skill from this PR please </details> <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/dotnet/maui/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: PureWeen <[email protected]> Co-authored-by: Shane Neuville <[email protected]>
1 parent fdb7d04 commit 63761c7

File tree

5 files changed

+1079
-0
lines changed

5 files changed

+1079
-0
lines changed

.github/copilot-instructions.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,16 @@ The repository includes specialized custom agents for specific tasks. These agen
200200
- **Trigger phrases**: "test this PR", "validate PR #XXXXX in Sandbox", "reproduce issue #XXXXX", "try out in Sandbox"
201201
- **Do NOT use for**: Code review (use pr agent), writing automated tests (use uitest-coding-agent)
202202

203+
### Reusable Skills
204+
205+
Skills are modular capabilities that can be invoked directly or used by agents. Located in `.github/skills/`:
206+
207+
1. **issue-triage** (`.github/skills/issue-triage/SKILL.md`)
208+
- **Purpose**: Query and triage open issues that need milestones, labels, or investigation
209+
- **Trigger phrases**: "find issues to triage", "show me old Android issues", "what issues need attention", "triage Android issues"
210+
- **Scripts**: `init-triage-session.ps1`, `query-issues.ps1`, `record-triage.ps1`
211+
- **Used by**: Any agent or direct invocation
212+
203213
### Using Custom Agents
204214

205215
**Delegation Policy**: When user request matches agent trigger phrases, **ALWAYS delegate to the appropriate agent immediately**. Do not ask for permission or explain alternatives unless the request is ambiguous.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
name: issue-triage
3+
description: Queries and triages open GitHub issues that need attention. Helps identify issues needing milestones, labels, or investigation.
4+
metadata:
5+
author: dotnet-maui
6+
version: "2.1"
7+
compatibility: Requires GitHub CLI (gh) authenticated with access to dotnet/maui repository.
8+
---
9+
10+
# Issue Triage Skill
11+
12+
This skill helps triage open GitHub issues in the dotnet/maui repository by:
13+
1. Initializing a session with current milestones and labels
14+
2. Loading a batch of issues into memory
15+
3. Presenting issues ONE AT A TIME for triage decisions
16+
4. Suggesting milestones based on issue characteristics
17+
5. Tracking progress through a triage session
18+
19+
## When to Use
20+
21+
- "Find issues to triage"
22+
- "Let's triage issues"
23+
- "Grab me 10 issues to triage"
24+
- "Triage Android issues"
25+
26+
## Triage Workflow
27+
28+
### Step 1: Initialize Session
29+
30+
Start by initializing a session to load current milestones and labels:
31+
32+
```bash
33+
pwsh .github/skills/issue-triage/scripts/init-triage-session.ps1
34+
```
35+
36+
### Step 2: Load Issues Into Memory
37+
38+
Load a batch of issues (e.g., 20) but DO NOT display them all. Store them for one-at-a-time presentation:
39+
40+
```bash
41+
pwsh .github/skills/issue-triage/scripts/query-issues.ps1 -Limit 100 -OutputFormat triage
42+
```
43+
44+
### Step 3: Present ONE Issue at a Time
45+
46+
**IMPORTANT**: When user asks to triage, present only ONE issue at a time in this format:
47+
48+
```markdown
49+
## Issue #XXXXX
50+
51+
**[Title]**
52+
53+
🔗 [URL]
54+
55+
| Field | Value |
56+
|-------|-------|
57+
| **Author** | username (Syncfusion if applicable) |
58+
| **Platform** | platform |
59+
| **Area** | area |
60+
| **Labels** | labels |
61+
| **Linked PR** | PR info with milestone if available |
62+
| **Regression** | Yes/No |
63+
| **Comments** | count |
64+
65+
**Comment Summary** (if any):
66+
- [Author] Comment preview...
67+
68+
**My Suggestion**: `Milestone` - Reason
69+
70+
---
71+
72+
What would you like to do with this issue?
73+
```
74+
75+
### Step 4: Wait for User Decision
76+
77+
Wait for user to say:
78+
- A milestone name (e.g., "Backlog", "current SR", "Servicing")
79+
- "yes" to accept suggestion
80+
- "skip" or "next" to move on without changes
81+
- Specific instructions (e.g., "next SR and add regression label")
82+
83+
### Step 5: Apply Changes and Move to Next
84+
85+
After applying changes, automatically present the NEXT issue.
86+
87+
## Script Parameters
88+
89+
### query-issues.ps1
90+
91+
| Parameter | Values | Default | Description |
92+
|-----------|--------|---------|-------------|
93+
| `-Platform` | android, ios, windows, maccatalyst, all | all | Filter by platform |
94+
| `-Area` | Any area label (e.g., collectionview, shell) | "" | Filter by area |
95+
| `-Limit` | 1-1000 | 50 | Maximum issues to fetch |
96+
| `-Skip` | 0+ | 0 | Skip first N issues (for pagination) |
97+
| `-OutputFormat` | table, json, markdown, triage | table | Output format |
98+
| `-RequireAreaLabel` | switch | false | Only return issues with area-* labels |
99+
| `-SkipDetails` | switch | false | Skip fetching PRs/comments (faster) |
100+
101+
## Milestone Suggestion Logic
102+
103+
The script dynamically queries current milestones from dotnet/maui and suggests them based on issue characteristics:
104+
105+
| Condition | Suggested Milestone | Reason |
106+
|-----------|---------------------|--------|
107+
| Linked PR has milestone | PR's milestone | "PR already has milestone" |
108+
| Has `i/regression` label | Current SR milestone (soonest due) | "Regression - current SR milestone" |
109+
| Has open linked PR | Servicing milestone (or next SR) | "Has open PR" |
110+
| Default | Backlog | "No PR, not a regression" |
111+
112+
**Note**: SR milestones are sorted by due date, so the soonest SR is suggested for regressions. Milestone names change monthly, so they are queried dynamically rather than hardcoded.
113+
114+
## Applying Triage Decisions
115+
116+
```bash
117+
# Set milestone only
118+
gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "Backlog"
119+
120+
# Set milestone and add labels
121+
gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME" --add-label "i/regression"
122+
123+
# Set milestone on both issue AND linked PR
124+
gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME"
125+
gh pr edit PR_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME"
126+
```
127+
128+
## Common Milestone Types
129+
130+
| Milestone Type | Use When |
131+
|----------------|----------|
132+
| Current SR (e.g., SR3) | Regressions, critical bugs with PRs ready |
133+
| Next SR (e.g., SR4) | Important bugs, regressions being investigated |
134+
| Servicing | General fixes with PRs, non-urgent improvements |
135+
| Backlog | No PR, not a regression, nice-to-have fixes |
136+
137+
**Note**: Use `init-triage-session.ps1` to see current milestone names.
138+
139+
## Label Quick Reference
140+
141+
**Regression Labels:**
142+
- `i/regression` - Confirmed regression
143+
- `regressed-in-10.0.0` - Specific version
144+
145+
**Priority Labels:**
146+
- `p/0` - Critical
147+
- `p/1` - High
148+
- `p/2` - Medium
149+
- `p/3` - Low
150+
151+
**iOS 26 / macOS 26:**
152+
- `version/iOS-26` - iOS 26 specific issue
153+
154+
## Session Tracking (Optional)
155+
156+
```bash
157+
# Record triaged issue
158+
pwsh .github/skills/issue-triage/scripts/record-triage.ps1 -IssueNumber 33272 -Milestone "Backlog"
159+
160+
# View session stats
161+
cat CustomAgentLogsTmp/Triage/triage-*.json | jq '.Stats'
162+
```
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#!/usr/bin/env pwsh
2+
<#
3+
.SYNOPSIS
4+
Initializes a triage session by loading current milestones, labels, and creating a session tracker.
5+
6+
.DESCRIPTION
7+
This script prepares for an issue triage session by:
8+
1. Querying all open milestones from dotnet/maui
9+
2. Loading common labels for quick reference
10+
3. Creating a session file to track triaged issues
11+
12+
Run this at the start of a triage session to have current milestone/label data available.
13+
14+
.PARAMETER SessionName
15+
Optional name for the triage session (default: timestamp-based)
16+
17+
.PARAMETER OutputDir
18+
Directory to store session files (default: CustomAgentLogsTmp/Triage)
19+
20+
.EXAMPLE
21+
./init-triage-session.ps1
22+
# Initializes a new triage session with defaults
23+
24+
.EXAMPLE
25+
./init-triage-session.ps1 -SessionName "android-triage"
26+
# Creates a named session for Android issue triage
27+
#>
28+
29+
param(
30+
[Parameter(Mandatory = $false)]
31+
[string]$SessionName = "",
32+
33+
[Parameter(Mandatory = $false)]
34+
[string]$OutputDir = "CustomAgentLogsTmp/Triage"
35+
)
36+
37+
$ErrorActionPreference = "Stop"
38+
39+
Write-Host "╔═══════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
40+
Write-Host "║ Initializing Triage Session ║" -ForegroundColor Cyan
41+
Write-Host "╚═══════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
42+
43+
# Create output directory
44+
if (-not (Test-Path $OutputDir)) {
45+
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
46+
}
47+
48+
# Generate session name if not provided
49+
if ($SessionName -eq "") {
50+
$SessionName = "triage-$(Get-Date -Format 'yyyy-MM-dd-HHmm')"
51+
}
52+
53+
$sessionFile = Join-Path $OutputDir "$SessionName.json"
54+
55+
Write-Host ""
56+
Write-Host "Session: $SessionName" -ForegroundColor Green
57+
Write-Host "Output: $sessionFile" -ForegroundColor DarkGray
58+
59+
# Query open milestones
60+
Write-Host ""
61+
Write-Host "Fetching open milestones..." -ForegroundColor Cyan
62+
63+
$milestones = @()
64+
try {
65+
$msResult = gh api repos/dotnet/maui/milestones --jq '.[] | {number, title, due_on, open_issues}' 2>&1
66+
$msLines = $msResult -split "`n" | Where-Object { $_ -match "^\{" }
67+
68+
foreach ($line in $msLines) {
69+
$ms = $line | ConvertFrom-Json
70+
$milestones += [PSCustomObject]@{
71+
Number = $ms.number
72+
Title = $ms.title
73+
DueOn = $ms.due_on
74+
OpenIssues = $ms.open_issues
75+
}
76+
}
77+
78+
# Sort by title for easy reference
79+
$milestones = $milestones | Sort-Object Title
80+
81+
Write-Host " Found $($milestones.Count) open milestones:" -ForegroundColor Green
82+
83+
# Group milestones by type
84+
$srMilestones = $milestones | Where-Object { $_.Title -match "SR\d|Servicing" }
85+
$backlog = $milestones | Where-Object { $_.Title -eq "Backlog" }
86+
$otherMs = $milestones | Where-Object { $_.Title -notmatch "SR\d|Servicing" -and $_.Title -ne "Backlog" }
87+
88+
Write-Host ""
89+
Write-Host " Servicing Releases:" -ForegroundColor Yellow
90+
foreach ($ms in $srMilestones) {
91+
$dueInfo = ""
92+
if ($ms.DueOn -and $ms.DueOn -is [string] -and $ms.DueOn.Length -ge 10) {
93+
$dueInfo = " (due: $($ms.DueOn.Substring(0, 10)))"
94+
}
95+
Write-Host " - $($ms.Title)$dueInfo [$($ms.OpenIssues) open]"
96+
}
97+
98+
if ($backlog) {
99+
Write-Host ""
100+
Write-Host " Backlog:" -ForegroundColor Yellow
101+
Write-Host " - $($backlog.Title) [$($backlog.OpenIssues) open]"
102+
}
103+
104+
if ($otherMs.Count -gt 0) {
105+
Write-Host ""
106+
Write-Host " Other:" -ForegroundColor Yellow
107+
foreach ($ms in $otherMs | Select-Object -First 5) {
108+
Write-Host " - $($ms.Title) [$($ms.OpenIssues) open]"
109+
}
110+
if ($otherMs.Count -gt 5) {
111+
Write-Host " ... and $($otherMs.Count - 5) more"
112+
}
113+
}
114+
}
115+
catch {
116+
Write-Host " Failed to fetch milestones: $_" -ForegroundColor Red
117+
}
118+
119+
# Query common labels
120+
Write-Host ""
121+
Write-Host "Fetching labels..." -ForegroundColor Cyan
122+
123+
$labels = @{
124+
Platforms = @()
125+
Areas = @()
126+
Status = @()
127+
Priority = @()
128+
Regression = @()
129+
Other = @()
130+
}
131+
132+
try {
133+
$labelResult = gh api repos/dotnet/maui/labels --paginate --jq '.[].name' 2>&1
134+
$allLabels = $labelResult -split "`n" | Where-Object { $_ -ne "" }
135+
136+
foreach ($label in $allLabels) {
137+
if ($label -match "^platform/") {
138+
$labels.Platforms += $label
139+
}
140+
elseif ($label -match "^area-") {
141+
$labels.Areas += $label
142+
}
143+
elseif ($label -match "^s/") {
144+
$labels.Status += $label
145+
}
146+
elseif ($label -match "^p/") {
147+
$labels.Priority += $label
148+
}
149+
elseif ($label -match "regression|regressed") {
150+
$labels.Regression += $label
151+
}
152+
}
153+
154+
Write-Host " Platforms: $($labels.Platforms.Count) labels"
155+
Write-Host " Areas: $($labels.Areas.Count) labels"
156+
Write-Host " Status: $($labels.Status.Count) labels"
157+
Write-Host " Priority: $($labels.Priority.Count) labels"
158+
Write-Host " Regression: $($labels.Regression.Count) labels"
159+
}
160+
catch {
161+
Write-Host " Failed to fetch labels: $_" -ForegroundColor Red
162+
}
163+
164+
# Create session object
165+
$session = [PSCustomObject]@{
166+
Name = $SessionName
167+
StartedAt = (Get-Date).ToString("o")
168+
Milestones = $milestones
169+
Labels = $labels
170+
TriagedIssues = @()
171+
Stats = @{
172+
Total = 0
173+
Backlog = 0
174+
Servicing = 0
175+
SR = 0
176+
Skipped = 0
177+
}
178+
}
179+
180+
# Save session file
181+
$session | ConvertTo-Json -Depth 10 | Out-File -FilePath $sessionFile -Encoding UTF8
182+
183+
Write-Host ""
184+
Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
185+
Write-Host ""
186+
Write-Host "Session initialized! Quick reference:" -ForegroundColor Green
187+
Write-Host ""
188+
Write-Host " Common Milestones:" -ForegroundColor Yellow
189+
$srMilestones | ForEach-Object { Write-Host " $($_.Title)" }
190+
Write-Host " Backlog"
191+
Write-Host ""
192+
Write-Host " Priority Labels:" -ForegroundColor Yellow
193+
$labels.Priority | ForEach-Object { Write-Host " $_" }
194+
Write-Host ""
195+
Write-Host " Regression Labels:" -ForegroundColor Yellow
196+
$labels.Regression | Select-Object -First 5 | ForEach-Object { Write-Host " $_" }
197+
Write-Host ""
198+
Write-Host " Session file: $sessionFile" -ForegroundColor DarkGray
199+
Write-Host ""
200+
Write-Host "Ready to triage! Run query-issues.ps1 to load issues." -ForegroundColor Green
201+
202+
# Return session for pipeline usage
203+
return $session

0 commit comments

Comments
 (0)