Skip to content

Commit 7692e85

Browse files
committed
build: automatically triage issues using Gemini API
1 parent 5fc395c commit 7692e85

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

.github/scripts/triage_issue.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import os
2+
import json
3+
import urllib.request
4+
import sys
5+
6+
def get_gemini_response(api_key, prompt):
7+
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
8+
headers = {'Content-Type': 'application/json'}
9+
data = {
10+
"contents": [{
11+
"parts": [{"text": prompt}]
12+
}],
13+
"generationConfig": {
14+
"response_mime_type": "application/json"
15+
}
16+
}
17+
18+
req = urllib.request.Request(url, data=json.dumps(data).encode('utf-8'), headers=headers)
19+
try:
20+
with urllib.request.urlopen(req) as response:
21+
res_data = json.loads(response.read().decode('utf-8'))
22+
return res_data['candidates'][0]['content']['parts'][0]['text']
23+
except Exception as e:
24+
print(f"Error calling Gemini API: {e}", file=sys.stderr)
25+
return None
26+
27+
def main():
28+
api_key = os.getenv("GEMINI_API_KEY")
29+
issue_title = os.getenv("ISSUE_TITLE")
30+
issue_body = os.getenv("ISSUE_BODY")
31+
32+
if not api_key:
33+
print("GEMINI_API_KEY not found", file=sys.stderr)
34+
sys.exit(1)
35+
36+
prompt = f"""
37+
You are an expert software engineer and triage assistant.
38+
Analyze the following GitHub Issue details and suggest appropriate labels.
39+
40+
Issue Title: {issue_title}
41+
Issue Description: {issue_body}
42+
43+
Triage Criteria:
44+
- Severity:
45+
- priority: p0: Critical issues, crashes, security vulnerabilities (specifically if it mentions "crash" or "exception").
46+
- priority: p1: Important issues that block release.
47+
- priority: p2: Normal priority bugs or improvements.
48+
- priority: p3: Minor enhancements or non-critical fixes.
49+
- priority: p4: Low priority, nice-to-have eventually.
50+
- Type:
51+
- type: docs: Documentation issues or requests.
52+
- type: typo: Mentioning typos in the codebase or UI.
53+
- type: test: Issues related to testing.
54+
- type: feature: Feature requests.
55+
- type: bug: Bug reports.
56+
- Environment:
57+
- environment: no-google-play: If the issue specifically mentions devices without Google Play services, Huawei devices, or microG.
58+
59+
Return a JSON object with a 'labels' key containing an array of suggested label names.
60+
The response MUST be valid JSON.
61+
Example: {{"labels": ["priority: p2", "type: bug"]}}
62+
"""
63+
64+
response_text = get_gemini_response(api_key, prompt)
65+
if response_text:
66+
try:
67+
# Clean up response text in case it has markdown wrapping
68+
if response_text.startswith("```json"):
69+
response_text = response_text.replace("```json", "", 1).replace("```", "", 1).strip()
70+
71+
result = json.loads(response_text)
72+
labels = result.get("labels", [])
73+
# Print labels as a comma-separated string for GitHub Actions
74+
print(",".join(labels))
75+
except Exception as e:
76+
print(f"Error parsing Gemini response: {e}", file=sys.stderr)
77+
print(f"Raw response: {response_text}", file=sys.stderr)
78+
sys.exit(1)
79+
else:
80+
sys.exit(1)
81+
82+
if __name__ == "__main__":
83+
main()

.github/workflows/triage-issue.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Issue Triage with Gemini
2+
3+
on:
4+
issues:
5+
types: [opened, edited]
6+
workflow_dispatch:
7+
inputs:
8+
title:
9+
description: 'Mock Issue Title'
10+
default: 'Test Issue'
11+
body:
12+
description: 'Mock Issue Body'
13+
default: 'This is a test issue description.'
14+
15+
jobs:
16+
triage:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
issues: write
20+
contents: read
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: '3.x'
29+
30+
- name: Run Triage Script
31+
id: run_script
32+
env:
33+
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
34+
ISSUE_TITLE: ${{ github.event.issue.title || github.event.inputs.title }}
35+
ISSUE_BODY: ${{ github.event.issue.body || github.event.inputs.body }}
36+
run: |
37+
labels=$(python .github/scripts/triage_issue.py)
38+
echo "labels=$labels" >> $GITHUB_OUTPUT
39+
40+
- name: Apply Labels
41+
if: steps.run_script.outputs.labels != ''
42+
env:
43+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
run: |
45+
# Convert comma-separated labels to gh command arguments
46+
IFS=',' read -ra ADDR <<< "${{ steps.run_script.outputs.labels }}"
47+
for i in "${ADDR[@]}"; do
48+
# Trim whitespace and only add if not empty
49+
label=$(echo "$i" | xargs)
50+
if [ -n "$label" ]; then
51+
gh issue edit ${{ github.event.issue.number }} --add-label "$label"
52+
fi
53+
done

0 commit comments

Comments
 (0)