-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add issue-triage skill from PureWeen/maui PR #9 #33327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4312b94
65d581e
c6de4d8
b77e761
73e52e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| --- | ||
| name: issue-triage | ||
| description: Queries and triages open GitHub issues that need attention. Helps identify issues needing milestones, labels, or investigation. | ||
| metadata: | ||
| author: dotnet-maui | ||
| version: "2.1" | ||
| compatibility: Requires GitHub CLI (gh) authenticated with access to dotnet/maui repository. | ||
| --- | ||
|
|
||
| # Issue Triage Skill | ||
|
|
||
| This skill helps triage open GitHub issues in the dotnet/maui repository by: | ||
| 1. Initializing a session with current milestones and labels | ||
| 2. Loading a batch of issues into memory | ||
| 3. Presenting issues ONE AT A TIME for triage decisions | ||
| 4. Suggesting milestones based on issue characteristics | ||
| 5. Tracking progress through a triage session | ||
|
|
||
| ## When to Use | ||
|
|
||
| - "Find issues to triage" | ||
| - "Let's triage issues" | ||
| - "Grab me 10 issues to triage" | ||
| - "Triage Android issues" | ||
|
|
||
| ## Triage Workflow | ||
|
|
||
| ### Step 1: Initialize Session | ||
|
|
||
| Start by initializing a session to load current milestones and labels: | ||
|
|
||
| ```bash | ||
| pwsh .github/skills/issue-triage/scripts/init-triage-session.ps1 | ||
| ``` | ||
|
|
||
| ### Step 2: Load Issues Into Memory | ||
|
|
||
| Load a batch of issues (e.g., 20) but DO NOT display them all. Store them for one-at-a-time presentation: | ||
|
|
||
| ```bash | ||
| pwsh .github/skills/issue-triage/scripts/query-issues.ps1 -Limit 100 -OutputFormat triage | ||
| ``` | ||
|
|
||
| ### Step 3: Present ONE Issue at a Time | ||
|
|
||
| **IMPORTANT**: When user asks to triage, present only ONE issue at a time in this format: | ||
|
|
||
| ```markdown | ||
| ## Issue #XXXXX | ||
|
|
||
| **[Title]** | ||
|
|
||
| 🔗 [URL] | ||
|
|
||
| | Field | Value | | ||
| |-------|-------| | ||
| | **Author** | username (Syncfusion if applicable) | | ||
| | **Platform** | platform | | ||
| | **Area** | area | | ||
| | **Labels** | labels | | ||
| | **Linked PR** | PR info with milestone if available | | ||
| | **Regression** | Yes/No | | ||
| | **Comments** | count | | ||
|
|
||
| **Comment Summary** (if any): | ||
| - [Author] Comment preview... | ||
|
|
||
| **My Suggestion**: `Milestone` - Reason | ||
|
|
||
| --- | ||
|
|
||
| What would you like to do with this issue? | ||
| ``` | ||
|
|
||
| ### Step 4: Wait for User Decision | ||
|
|
||
| Wait for user to say: | ||
| - A milestone name (e.g., "Backlog", "current SR", "Servicing") | ||
| - "yes" to accept suggestion | ||
| - "skip" or "next" to move on without changes | ||
| - Specific instructions (e.g., "next SR and add regression label") | ||
|
|
||
| ### Step 5: Apply Changes and Move to Next | ||
|
|
||
| After applying changes, automatically present the NEXT issue. | ||
|
|
||
| ## Script Parameters | ||
|
|
||
| ### query-issues.ps1 | ||
|
|
||
| | Parameter | Values | Default | Description | | ||
| |-----------|--------|---------|-------------| | ||
| | `-Platform` | android, ios, windows, maccatalyst, all | all | Filter by platform | | ||
| | `-Area` | Any area label (e.g., collectionview, shell) | "" | Filter by area | | ||
| | `-Limit` | 1-1000 | 50 | Maximum issues to fetch | | ||
| | `-Skip` | 0+ | 0 | Skip first N issues (for pagination) | | ||
| | `-OutputFormat` | table, json, markdown, triage | table | Output format | | ||
| | `-RequireAreaLabel` | switch | false | Only return issues with area-* labels | | ||
| | `-SkipDetails` | switch | false | Skip fetching PRs/comments (faster) | | ||
|
|
||
| ## Milestone Suggestion Logic | ||
|
|
||
| The script dynamically queries current milestones from dotnet/maui and suggests them based on issue characteristics: | ||
|
|
||
| | Condition | Suggested Milestone | Reason | | ||
| |-----------|---------------------|--------| | ||
| | Linked PR has milestone | PR's milestone | "PR already has milestone" | | ||
| | Has `i/regression` label | Current SR milestone (soonest due) | "Regression - current SR milestone" | | ||
| | Has open linked PR | Servicing milestone (or next SR) | "Has open PR" | | ||
| | Default | Backlog | "No PR, not a regression" | | ||
|
|
||
| **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. | ||
|
|
||
| ## Applying Triage Decisions | ||
|
|
||
| ```bash | ||
| # Set milestone only | ||
| gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "Backlog" | ||
|
|
||
| # Set milestone and add labels | ||
| gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME" --add-label "i/regression" | ||
|
|
||
| # Set milestone on both issue AND linked PR | ||
| gh issue edit ISSUE_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME" | ||
| gh pr edit PR_NUMBER --repo dotnet/maui --milestone "MILESTONE_NAME" | ||
| ``` | ||
|
|
||
| ## Common Milestone Types | ||
|
|
||
| | Milestone Type | Use When | | ||
| |----------------|----------| | ||
| | Current SR (e.g., SR3) | Regressions, critical bugs with PRs ready | | ||
| | Next SR (e.g., SR4) | Important bugs, regressions being investigated | | ||
| | Servicing | General fixes with PRs, non-urgent improvements | | ||
| | Backlog | No PR, not a regression, nice-to-have fixes | | ||
|
|
||
| **Note**: Use `init-triage-session.ps1` to see current milestone names. | ||
|
|
||
| ## Label Quick Reference | ||
|
|
||
| **Regression Labels:** | ||
| - `i/regression` - Confirmed regression | ||
| - `regressed-in-10.0.0` - Specific version | ||
|
|
||
| **Priority Labels:** | ||
| - `p/0` - Critical | ||
| - `p/1` - High | ||
| - `p/2` - Medium | ||
| - `p/3` - Low | ||
|
|
||
| **iOS 26 / macOS 26:** | ||
| - `version/iOS-26` - iOS 26 specific issue | ||
|
|
||
| ## Session Tracking (Optional) | ||
|
|
||
| ```bash | ||
| # Record triaged issue | ||
| pwsh .github/skills/issue-triage/scripts/record-triage.ps1 -IssueNumber 33272 -Milestone "Backlog" | ||
|
|
||
| # View session stats | ||
| cat CustomAgentLogsTmp/Triage/triage-*.json | jq '.Stats' | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| #!/usr/bin/env pwsh | ||
| <# | ||
| .SYNOPSIS | ||
| Initializes a triage session by loading current milestones, labels, and creating a session tracker. | ||
|
|
||
| .DESCRIPTION | ||
| This script prepares for an issue triage session by: | ||
| 1. Querying all open milestones from dotnet/maui | ||
| 2. Loading common labels for quick reference | ||
| 3. Creating a session file to track triaged issues | ||
|
|
||
| Run this at the start of a triage session to have current milestone/label data available. | ||
|
|
||
| .PARAMETER SessionName | ||
| Optional name for the triage session (default: timestamp-based) | ||
|
|
||
| .PARAMETER OutputDir | ||
| Directory to store session files (default: CustomAgentLogsTmp/Triage) | ||
|
|
||
| .EXAMPLE | ||
| ./init-triage-session.ps1 | ||
| # Initializes a new triage session with defaults | ||
|
|
||
| .EXAMPLE | ||
| ./init-triage-session.ps1 -SessionName "android-triage" | ||
| # Creates a named session for Android issue triage | ||
| #> | ||
|
|
||
| param( | ||
| [Parameter(Mandatory = $false)] | ||
| [string]$SessionName = "", | ||
|
|
||
| [Parameter(Mandatory = $false)] | ||
| [string]$OutputDir = "CustomAgentLogsTmp/Triage" | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| Write-Host "╔═══════════════════════════════════════════════════════════╗" -ForegroundColor Cyan | ||
| Write-Host "║ Initializing Triage Session ║" -ForegroundColor Cyan | ||
| Write-Host "╚═══════════════════════════════════════════════════════════╝" -ForegroundColor Cyan | ||
|
|
||
| # Create output directory | ||
| if (-not (Test-Path $OutputDir)) { | ||
| New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null | ||
| } | ||
|
|
||
| # Generate session name if not provided | ||
| if ($SessionName -eq "") { | ||
| $SessionName = "triage-$(Get-Date -Format 'yyyy-MM-dd-HHmm')" | ||
| } | ||
|
|
||
| $sessionFile = Join-Path $OutputDir "$SessionName.json" | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Session: $SessionName" -ForegroundColor Green | ||
| Write-Host "Output: $sessionFile" -ForegroundColor DarkGray | ||
|
|
||
| # Query open milestones | ||
| Write-Host "" | ||
| Write-Host "Fetching open milestones..." -ForegroundColor Cyan | ||
|
|
||
| $milestones = @() | ||
| try { | ||
| $msResult = gh api repos/dotnet/maui/milestones --jq '.[] | {number, title, due_on, open_issues}' 2>&1 | ||
| $msLines = $msResult -split "`n" | Where-Object { $_ -match "^\{" } | ||
|
|
||
| foreach ($line in $msLines) { | ||
| $ms = $line | ConvertFrom-Json | ||
| $milestones += [PSCustomObject]@{ | ||
| Number = $ms.number | ||
| Title = $ms.title | ||
| DueOn = $ms.due_on | ||
| OpenIssues = $ms.open_issues | ||
| } | ||
| } | ||
|
|
||
| # Sort by title for easy reference | ||
| $milestones = $milestones | Sort-Object Title | ||
|
|
||
| Write-Host " Found $($milestones.Count) open milestones:" -ForegroundColor Green | ||
|
|
||
| # Group milestones by type | ||
| $srMilestones = $milestones | Where-Object { $_.Title -match "SR\d|Servicing" } | ||
| $backlog = $milestones | Where-Object { $_.Title -eq "Backlog" } | ||
| $otherMs = $milestones | Where-Object { $_.Title -notmatch "SR\d|Servicing" -and $_.Title -ne "Backlog" } | ||
|
|
||
| Write-Host "" | ||
| Write-Host " Servicing Releases:" -ForegroundColor Yellow | ||
| foreach ($ms in $srMilestones) { | ||
| $dueInfo = "" | ||
| if ($ms.DueOn -and $ms.DueOn -is [string] -and $ms.DueOn.Length -ge 10) { | ||
| $dueInfo = " (due: $($ms.DueOn.Substring(0, 10)))" | ||
| } | ||
| Write-Host " - $($ms.Title)$dueInfo [$($ms.OpenIssues) open]" | ||
| } | ||
|
|
||
| if ($backlog) { | ||
| Write-Host "" | ||
| Write-Host " Backlog:" -ForegroundColor Yellow | ||
| Write-Host " - $($backlog.Title) [$($backlog.OpenIssues) open]" | ||
| } | ||
|
|
||
| if ($otherMs.Count -gt 0) { | ||
| Write-Host "" | ||
| Write-Host " Other:" -ForegroundColor Yellow | ||
| foreach ($ms in $otherMs | Select-Object -First 5) { | ||
| Write-Host " - $($ms.Title) [$($ms.OpenIssues) open]" | ||
| } | ||
| if ($otherMs.Count -gt 5) { | ||
| Write-Host " ... and $($otherMs.Count - 5) more" | ||
| } | ||
| } | ||
| } | ||
| catch { | ||
| Write-Host " Failed to fetch milestones: $_" -ForegroundColor Red | ||
| } | ||
|
|
||
| # Query common labels | ||
| Write-Host "" | ||
| Write-Host "Fetching labels..." -ForegroundColor Cyan | ||
|
|
||
| $labels = @{ | ||
| Platforms = @() | ||
| Areas = @() | ||
| Status = @() | ||
| Priority = @() | ||
| Regression = @() | ||
| Other = @() | ||
| } | ||
|
|
||
| try { | ||
| $labelResult = gh api repos/dotnet/maui/labels --paginate --jq '.[].name' 2>&1 | ||
| $allLabels = $labelResult -split "`n" | Where-Object { $_ -ne "" } | ||
|
|
||
| foreach ($label in $allLabels) { | ||
| if ($label -match "^platform/") { | ||
| $labels.Platforms += $label | ||
| } | ||
| elseif ($label -match "^area-") { | ||
| $labels.Areas += $label | ||
| } | ||
| elseif ($label -match "^s/") { | ||
| $labels.Status += $label | ||
| } | ||
| elseif ($label -match "^p/") { | ||
| $labels.Priority += $label | ||
| } | ||
| elseif ($label -match "regression|regressed") { | ||
| $labels.Regression += $label | ||
| } | ||
| } | ||
|
|
||
| Write-Host " Platforms: $($labels.Platforms.Count) labels" | ||
| Write-Host " Areas: $($labels.Areas.Count) labels" | ||
| Write-Host " Status: $($labels.Status.Count) labels" | ||
| Write-Host " Priority: $($labels.Priority.Count) labels" | ||
| Write-Host " Regression: $($labels.Regression.Count) labels" | ||
| } | ||
| catch { | ||
| Write-Host " Failed to fetch labels: $_" -ForegroundColor Red | ||
| } | ||
|
|
||
| # Create session object | ||
| $session = [PSCustomObject]@{ | ||
| Name = $SessionName | ||
| StartedAt = (Get-Date).ToString("o") | ||
| Milestones = $milestones | ||
| Labels = $labels | ||
| TriagedIssues = @() | ||
| Stats = @{ | ||
| Total = 0 | ||
| Backlog = 0 | ||
| Servicing = 0 | ||
| SR = 0 | ||
| Skipped = 0 | ||
| } | ||
|
Comment on lines
+171
to
+177
|
||
| } | ||
|
|
||
| # Save session file | ||
| $session | ConvertTo-Json -Depth 10 | Out-File -FilePath $sessionFile -Encoding UTF8 | ||
|
|
||
| Write-Host "" | ||
| Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan | ||
| Write-Host "" | ||
| Write-Host "Session initialized! Quick reference:" -ForegroundColor Green | ||
| Write-Host "" | ||
| Write-Host " Common Milestones:" -ForegroundColor Yellow | ||
| $srMilestones | ForEach-Object { Write-Host " $($_.Title)" } | ||
| Write-Host " Backlog" | ||
| Write-Host "" | ||
| Write-Host " Priority Labels:" -ForegroundColor Yellow | ||
| $labels.Priority | ForEach-Object { Write-Host " $_" } | ||
| Write-Host "" | ||
| Write-Host " Regression Labels:" -ForegroundColor Yellow | ||
| $labels.Regression | Select-Object -First 5 | ForEach-Object { Write-Host " $_" } | ||
| Write-Host "" | ||
| Write-Host " Session file: $sessionFile" -ForegroundColor DarkGray | ||
| Write-Host "" | ||
| Write-Host "Ready to triage! Run query-issues.ps1 to load issues." -ForegroundColor Green | ||
|
|
||
| # Return session for pipeline usage | ||
| return $session | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The shebang line has incorrect spacing. PowerShell shebangs should be '#!/usr/bin/env pwsh' without extra spaces. The current format with spaces after '#' may not be recognized correctly by some systems.