mirror of
https://github.com/rsyslog/rsyslog.git
synced 2026-08-24 19:24:14 +02:00
186 lines
7.9 KiB
YAML
186 lines
7.9 KiB
YAML
name: Auto-label Issues with Gemini
|
|
|
|
on:
|
|
issues:
|
|
types: [opened]
|
|
workflow_dispatch:
|
|
inputs:
|
|
issue_number:
|
|
description: 'Issue Number (for manual testing of existing issue)'
|
|
required: false
|
|
type: number
|
|
issue_title:
|
|
description: 'Issue Title (for manual testing)'
|
|
required: false
|
|
default: ''
|
|
issue_body:
|
|
description: 'Issue Body (for manual testing)'
|
|
required: false
|
|
default: ''
|
|
|
|
jobs:
|
|
label_issue:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
issues: write # Grant write permission for issues to this job
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.x'
|
|
|
|
- name: Install Google Generative AI client library
|
|
run: pip install google-generativeai
|
|
|
|
- name: Determine Issue Content and Number
|
|
id: get_issue_context
|
|
shell: bash # Explicitly set shell to bash for robust string handling
|
|
env:
|
|
# Define your available labels here, separated by commas
|
|
AVAILABLE_LABELS: "bug,feature,documentation,question,enhancement,performance,security,configuration"
|
|
run: |
|
|
# Initialize variables
|
|
ISSUE_NUMBER=""
|
|
ISSUE_TITLE=""
|
|
ISSUE_BODY=""
|
|
|
|
# Determine context based on trigger event
|
|
if [[ "${{ github.event_name }}" == "issues" ]]; then
|
|
ISSUE_NUMBER="${{ github.event.issue.number }}"
|
|
ISSUE_TITLE="${{ github.event.issue.title }}"
|
|
ISSUE_BODY="${{ github.event.issue.body }}"
|
|
echo "Triggered by issue creation event."
|
|
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
# For manual dispatch, use inputs
|
|
ISSUE_NUMBER="${{ github.event.inputs.issue_number }}"
|
|
ISSUE_TITLE="${{ github.event.inputs.issue_title }}"
|
|
ISSUE_BODY="${{ github.event.inputs.issue_body }}"
|
|
echo "Triggered by manual workflow_dispatch."
|
|
fi
|
|
|
|
# Set output variables for use in subsequent steps using GITHUB_OUTPUT file
|
|
echo "ISSUE_NUMBER=${ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
|
|
echo "ISSUE_TITLE=${ISSUE_TITLE}" >> "$GITHUB_OUTPUT"
|
|
|
|
# --- FIX for multiline ISSUE_BODY using EOF delimiter ---
|
|
echo "ISSUE_BODY<<EOF_BODY_TEXT" >> "$GITHUB_OUTPUT"
|
|
echo "${ISSUE_BODY}" >> "$GITHUB_OUTPUT"
|
|
echo "EOF_BODY_TEXT" >> "$GITHUB_OUTPUT"
|
|
# --------------------------------------------------------
|
|
|
|
echo "AVAILABLE_LABELS=${{ env.AVAILABLE_LABELS }}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Call Gemini API to suggest label
|
|
id: gemini_call
|
|
env:
|
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
# Use outputs from the previous step as environment variables for the Python script
|
|
ISSUE_TITLE: ${{ steps.get_issue_context.outputs.ISSUE_TITLE }}
|
|
ISSUE_BODY: ${{ steps.get_issue_context.outputs.ISSUE_BODY }}
|
|
AVAILABLE_LABELS: ${{ steps.get_issue_context.outputs.AVAILABLE_LABELS }}
|
|
GITHUB_OUTPUT: ${{ github.output }} # Ensure GITHUB_OUTPUT path is available to Python
|
|
run: |
|
|
python <<EOF
|
|
import google.generativeai as genai
|
|
import os
|
|
import json
|
|
|
|
api_key = os.environ.get('GEMINI_API_KEY')
|
|
if not api_key:
|
|
print("Error: GEMINI_API_KEY not found in environment variables. Exiting.")
|
|
# Ensure fallback also writes to GITHUB_OUTPUT
|
|
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
f.write("SUGGESTED_LABEL=no label\n")
|
|
exit(1) # Exit with an error code
|
|
|
|
genai.configure(api_key=api_key)
|
|
# Using gemini-2.0-flash as per your modification
|
|
model = genai.GenerativeModel('gemini-2.0-flash')
|
|
|
|
issue_title = os.environ['ISSUE_TITLE']
|
|
issue_body = os.environ['ISSUE_BODY']
|
|
available_labels = os.environ['AVAILABLE_LABELS'].split(',')
|
|
|
|
# Construct a robust prompt. Instruct it to only output the label name and choose from the list.
|
|
prompt = f"""
|
|
You are an automated issue labeling bot for the rsyslog open source project.
|
|
Based on the following GitHub issue, suggest the single most appropriate label from the list provided.
|
|
Only output the label name. Do NOT output any additional text or explanation.
|
|
You MUST choose one label from the 'Available labels' list.
|
|
|
|
Available labels: {', '.join(available_labels)}
|
|
|
|
Issue Title: {issue_title}
|
|
Issue Body:
|
|
{issue_body}
|
|
"""
|
|
|
|
suggested_label_raw = "no label" # Default fallback for API errors or unexpected responses
|
|
|
|
try:
|
|
# Add generation_config to ensure the model responds with only plain text.
|
|
response = model.generate_content(prompt, generation_config=genai.types.GenerationConfig(
|
|
response_mime_type='text/plain' # Ensure plain text output
|
|
))
|
|
suggested_label_raw = response.text.strip().lower()
|
|
|
|
# Clean and validate the suggested label against available labels (case-insensitive check)
|
|
cleaned_label = "no label" # Default if no valid match found in the list
|
|
for label in available_labels:
|
|
if suggested_label_raw == label.lower():
|
|
cleaned_label = label
|
|
break
|
|
|
|
# If Gemini suggested something not in our exact list (despite prompt instructions)
|
|
if cleaned_label == "no label":
|
|
print(f"Warning: Gemini suggested '{suggested_label_raw}', which was not an exact match in the available labels list. Defaulting to 'no label'.")
|
|
|
|
|
|
print(f"Suggested Label: {cleaned_label}")
|
|
# --- CRITICAL FIX: Write to GITHUB_OUTPUT file instead of using ##vso[task.setvariable] ---
|
|
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
f.write(f"SUGGESTED_LABEL={cleaned_label}\n")
|
|
# -----------------------------------------------------------------------------------------
|
|
|
|
except Exception as e:
|
|
print(f"Error calling Gemini API: {e}")
|
|
# Ensure fallback also writes to GITHUB_OUTPUT
|
|
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
|
f.write("SUGGESTED_LABEL=no label\n")
|
|
EOF
|
|
|
|
- name: Add label to issue
|
|
# Only attempt to add label if a valid one was suggested AND an issue number is available
|
|
if: steps.gemini_call.outputs.SUGGESTED_LABEL != 'no label' && steps.get_issue_context.outputs.ISSUE_NUMBER != ''
|
|
uses: actions/github-script@v6
|
|
with:
|
|
script: |
|
|
// Access variables directly from process.env, as they are passed in the 'env' block
|
|
const label = process.env.SUGGESTED_LABEL;
|
|
const issue_number = process.env.ISSUE_NUMBER;
|
|
|
|
// These debug lines should now show the correct 'feature' label
|
|
console.log(`DEBUG: Value of label (from process.env.SUGGESTED_LABEL): "${label}"`);
|
|
console.log(`DEBUG: Value of issue_number (from process.env.ISSUE_NUMBER): "${issue_number}"`);
|
|
|
|
console.log(`Attempting to add label "${label}" to issue #${issue_number}`);
|
|
try {
|
|
await github.rest.issues.addLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: parseInt(issue_number), // Ensure issue_number is an integer for the API call
|
|
labels: [label]
|
|
});
|
|
console.log(`Successfully added label "${label}" to issue #${issue_number}`);
|
|
} catch (error) {
|
|
console.error(`Failed to add label "${label}" to issue #${issue_number}: ${error.message}`);
|
|
}
|
|
# Pass variables as environment variables for the script to access
|
|
env:
|
|
SUGGESTED_LABEL: ${{ steps.gemini_call.outputs.SUGGESTED_LABEL }}
|
|
ISSUE_NUMBER: ${{ steps.get_issue_context.outputs.ISSUE_NUMBER }} # Pass the determined issue number
|