Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions .github/workflows/issue-triage.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
---
name: Issue Triage
name: Issue and PR Triage

'on':
issues:
types: [opened]
pull_request:
types: [opened]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to triage (leave empty to process all)'
description: 'Issue/PR number to triage (leave empty to process all)'
required: false
type: string

jobs:
issue-triage:
uses: wp-cli/.github/.github/workflows/reusable-issue-triage.yml@main
with:
issue_number: ${{ github.event_name == 'workflow_dispatch' && inputs.issue_number || github.event.issue.number }}
issue_number: >-
${{
(github.event_name == 'workflow_dispatch' && inputs.issue_number) ||
(github.event_name == 'pull_request' && github.event.pull_request.number) ||
(github.event_name == 'issues' && github.event.issue.number) ||
''
}}
131 changes: 72 additions & 59 deletions .github/workflows/reusable-issue-triage.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
---
name: Issue Triage
name: Issue and PR Triage

'on':
workflow_call:
inputs:
issue_number:
description: 'Issue number to triage (leave empty to process all)'
description: 'Issue/PR number to triage (leave empty to process all)'
required: false
type: string

permissions:
issues: write
pull-requests: write
contents: read
models: read

jobs:
triage-new-issue:
name: Triage New Issue
if: github.event_name == 'issues'
triage-new-item:
name: Triage New Issue or PR
if: github.event_name == 'issues' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Get available labels
Expand All @@ -35,27 +36,29 @@ jobs:

- name: Set environment variables
env:
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
ITEM_TITLE: ${{ github.event_name == 'pull_request' && github.event.pull_request.title || github.event.issue.title }}
ITEM_BODY: ${{ github.event_name == 'pull_request' && github.event.pull_request.body || github.event.issue.body }}
ITEM_TYPE: ${{ github.event_name == 'pull_request' && 'pull request' || 'issue' }}
LABELS_RESULT: ${{ steps.get-labels.outputs.result }}
run: |
{
echo "AVAILABLE_LABELS=${LABELS_RESULT}"
echo "ISSUE_TITLE=${ISSUE_TITLE}"
echo "ISSUE_BODY<<EOF"
echo "${ISSUE_BODY}"
echo "ITEM_TITLE=${ITEM_TITLE}"
echo "ITEM_TYPE=${ITEM_TYPE}"
echo "ITEM_BODY<<EOF"
echo "${ITEM_BODY}"
echo "EOF"
} >> "$GITHUB_ENV"

- name: Analyze issue with AI
- name: Analyze with AI
id: ai-triage
uses: actions/ai-inference@v2
with:
prompt: |
## Role

You are an issue triage assistant. Analyze the current GitHub
issue and identify the most appropriate existing labels. Use the
You are an issue and pull request triage assistant. Analyze the current GitHub
${{ env.ITEM_TYPE }} and identify the most appropriate existing labels. Use the
available tools to gather information; do not ask for information
to be provided.

Expand All @@ -74,22 +77,22 @@ jobs:
${{ env.AVAILABLE_LABELS }}
```

**Issue Title**:
**Title**:
```
${{ env.ISSUE_TITLE }}
${{ env.ITEM_TITLE }}
```

**Issue Body**:
**Body**:
```
${{ env.ISSUE_BODY }}
${{ env.ITEM_BODY }}
```

## Steps

1. Review the issue title, issue body, and available labels
1. Review the title, body, and available labels
provided above.

2. Based on the issue title and issue body, classify the issue
2. Based on the title and body, classify the ${{ env.ITEM_TYPE }}
and choose all appropriate labels from the list of available
labels.

Expand Down Expand Up @@ -128,18 +131,18 @@ jobs:
console.log('No valid labels to apply');
}

triage-unlabeled-issues:
name: Triage Unlabeled Issues
triage-unlabeled-items:
name: Triage Unlabeled Issues and PRs
if: |
github.event_name == 'workflow_dispatch' &&
inputs.issue_number == ''
runs-on: ubuntu-latest
steps:
- name: Find and dispatch triage for unlabeled issues
- name: Find and dispatch triage for unlabeled items
uses: actions/github-script@v8
with:
script: |
// Get all open issues
// Get all open issues (includes PRs)
const issues = await github.paginate(
github.rest.issues.listForRepo,
{
Expand All @@ -150,27 +153,28 @@ jobs:
}
);

console.log(`Found ${issues.length} open issues`);
console.log(`Found ${issues.length} open issues and PRs`);

// Filter issues without labels
const unlabeledIssues = issues.filter(issue =>
!issue.pull_request && issue.labels.length === 0
// Filter items without labels
const unlabeledItems = issues.filter(issue =>
issue.labels.length === 0
);

console.log(
`Found ${unlabeledIssues.length} unlabeled issues`
`Found ${unlabeledItems.length} unlabeled items`
);

if (unlabeledIssues.length === 0) {
console.log('No unlabeled issues to process');
if (unlabeledItems.length === 0) {
console.log('No unlabeled items to process');
return;
}

// Dispatch triage workflow for each unlabeled issue
for (const issue of unlabeledIssues) {
// Dispatch triage workflow for each unlabeled item
for (const item of unlabeledItems) {
const itemType = item.pull_request ? 'PR' : 'issue';
console.log(
`Dispatching triage for issue #${issue.number}: ` +
`"${issue.title}"`
`Dispatching triage for ${itemType} #${item.number}: ` +
`"${item.title}"`
);

