Files
Actions/triage-issue/action.yml

184 lines
7.5 KiB
YAML

name: Triage Issue
description: "Analizza una issue con opencode: classifica, riassume, gap analisi e produce report MD."
inputs:
issue-title:
description: Titolo dell'issue.
required: true
issue-body:
description: Corpo dell'issue.
required: true
issue-number:
description: Numero dell'issue.
required: true
repository:
description: Repository in formato owner/repo.
required: true
api-token:
description: Token API Gitea.
required: true
gitea-host:
description: URL del server Gitea.
required: false
default: "https://git.incloud.ovh"
api-key:
description: API key per opencode.
required: true
model:
description: Modello AI in formato provider/model.
required: false
default: "opencode-go/deepseek-v4-flash"
outputs:
label:
description: Label attribuita (bug o richiesta).
value: ${{ steps.classifica.outputs.label }}
comment:
description: Commento di triage pubblicato.
value: ${{ steps.classifica.outputs.comment }}
runs:
using: composite
steps:
- name: Configura autenticazione opencode
shell: bash
run: |
set -euo pipefail
if ! command -v jq &> /dev/null; then
echo "jq non trovato, tentativo di installazione..."
if command -v apt-get &> /dev/null; then
apt-get update -qq && apt-get install -y -qq jq 2>&1 || true
elif command -v apk &> /dev/null; then
apk add --no-cache jq 2>&1 || true
fi
command -v jq &> /dev/null || { echo "ERRORE: impossibile installare jq."; exit 1; }
fi
mkdir -p ~/.local/share/opencode
jq -n \
--arg provider "opencode-go" \
--arg key "${{ inputs.api-key }}" \
'{($provider): {type: "api", key: $key}}' > ~/.local/share/opencode/auth.json
chmod 600 ~/.local/share/opencode/auth.json
- name: Classifica issue
id: classifica
shell: bash
run: |
set -euo pipefail
# Assicura curl (potrebbe mancare su Alpine)
if ! command -v curl &> /dev/null; then
echo "curl non trovato, tentativo di installazione..."
if command -v apt-get &> /dev/null; then
apt-get update -qq && apt-get install -y -qq curl 2>&1 || true
elif command -v apk &> /dev/null; then
apk add --no-cache curl 2>&1 || true
fi
command -v curl &> /dev/null || { echo "ERRORE: impossibile installare curl."; exit 1; }
fi
HOST="${{ inputs.gitea-host }}"
TOKEN="${{ inputs.api-token }}"
REPO="${{ inputs.repository }}"
ISSUE_NUM="${{ inputs.issue-number }}"
MODEL_ARG=()
[ -n "${{ inputs.model }}" ] && MODEL_ARG=(--model "${{ inputs.model }}")
BODY="$(echo "${{ inputs.issue-body }}" | head -c 10000)"
[ "${#BODY}" -ge 10000 ] && BODY+=$'\n... (troncato)'
printf -v PROMPT '%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s: %s\n%s:\n%s' \
"Sei un sistema di triage automatico per repository software." \
"Analizza il codice sorgente nel repository ed esamina la seguente issue." \
"Classifica con UNA delle label:" \
'- "bug": malfunzionamento, errore, crash, anomalia, comportamento inaspettato' \
'- "richiesta": nuova funzionalità, miglioramento, refactoring, ottimizzazione, o dubbio' \
"Rispondi ESCLUSIVAMENTE con un JSON valido su una SINGOLA riga, senza nessun altro testo:" \
'{"label":"bug","comment":"**Riassunto**: ...\\n\\n**Gap analisi**: codice mancante...\\n\\n**Domande aperte**:\\n1. ...","md":"# Analisi tecnica\\n\\n## Codice coinvolto\\n..."}' \
"Il campo 'comment' deve contenere: riassunto della issue, gap analisi (cosa manca rispetto al codice), domande aperte. Usa \\n per i newline." \
"Il campo 'md' deve contenere: analisi tecnica completa in formato markdown, file/moduli coinvolti, ipotesi root cause, proposta di fix. Usa \\n per i newline." \
"Titolo" "${{ inputs.issue-title }}" \
"Corpo" "$BODY"
OUTFILE="$GITHUB_WORKSPACE/opencode-triage.txt"
opencode run "$PROMPT" "${MODEL_ARG[@]}" --dangerously-skip-permissions 2>&1 | tee "$OUTFILE"
# Estrai la riga JSON dalla risposta (salta banner ANSI)
JSON_LINE=$(grep -E '^\{"label":"(bug|richiesta)","comment":' "$OUTFILE" | head -1)
JSON=""
if [ -n "$JSON_LINE" ]; then
JSON=$(echo "$JSON_LINE" | jq -c . 2>/dev/null)
fi
if [ -z "$JSON" ] || ! echo "$JSON" | jq empty 2>/dev/null; then
echo "WARN: Impossibile estrarre JSON valido, default a richiesta"
LABEL="richiesta"
COMMENT="Classificazione automatica non riuscita. Label impostata a richiesta per default."
MD_CONTENT=""
else
LABEL=$(echo "$JSON" | jq -r '.label // "richiesta"')
COMMENT=$(echo "$JSON" | jq -r '.comment // "Classificazione automatica."' | sed 's/\\n/\n/g')
MD_CONTENT=$(echo "$JSON" | jq -r '.md // ""' | sed 's/\\n/\n/g')
fi
case "$LABEL" in
bug|richiesta) ;;
*) echo "WARN: Label '$LABEL' sconosciuta, default a richiesta"; LABEL="richiesta" ;;
esac
echo "label=$LABEL" >> "$GITHUB_OUTPUT"
{
echo "comment<<EOF"
echo "$COMMENT"
echo "EOF"
} >> "$GITHUB_OUTPUT"
echo "Label determinata: $LABEL"
LABEL_ID=$(curl -sS -f "$HOST/api/v1/repos/$REPO/labels" \
-H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
2>/dev/null | jq -r ".[] | select(.name==\"$LABEL\") | .id" | head -1)
if [ -n "$LABEL_ID" ]; then
curl -sS -X PUT "$HOST/api/v1/repos/$REPO/issues/$ISSUE_NUM/labels" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"labels\":[$LABEL_ID]}" 2>/dev/null && \
echo "Label '$LABEL' applicata" || \
echo "WARN: Impossibile applicare la label '$LABEL'"
else
echo "WARN: Label '$LABEL' non trovata nel repo. Creala manualmente o passa un token con permessi."
fi
# Carica il file MD come asset (prima del commento per poterlo linkare)
LINK_MD=""
if [ -n "$MD_CONTENT" ] && [ "$MD_CONTENT" != "null" ]; then
MD_FILE="/tmp/triage-issue-${ISSUE_NUM}.md"
printf '%s\n' "$MD_CONTENT" > "$MD_FILE"
ASSET_RESP=$(curl -sS -X POST "$HOST/api/v1/repos/$REPO/issues/$ISSUE_NUM/assets" \
-H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
-F "attachment=@${MD_FILE};filename=triage-issue-${ISSUE_NUM}.md" 2>/dev/null)
ASSET_URL=$(echo "$ASSET_RESP" | jq -r '.browser_download_url // empty' 2>/dev/null)
if [ -n "$ASSET_URL" ] && [ "$ASSET_URL" != "null" ]; then
LINK_MD="
---
📎 **Analisi tecnica completa**: [triage-issue-${ISSUE_NUM}.md](${ASSET_URL})"
echo "Asset MD caricato: $ASSET_URL"
else
echo "WARN: Impossibile caricare il file MD come asset"
fi
fi
COMMENT_BODY="${COMMENT}${LINK_MD}"
COMMENT_JSON=$(jq -n --arg body "$COMMENT_BODY" '{body: $body}')
curl -sS -X POST "$HOST/api/v1/repos/$REPO/issues/$ISSUE_NUM/comments" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "$COMMENT_JSON" 2>/dev/null && \
echo "Commento pubblicato sull'issue #$ISSUE_NUM" || \
echo "WARN: Impossibile pubblicare il commento"