Skip to content

triage-issue-1302

triage-issue-1302 #63

Workflow file for this run

name: issue-triage
run-name: triage-issue-${{ github.event.issue.number || inputs.issue_number }}
# Triages every incoming issue on open and edit: closes issues that skip every template (free, no
# LLM call), then runs an LLM based substantiation, template-completeness, and noise check on the
# rest.
# Both jobs apply immediately; a manual run stays dry only if dry_run is set to true.
on: # yamllint disable-line rule:truthy
issues:
types: [opened, edited]
workflow_dispatch:
inputs:
issue_number:
description: 'Number of an existing issue to triage.'
required: true
type: string
dry_run:
description: 'Report the decision only, do not touch the issue.'
required: false
type: boolean
default: false
# One run per issue, so a burst of edits cannot race on the same comment or label.
concurrency:
group: issue-triage-${{ github.event.issue.number || inputs.issue_number }}
cancel-in-progress: true
permissions:
contents: read
issues: write
env:
MARKER: '<!-- gdunit4-issue-triage -->'
UNVERIFIABLE_LABEL: 'triage:failed'
PASSED_LABEL: 'triage:passed'
LLM_MODEL: 'gemini-3.5-flash'
MIN_CONFIDENCE: '0.8'
jobs:
check-template-usage:
name: Check Template Usage
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
bypass: ${{ steps.verdict.outputs.bypass }}
number: ${{ steps.resolve.outputs.number }}
state: ${{ steps.resolve.outputs.state }}
template-name: ${{ steps.resolve.outputs.template-name }}
required-ids: ${{ steps.resolve.outputs.required-ids }}
steps:
- name: Checkout GdUnit Repository
uses: actions/checkout@v7
- name: Resolve Issue Template
id: resolve
uses: ./.github/actions/resolve-issue-template
with:
issue-number: ${{ github.event.issue.number || inputs.issue_number }}
- name: Determine Triage Verdict
id: verdict
shell: bash
env:
TEMPLATE_NAME: ${{ steps.resolve.outputs.template-name }}
run: |
set -euo pipefail
if [ -z "$TEMPLATE_NAME" ]; then
echo "bypass=true" >> "$GITHUB_OUTPUT"
else
echo "bypass=false" >> "$GITHUB_OUTPUT"
fi
- name: Reject Bypassed Issue
if: steps.verdict.outputs.bypass == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
NUMBER: ${{ steps.resolve.outputs.number }}
ISSUE_STATE: ${{ steps.resolve.outputs.state }}
EVENT_NAME: ${{ github.event_name }}
INPUT_DRY_RUN: ${{ inputs.dry_run }}
run: |
set -euo pipefail
# A manual run follows its own dry_run input. Event driven runs always apply.
DRY_RUN='false'
if [ "$EVENT_NAME" = 'workflow_dispatch' ]; then
DRY_RUN="$INPUT_DRY_RUN"
fi
close='false'
if [ "$ISSUE_STATE" = 'open' ]; then
close='true'
fi
{
echo "$MARKER"
echo
echo '## This issue was closed by automated triage'
echo
echo 'This issue was created without going through one of the provided issue templates, most'
echo 'commonly by filing it directly through the API rather than the "New issue" page. The'
echo 'templates ask for exactly the information a maintainer needs to act on a report.'
echo
echo 'Please open a new issue using one of the templates offered on the "New issue" page.'
} > triage/comment.md
{
echo "## Issue triage for #$NUMBER"
echo
if [ "$DRY_RUN" = 'true' ]; then
echo 'Mode: **DRY RUN, nothing was written**'
else
echo 'Mode: **applied**'
fi
echo
echo 'Decision: the issue was not filed through one of the provided issue templates'
echo
echo "- issue closed: $close"
echo
echo '<details><summary>Triage comment</summary>'
echo
cat triage/comment.md
echo
echo '</details>'
} >> "$GITHUB_STEP_SUMMARY"
if [ "$DRY_RUN" = 'true' ]; then
exit 0
fi
# One sticky comment per issue, updated in place, so repeated runs never flood the thread.
comment_id=$(gh api --paginate "repos/$GITHUB_REPOSITORY/issues/$NUMBER/comments" \
--jq "[.[] | select(.body | contains(\"$MARKER\")) | .id] | first // empty")
jq -n --rawfile body triage/comment.md '{body: $body}' > triage/comment.json
if [ -z "$comment_id" ]; then
gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$NUMBER/comments" --input triage/comment.json
else
gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$comment_id" --input triage/comment.json
fi
if [ "$close" = 'true' ]; then
gh issue close "$NUMBER" --repo "$GITHUB_REPOSITORY" --reason 'not planned'
fi
llm-review:
name: LLM Review
needs: check-template-usage
if: needs.check-template-usage.outputs.bypass != 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout GdUnit Repository
uses: actions/checkout@v7
- name: Run LLM Issue Review
uses: ./.github/actions/llm-issue-review
with:
issue-number: ${{ needs.check-template-usage.outputs.number }}
issue-state: ${{ needs.check-template-usage.outputs.state }}
template-name: ${{ needs.check-template-usage.outputs.template-name }}
required-ids: ${{ needs.check-template-usage.outputs.required-ids }}
dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || 'false' }}
llm-api-key: ${{ secrets.LLM_API_KEY }}
llm-model: ${{ env.LLM_MODEL }}
min-confidence: ${{ env.MIN_CONFIDENCE }}
marker: ${{ env.MARKER }}
unverifiable-label: ${{ env.UNVERIFIABLE_LABEL }}
passed-label: ${{ env.PASSED_LABEL }}