try {
Expand All @@ -180,12 +184,12 @@ jobs:
workflow_id: 'issue-triage.yml',
ref: context.ref || 'main',
inputs: {
issue_number: issue.number.toString()
issue_number: item.number.toString()
}
});
} catch (error) {
console.error(
`Failed to dispatch triage for issue #${issue.number}: ` +
`Failed to dispatch triage for ${itemType} #${item.number}: ` +
`${error.message}`
);
}
Expand All @@ -196,8 +200,8 @@ jobs:

console.log('Finished dispatching triage workflows');

triage-single-issue:
name: Triage Single Issue
triage-single-item:
name: Triage Single Issue or PR
if: |
github.event_name == 'workflow_dispatch' &&
inputs.issue_number != ''
Expand All @@ -216,44 +220,53 @@ jobs:
const labelNames = labels.data.map(label => label.name);
return labelNames.join(', ');

- name: Get issue details
id: get-issue
- name: Get item details
id: get-item
uses: actions/github-script@v8
with:
script: |
const itemNumber = parseInt('${{ inputs.issue_number }}');

// Try to get as an issue first (works for both issues and PRs)
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt('${{ inputs.issue_number }}')
issue_number: itemNumber
});

const itemType = issue.data.pull_request ? 'pull request' : 'issue';

return {
title: issue.data.title,
body: issue.data.body || ''
body: issue.data.body || '',
type: itemType
};

- name: Set environment variables
env:
ISSUE_TITLE: ${{ fromJSON(steps.get-issue.outputs.result).title }}
ISSUE_BODY: ${{ fromJSON(steps.get-issue.outputs.result).body }}
ITEM_TITLE: ${{ fromJSON(steps.get-item.outputs.result).title }}
ITEM_BODY: ${{ fromJSON(steps.get-item.outputs.result).body }}
ITEM_TYPE: ${{ fromJSON(steps.get-item.outputs.result).type }}
LABELS_RESULT: ${{ steps.get-labels.outputs.result }}
run: |
{
echo "AVAILABLE_LABELS=${LABELS_RESULT}"
echo "ISSUE_TITLE=${ISSUE_TITLE}"
echo "ISSUE_BODY<<EOF"
echo "${ISSUE_BODY}"
echo "ITEM_TITLE=${ITEM_TITLE}"
echo "ITEM_TYPE=${ITEM_TYPE}"
echo "ITEM_BODY<<EOF"
echo "${ITEM_BODY}"
echo "EOF"
} >> "$GITHUB_ENV"

- name: Analyze issue with AI
- name: Analyze with AI
id: ai-triage
uses: actions/ai-inference@v2
with:
prompt: |
## Role

You are an issue triage assistant. Analyze the current GitHub
issue and identify the most appropriate existing labels. Use the
You are an issue and pull request triage assistant. Analyze the current GitHub
${{ env.ITEM_TYPE }} and identify the most appropriate existing labels. Use the
available tools to gather information; do not ask for information
to be provided.

Expand All @@ -272,22 +285,22 @@ jobs:
${{ env.AVAILABLE_LABELS }}
```

**Issue Title**:
**Title**:
```
${{ env.ISSUE_TITLE }}
${{ env.ITEM_TITLE }}
```

**Issue Body**:
**Body**:
```
${{ env.ISSUE_BODY }}
${{ env.ITEM_BODY }}
```

## Steps

1. Review the issue title, issue body, and available labels
1. Review the title, body, and available labels
provided above.

2. Based on the issue title and issue body, classify the issue
2. Based on the title and body, classify the ${{ env.ITEM_TYPE }}
and choose all appropriate labels from the list of available
labels.

Expand All @@ -302,11 +315,11 @@ jobs:
uses: actions/github-script@v8
env:
AI_RESPONSE: ${{ steps.ai-triage.outputs.response }}
ISSUE_NUMBER: ${{ inputs.issue_number }}
ITEM_NUMBER: ${{ inputs.issue_number }}
with:
script: |
const response = process.env.AI_RESPONSE;
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const itemNumber = parseInt(process.env.ITEM_NUMBER);

if (!response || response.trim() === '') {
console.log('No labels selected by AI');
Expand All @@ -322,7 +335,7 @@ jobs:
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
issue_number: itemNumber,
labels: labels
});
} else {
Expand Down