mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
0bdf428da0
* Fix triage workflow: separate label and assignee operations - Use add_labels tool for labeling (Step 6) instead of update_issue - Reserve update_issue exclusively for assignee assignment (Step 4) - Increase update_issue max to 2 for assignment flexibility - Add explicit workflow_dispatch guidance: agent must pass issue_number/item_number on all safe-output calls when there is no triggering issue context - Fixes issues where owners were mentioned in comments but not actually assigned to the issue * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
209 lines
9.8 KiB
Markdown
209 lines
9.8 KiB
Markdown
---
|
|
name: "Issue Triage"
|
|
description: >
|
|
Intelligent issue triage assistant that processes new and reopened issues.
|
|
Analyzes issue content, assigns area labels based on the codebase structure,
|
|
determines appropriate owners from CODEOWNERS, and provides a brief
|
|
actionable triage summary. Links similar issues when relevant.
|
|
|
|
on:
|
|
issues:
|
|
types: [opened, reopened]
|
|
workflow_dispatch:
|
|
inputs:
|
|
issue_number:
|
|
description: "Issue number to triage"
|
|
required: true
|
|
|
|
# ###############################################################
|
|
# Override the COPILOT_GITHUB_TOKEN secret usage for the workflow
|
|
# with a randomly-selected token from a pool of secrets.
|
|
#
|
|
# As soon as organization-level billing is offered for Agentic
|
|
# Workflows, this stop-gap approach will be removed.
|
|
#
|
|
# See: /.github/actions/select-copilot-pat/README.md
|
|
# ###############################################################
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
name: Checkout the select-copilot-pat action folder
|
|
with:
|
|
persist-credentials: false
|
|
sparse-checkout: .github/actions/select-copilot-pat
|
|
sparse-checkout-cone-mode: true
|
|
fetch-depth: 1
|
|
|
|
- id: select-copilot-pat
|
|
name: Select Copilot token from pool
|
|
uses: ./.github/actions/select-copilot-pat
|
|
env:
|
|
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
|
|
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
|
|
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
|
|
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
|
|
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
|
|
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
|
|
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
|
|
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
|
|
|
|
concurrency:
|
|
group: gh-aw-${{ github.workflow }}-${{ github.event.issue.number || inputs.issue_number }}
|
|
|
|
# Add the pre-activation output of the randomly selected PAT
|
|
jobs:
|
|
pre-activation:
|
|
outputs:
|
|
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
|
|
|
|
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
|
|
engine:
|
|
id: copilot
|
|
env:
|
|
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
|
|
|
|
permissions:
|
|
contents: read
|
|
issues: read
|
|
|
|
tools:
|
|
github:
|
|
toolsets: [repos, issues]
|
|
bash: ["cat", "grep", "head", "tail", "find", "ls", "jq", "sort"]
|
|
|
|
safe-outputs:
|
|
add-labels:
|
|
max: 5
|
|
update-issue:
|
|
target: "*"
|
|
max: 2
|
|
add-comment:
|
|
max: 1
|
|
|
|
network:
|
|
allowed:
|
|
- defaults
|
|
|
|
timeout-minutes: 10
|
|
---
|
|
|
|
# Issue Triage
|
|
|
|
You are a triage assistant for the dotnet/skills GitHub repository. Your task is to analyze and triage a single issue.
|
|
|
|
## Target Issue
|
|
|
|
Triage issue number: `${{ github.event.issue.number || inputs.issue_number }}`
|
|
|
|
**Important — workflow_dispatch context:** When this workflow is triggered via `workflow_dispatch`, there is no triggering issue context. You MUST pass `issue_number` (for `update_issue`) or `item_number` (for `add_labels` and `add_comment`) explicitly in every safe-output tool call. Use the issue number from the Target Issue above.
|
|
|
|
## Step 1: Retrieve Issue Content
|
|
|
|
Use the `get_issue` tool to fetch the full issue content (title, body, labels, comments).
|
|
|
|
If the issue is obviously spam, bot-generated, or not an actionable issue, add a brief comment explaining why it was skipped, add the `Triaged` label, and stop.
|
|
|
|
If the issue already has the `Triaged` label, skip it entirely — it has already been triaged.
|
|
|
|
### Reopened Issues
|
|
|
|
If the issue was **reopened** (i.e., it already has labels, assignees, or prior triage comments):
|
|
- Review existing labels — they may still be correct. Do not blindly overwrite them.
|
|
- Pay special attention to the **reopen context**: the most recent comment or event that caused the reopen often contains the key new information (e.g., "still happening after fix", "different repro").
|
|
- If existing labels are still accurate, keep them. Only change the area label if the reopen context clearly indicates a different area.
|
|
- If the issue was previously triaged and closed as resolved, note that it has regressed or resurfaced in your triage comment.
|
|
|
|
## Step 2: Gather Context
|
|
|
|
- Fetch the CODEOWNERS file at `.github/CODEOWNERS` using bash: `cat .github/CODEOWNERS`
|
|
- Fetch available labels using the `list_labels` GitHub tool
|
|
- Search for similar open issues using the `search_issues` tool with key terms from the issue title and body
|
|
- List recent issues to check for duplicates
|
|
|
|
## Step 3: Determine Area Label
|
|
|
|
Analyze the issue content and determine which area of the codebase it relates to. Assign **one** `area-*` label based on these mappings:
|
|
|
|
| Area Label | Scope |
|
|
|---|---|
|
|
| `area-msbuild` | MSBuild, build system, project files |
|
|
| `area-dotnet` | General C#/.NET, common language features |
|
|
| `area-dotnet-ai` | AI/ML, MCP, model context protocol |
|
|
| `area-dotnet-aspnet` | ASP.NET Core, web development |
|
|
| `area-dotnet-data` | Data access, Entity Framework |
|
|
| `area-dotnet-diag` | Diagnostics, performance, debugging, crash analysis |
|
|
| `area-dotnet-experimental` | Experimental skills under evaluation |
|
|
| `area-dotnet-maui` | .NET MAUI, mobile/desktop UI |
|
|
| `area-dotnet-nuget` | NuGet package management |
|
|
| `area-dotnet-template-engine` | Template engine, dotnet new |
|
|
| `area-dotnet-test` | Testing frameworks, test tooling |
|
|
| `area-dotnet-upgrade` | Migration, upgrading .NET versions |
|
|
| `area-dotnet11` | .NET 11 specific features |
|
|
| `area-infrastructure` | CI/CD, engineering infrastructure, workflows |
|
|
| `area-skill-validator` | Skill validation tooling |
|
|
|
|
If the issue clearly spans multiple areas, pick the **primary** one.
|
|
|
|
If none of the predefined area labels above fit the issue, use the `list_labels` GitHub tool to fetch all repository labels and filter for those with the `area-` prefix. Check if any of those labels match the issue's topic. If a match is found, use it. If **no** `area-*` label fits — do **not** add any area label at all.
|
|
|
|
## Step 4: Determine Owners
|
|
|
|
Using the CODEOWNERS file, determine the most appropriate owners for the issue based on its area:
|
|
|
|
1. Match the issue's area to the relevant paths in CODEOWNERS
|
|
2. Extract the listed owners (GitHub usernames and teams)
|
|
3. If the issue maps to a specific plugin/skill path, use those specific owners
|
|
4. If the issue is general or cross-cutting, use the default owners from the `*` rule
|
|
5. If you cannot confidently determine owners, add the `needs-manual-assignment` label instead of assigning
|
|
|
|
Use the `update_issue` tool to **directly assign** the determined owners to the issue by setting the `assignees` field. To satisfy tool validation, include a no-op `title` field set to the issue's current title fetched in Step 1, unchanged. **Do NOT set labels in this call.** Labels are handled separately in Step 6 using the `add_labels` tool.
|
|
|
|
If a user cannot be assigned (e.g., teams cannot be set as assignees), mention them in the triage comment instead.
|
|
|
|
## Step 5: Determine Issue Type
|
|
|
|
Classify the issue as one of the following types and apply the corresponding label:
|
|
- `bug` — Something is broken or not working as expected
|
|
- `enhancement` — A new feature or improvement to existing functionality
|
|
- `task` — A work item, chore, or maintenance request that is not a bug or feature
|
|
- `question` — A question or request for clarification
|
|
|
|
If the type is ambiguous, make your best judgment. You must always assign exactly one type label.
|
|
|
|
## Step 6: Apply Labels
|
|
|
|
Use the `add_labels` tool (NOT `update_issue`) to apply labels to the issue. The `add_labels` tool is additive — it does not remove existing labels.
|
|
|
|
Add the following labels:
|
|
- The determined `area-*` label (if one was determined)
|
|
- The issue type label (`bug`, `enhancement`, `task`, or `question`)
|
|
- The `Triaged` label
|
|
- If owners could not be determined: `needs-manual-assignment`
|
|
- If clearly a duplicate of an open issue: `duplicate`
|
|
|
|
**Important:** Only use labels that exist in the repository. Verify against the label list fetched in Step 2.
|
|
|
|
## Step 7: Post Triage Comment
|
|
|
|
Add a **single** comment to the issue with your triage analysis:
|
|
|
|
- Start with "**🎯 Issue Triage**"
|
|
- **Summary** (2-3 sentences): what the issue is about and which area it falls under
|
|
- **Type**: the issue type you assigned (bug/enhancement/task/question)
|
|
- **Assigned owners**: confirm who was assigned; mention any team handles that could not be directly assigned
|
|
- **Confidence**: rate your triage confidence as **High**, **Medium**, or **Low**
|
|
- **High**: issue clearly maps to a single area, type is obvious, owners are unambiguous
|
|
- **Medium**: reasonable confidence but some ambiguity (e.g., could span two areas, type is debatable)
|
|
- **Low**: significant uncertainty — multiple areas could apply, issue is vague, or you had to guess
|
|
- **Similar issues**: link any related open issues found, noting if this might be a duplicate
|
|
|
|
<details><summary>Triage details</summary>
|
|
|
|
- Area mapping rationale
|
|
- CODEOWNERS path match
|
|
- Confidence rationale (why High/Medium/Low)
|
|
- Any additional context or suggested next steps
|
|
|
|
</details>
|
|
|
|
Keep the comment **brief and actionable**. The collapsed details section is for additional context only.
|