Files
dotnet__skills/.github/workflows/issue-triage.md
Jan Krivanek 0bdf428da0 Fix triage workflow: separate label and assignee operations (#626)
* 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>
2026-05-07 10:42:56 +00:00

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.