From b72e25e1c5c9dbe74f962464bdc1f5935c2d38bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:31:42 +0000 Subject: [PATCH 1/5] Initial plan From 3d27ec6700334f36fd7a8de9a9c19ee90f7c5ff2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:06:05 +0000 Subject: [PATCH 2/5] Add PR triage workflows for auto-labelling Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- .github/workflows/pr-triage.yml | 18 ++ .github/workflows/reusable-pr-triage.yml | 330 +++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 .github/workflows/pr-triage.yml create mode 100644 .github/workflows/reusable-pr-triage.yml diff --git a/.github/workflows/pr-triage.yml b/.github/workflows/pr-triage.yml new file mode 100644 index 0000000..226f474 --- /dev/null +++ b/.github/workflows/pr-triage.yml @@ -0,0 +1,18 @@ +--- +name: PR Triage + +'on': + pull_request: + types: [opened] + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to triage (leave empty to process all)' + required: false + type: string + +jobs: + pr-triage: + uses: wp-cli/.github/.github/workflows/reusable-pr-triage.yml@main + with: + pr_number: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} diff --git a/.github/workflows/reusable-pr-triage.yml b/.github/workflows/reusable-pr-triage.yml new file mode 100644 index 0000000..6bf3ef6 --- /dev/null +++ b/.github/workflows/reusable-pr-triage.yml @@ -0,0 +1,330 @@ +--- +name: PR Triage + +'on': + workflow_call: + inputs: + pr_number: + description: 'PR number to triage (leave empty to process all)' + required: false + type: string + +permissions: + pull-requests: write + contents: read + models: read + +jobs: + triage-new-pr: + name: Triage New PR + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + runs-on: ubuntu-latest + steps: + - name: Get available labels + id: get-labels + uses: actions/github-script@v8 + with: + script: | + const labels = await github.rest.issues.listLabelsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + const labelNames = labels.data.map(label => label.name); + return labelNames.join(', '); + + - name: Set environment variables + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + LABELS_RESULT: ${{ steps.get-labels.outputs.result }} + run: | + { + echo "AVAILABLE_LABELS=${LABELS_RESULT}" + echo "PR_TITLE=${PR_TITLE}" + echo "PR_BODY<> "$GITHUB_ENV" + + - name: Analyze PR with AI + id: ai-triage + uses: actions/ai-inference@v2 + with: + prompt: | + ## Role + + You are a pull request triage assistant. Analyze the current GitHub + pull request and identify the most appropriate existing labels. Use the + available tools to gather information; do not ask for information + to be provided. + + ## Guidelines + + - Only use labels that are from the list of available labels. + - You can choose multiple labels to apply. + - When generating shell commands, you **MUST NOT** use command + substitution with `$(...)`, `<(...)`, or `>(...)`. This is a + security measure to prevent unintended command execution. + + ## Input Data + + **Available Labels** (comma-separated): + ``` + ${{ env.AVAILABLE_LABELS }} + ``` + + **PR Title**: + ``` + ${{ env.PR_TITLE }} + ``` + + **PR Body**: + ``` + ${{ env.PR_BODY }} + ``` + + ## Steps + + 1. Review the PR title, PR body, and available labels + provided above. + + 2. Based on the PR title and PR body, classify the pull request + and choose all appropriate labels from the list of available + labels. + + 3. Return only the selected labels as a comma-separated list, + with no additional text or explanation. For example: + ``` + label1, label2, label3 + ``` + + - name: Apply labels + if: steps.ai-triage.outputs.response != '' + uses: actions/github-script@v8 + env: + AI_RESPONSE: ${{ steps.ai-triage.outputs.response }} + with: + script: | + const response = process.env.AI_RESPONSE; + if (!response || response.trim() === '') { + console.log('No labels selected by AI'); + return; + } + + const labels = response.replaceAll('```', '').split(',') + .map(l => l.trim()) + .filter(l => l.length > 0); + + if (labels.length > 0) { + console.log(`Applying labels: ${labels.join(', ')}`); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: labels + }); + } else { + console.log('No valid labels to apply'); + } + + triage-unlabeled-prs: + name: Triage Unlabeled PRs + if: | + github.event_name == 'workflow_dispatch' && + inputs.pr_number == '' + runs-on: ubuntu-latest + steps: + - name: Find and dispatch triage for unlabeled PRs + uses: actions/github-script@v8 + with: + script: | + // Get all open pull requests + const prs = await github.paginate( + github.rest.pulls.list, + { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100 + } + ); + + console.log(`Found ${prs.length} open pull requests`); + + // Filter PRs without labels + const unlabeledPRs = prs.filter(pr => + pr.labels.length === 0 + ); + + console.log( + `Found ${unlabeledPRs.length} unlabeled pull requests` + ); + + if (unlabeledPRs.length === 0) { + console.log('No unlabeled pull requests to process'); + return; + } + + // Dispatch triage workflow for each unlabeled PR + for (const pr of unlabeledPRs) { + console.log( + `Dispatching triage for PR #${pr.number}: ` + + `"${pr.title}"` + ); + + try { + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'pr-triage.yml', + ref: context.ref || 'main', + inputs: { + pr_number: pr.number.toString() + } + }); + } catch (error) { + console.error( + `Failed to dispatch triage for PR #${pr.number}: ` + + `${error.message}` + ); + } + + // Add a small delay to avoid rate limiting + await new Promise(resolve => setTimeout(resolve, 100)); + } + + console.log('Finished dispatching triage workflows'); + + triage-single-pr: + name: Triage Single PR + if: | + github.event_name == 'workflow_dispatch' && + inputs.pr_number != '' + runs-on: ubuntu-latest + steps: + - name: Get available labels + id: get-labels + uses: actions/github-script@v8 + with: + script: | + const labels = await github.rest.issues.listLabelsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + const labelNames = labels.data.map(label => label.name); + return labelNames.join(', '); + + - name: Get PR details + id: get-pr + uses: actions/github-script@v8 + with: + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: parseInt('${{ inputs.pr_number }}') + }); + return { + title: pr.data.title, + body: pr.data.body || '' + }; + + - name: Set environment variables + env: + PR_TITLE: ${{ fromJSON(steps.get-pr.outputs.result).title }} + PR_BODY: ${{ fromJSON(steps.get-pr.outputs.result).body }} + LABELS_RESULT: ${{ steps.get-labels.outputs.result }} + run: | + { + echo "AVAILABLE_LABELS=${LABELS_RESULT}" + echo "PR_TITLE=${PR_TITLE}" + echo "PR_BODY<> "$GITHUB_ENV" + + - name: Analyze PR with AI + id: ai-triage + uses: actions/ai-inference@v2 + with: + prompt: | + ## Role + + You are a pull request triage assistant. Analyze the current GitHub + pull request and identify the most appropriate existing labels. Use the + available tools to gather information; do not ask for information + to be provided. + + ## Guidelines + + - Only use labels that are from the list of available labels. + - You can choose multiple labels to apply. + - When generating shell commands, you **MUST NOT** use command + substitution with `$(...)`, `<(...)`, or `>(...)`. This is a + security measure to prevent unintended command execution. + + ## Input Data + + **Available Labels** (comma-separated): + ``` + ${{ env.AVAILABLE_LABELS }} + ``` + + **PR Title**: + ``` + ${{ env.PR_TITLE }} + ``` + + **PR Body**: + ``` + ${{ env.PR_BODY }} + ``` + + ## Steps + + 1. Review the PR title, PR body, and available labels + provided above. + + 2. Based on the PR title and PR body, classify the pull request + and choose all appropriate labels from the list of available + labels. + + 3. Return only the selected labels as a comma-separated list, + with no additional text or explanation. For example: + ``` + label1, label2, label3 + ``` + + - name: Apply labels + if: steps.ai-triage.outputs.response != '' + uses: actions/github-script@v8 + env: + AI_RESPONSE: ${{ steps.ai-triage.outputs.response }} + PR_NUMBER: ${{ inputs.pr_number }} + with: + script: | + const response = process.env.AI_RESPONSE; + const prNumber = parseInt(process.env.PR_NUMBER); + + if (!response || response.trim() === '') { + console.log('No labels selected by AI'); + return; + } + + const labels = response.replaceAll('```', '').split(',') + .map(l => l.trim()) + .filter(l => l.length > 0); + + if (labels.length > 0) { + console.log(`Applying labels: ${labels.join(', ')}`); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: labels + }); + } else { + console.log('No valid labels to apply'); + } From 14f66479f328ac0a341c7738b8f4e7917aa4a337 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:07:56 +0000 Subject: [PATCH 3/5] Fix PR number handling in triage workflow Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- .github/workflows/pr-triage.yml | 7 ++++++- .github/workflows/reusable-pr-triage.yml | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-triage.yml b/.github/workflows/pr-triage.yml index 226f474..69278ec 100644 --- a/.github/workflows/pr-triage.yml +++ b/.github/workflows/pr-triage.yml @@ -15,4 +15,9 @@ jobs: pr-triage: uses: wp-cli/.github/.github/workflows/reusable-pr-triage.yml@main with: - pr_number: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} + pr_number: >- + ${{ + github.event_name == 'workflow_dispatch' && + inputs.pr_number || + github.event.pull_request.number + }} diff --git a/.github/workflows/reusable-pr-triage.yml b/.github/workflows/reusable-pr-triage.yml index 6bf3ef6..9f8bfa7 100644 --- a/.github/workflows/reusable-pr-triage.yml +++ b/.github/workflows/reusable-pr-triage.yml @@ -104,9 +104,12 @@ jobs: uses: actions/github-script@v8 env: AI_RESPONSE: ${{ steps.ai-triage.outputs.response }} + PR_NUMBER: ${{ github.event.pull_request.number }} with: script: | const response = process.env.AI_RESPONSE; + const prNumber = parseInt(process.env.PR_NUMBER); + if (!response || response.trim() === '') { console.log('No labels selected by AI'); return; @@ -121,7 +124,7 @@ jobs: await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: context.issue.number, + issue_number: prNumber, labels: labels }); } else { From d98b38a2795c40564d3597ecf1c2be54b6a1c428 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:35:26 +0000 Subject: [PATCH 4/5] Refactor: Reuse issue triage workflow for PRs instead of duplicating Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- .github/workflows/issue-triage.yml | 13 +- .github/workflows/pr-triage.yml | 23 -- .github/workflows/reusable-issue-triage.yml | 131 ++++---- .github/workflows/reusable-pr-triage.yml | 333 -------------------- 4 files changed, 82 insertions(+), 418 deletions(-) delete mode 100644 .github/workflows/pr-triage.yml delete mode 100644 .github/workflows/reusable-pr-triage.yml diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 634607e..7c03bab 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -1,13 +1,15 @@ --- -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 @@ -15,4 +17,9 @@ 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.issue.number + }} diff --git a/.github/workflows/pr-triage.yml b/.github/workflows/pr-triage.yml deleted file mode 100644 index 69278ec..0000000 --- a/.github/workflows/pr-triage.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: PR Triage - -'on': - pull_request: - types: [opened] - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to triage (leave empty to process all)' - required: false - type: string - -jobs: - pr-triage: - uses: wp-cli/.github/.github/workflows/reusable-pr-triage.yml@main - with: - pr_number: >- - ${{ - github.event_name == 'workflow_dispatch' && - inputs.pr_number || - github.event.pull_request.number - }} diff --git a/.github/workflows/reusable-issue-triage.yml b/.github/workflows/reusable-issue-triage.yml index 6f255fb..8c040dd 100644 --- a/.github/workflows/reusable-issue-triage.yml +++ b/.github/workflows/reusable-issue-triage.yml @@ -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 @@ -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<> "$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. @@ -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. @@ -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, { @@ -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 { @@ -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}` ); } @@ -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 != '' @@ -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<> "$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. @@ -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. @@ -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'); @@ -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 { diff --git a/.github/workflows/reusable-pr-triage.yml b/.github/workflows/reusable-pr-triage.yml deleted file mode 100644 index 9f8bfa7..0000000 --- a/.github/workflows/reusable-pr-triage.yml +++ /dev/null @@ -1,333 +0,0 @@ ---- -name: PR Triage - -'on': - workflow_call: - inputs: - pr_number: - description: 'PR number to triage (leave empty to process all)' - required: false - type: string - -permissions: - pull-requests: write - contents: read - models: read - -jobs: - triage-new-pr: - name: Triage New PR - if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' - runs-on: ubuntu-latest - steps: - - name: Get available labels - id: get-labels - uses: actions/github-script@v8 - with: - script: | - const labels = await github.rest.issues.listLabelsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - per_page: 100 - }); - const labelNames = labels.data.map(label => label.name); - return labelNames.join(', '); - - - name: Set environment variables - env: - PR_TITLE: ${{ github.event.pull_request.title }} - PR_BODY: ${{ github.event.pull_request.body }} - LABELS_RESULT: ${{ steps.get-labels.outputs.result }} - run: | - { - echo "AVAILABLE_LABELS=${LABELS_RESULT}" - echo "PR_TITLE=${PR_TITLE}" - echo "PR_BODY<> "$GITHUB_ENV" - - - name: Analyze PR with AI - id: ai-triage - uses: actions/ai-inference@v2 - with: - prompt: | - ## Role - - You are a pull request triage assistant. Analyze the current GitHub - pull request and identify the most appropriate existing labels. Use the - available tools to gather information; do not ask for information - to be provided. - - ## Guidelines - - - Only use labels that are from the list of available labels. - - You can choose multiple labels to apply. - - When generating shell commands, you **MUST NOT** use command - substitution with `$(...)`, `<(...)`, or `>(...)`. This is a - security measure to prevent unintended command execution. - - ## Input Data - - **Available Labels** (comma-separated): - ``` - ${{ env.AVAILABLE_LABELS }} - ``` - - **PR Title**: - ``` - ${{ env.PR_TITLE }} - ``` - - **PR Body**: - ``` - ${{ env.PR_BODY }} - ``` - - ## Steps - - 1. Review the PR title, PR body, and available labels - provided above. - - 2. Based on the PR title and PR body, classify the pull request - and choose all appropriate labels from the list of available - labels. - - 3. Return only the selected labels as a comma-separated list, - with no additional text or explanation. For example: - ``` - label1, label2, label3 - ``` - - - name: Apply labels - if: steps.ai-triage.outputs.response != '' - uses: actions/github-script@v8 - env: - AI_RESPONSE: ${{ steps.ai-triage.outputs.response }} - PR_NUMBER: ${{ github.event.pull_request.number }} - with: - script: | - const response = process.env.AI_RESPONSE; - const prNumber = parseInt(process.env.PR_NUMBER); - - if (!response || response.trim() === '') { - console.log('No labels selected by AI'); - return; - } - - const labels = response.replaceAll('```', '').split(',') - .map(l => l.trim()) - .filter(l => l.length > 0); - - if (labels.length > 0) { - console.log(`Applying labels: ${labels.join(', ')}`); - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: labels - }); - } else { - console.log('No valid labels to apply'); - } - - triage-unlabeled-prs: - name: Triage Unlabeled PRs - if: | - github.event_name == 'workflow_dispatch' && - inputs.pr_number == '' - runs-on: ubuntu-latest - steps: - - name: Find and dispatch triage for unlabeled PRs - uses: actions/github-script@v8 - with: - script: | - // Get all open pull requests - const prs = await github.paginate( - github.rest.pulls.list, - { - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - per_page: 100 - } - ); - - console.log(`Found ${prs.length} open pull requests`); - - // Filter PRs without labels - const unlabeledPRs = prs.filter(pr => - pr.labels.length === 0 - ); - - console.log( - `Found ${unlabeledPRs.length} unlabeled pull requests` - ); - - if (unlabeledPRs.length === 0) { - console.log('No unlabeled pull requests to process'); - return; - } - - // Dispatch triage workflow for each unlabeled PR - for (const pr of unlabeledPRs) { - console.log( - `Dispatching triage for PR #${pr.number}: ` + - `"${pr.title}"` - ); - - try { - await github.rest.actions.createWorkflowDispatch({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: 'pr-triage.yml', - ref: context.ref || 'main', - inputs: { - pr_number: pr.number.toString() - } - }); - } catch (error) { - console.error( - `Failed to dispatch triage for PR #${pr.number}: ` + - `${error.message}` - ); - } - - // Add a small delay to avoid rate limiting - await new Promise(resolve => setTimeout(resolve, 100)); - } - - console.log('Finished dispatching triage workflows'); - - triage-single-pr: - name: Triage Single PR - if: | - github.event_name == 'workflow_dispatch' && - inputs.pr_number != '' - runs-on: ubuntu-latest - steps: - - name: Get available labels - id: get-labels - uses: actions/github-script@v8 - with: - script: | - const labels = await github.rest.issues.listLabelsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - per_page: 100 - }); - const labelNames = labels.data.map(label => label.name); - return labelNames.join(', '); - - - name: Get PR details - id: get-pr - uses: actions/github-script@v8 - with: - script: | - const pr = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: parseInt('${{ inputs.pr_number }}') - }); - return { - title: pr.data.title, - body: pr.data.body || '' - }; - - - name: Set environment variables - env: - PR_TITLE: ${{ fromJSON(steps.get-pr.outputs.result).title }} - PR_BODY: ${{ fromJSON(steps.get-pr.outputs.result).body }} - LABELS_RESULT: ${{ steps.get-labels.outputs.result }} - run: | - { - echo "AVAILABLE_LABELS=${LABELS_RESULT}" - echo "PR_TITLE=${PR_TITLE}" - echo "PR_BODY<> "$GITHUB_ENV" - - - name: Analyze PR with AI - id: ai-triage - uses: actions/ai-inference@v2 - with: - prompt: | - ## Role - - You are a pull request triage assistant. Analyze the current GitHub - pull request and identify the most appropriate existing labels. Use the - available tools to gather information; do not ask for information - to be provided. - - ## Guidelines - - - Only use labels that are from the list of available labels. - - You can choose multiple labels to apply. - - When generating shell commands, you **MUST NOT** use command - substitution with `$(...)`, `<(...)`, or `>(...)`. This is a - security measure to prevent unintended command execution. - - ## Input Data - - **Available Labels** (comma-separated): - ``` - ${{ env.AVAILABLE_LABELS }} - ``` - - **PR Title**: - ``` - ${{ env.PR_TITLE }} - ``` - - **PR Body**: - ``` - ${{ env.PR_BODY }} - ``` - - ## Steps - - 1. Review the PR title, PR body, and available labels - provided above. - - 2. Based on the PR title and PR body, classify the pull request - and choose all appropriate labels from the list of available - labels. - - 3. Return only the selected labels as a comma-separated list, - with no additional text or explanation. For example: - ``` - label1, label2, label3 - ``` - - - name: Apply labels - if: steps.ai-triage.outputs.response != '' - uses: actions/github-script@v8 - env: - AI_RESPONSE: ${{ steps.ai-triage.outputs.response }} - PR_NUMBER: ${{ inputs.pr_number }} - with: - script: | - const response = process.env.AI_RESPONSE; - const prNumber = parseInt(process.env.PR_NUMBER); - - if (!response || response.trim() === '') { - console.log('No labels selected by AI'); - return; - } - - const labels = response.replaceAll('```', '').split(',') - .map(l => l.trim()) - .filter(l => l.length > 0); - - if (labels.length > 0) { - console.log(`Applying labels: ${labels.join(', ')}`); - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: labels - }); - } else { - console.log('No valid labels to apply'); - } From 035f1af7b0b7637fa5042a5a2b9c3cbfa6612366 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:36:36 +0000 Subject: [PATCH 5/5] Fix conditional logic in issue-triage.yml for pull_request events Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- .github/workflows/issue-triage.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 7c03bab..cfd68e1 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -19,7 +19,8 @@ jobs: with: issue_number: >- ${{ - github.event_name == 'workflow_dispatch' && inputs.issue_number || - github.event_name == 'pull_request' && github.event.pull_request.number || - github.event.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) || + '' }}