name: Triage Issue description: Analizza una issue con opencode e la classifica come bug o richiesta. 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: "" 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: %s\n%s:\n%s' \ "Sei un sistema di triage automatico per repository software." \ "Analizza la seguente issue e classificala con UNA delle label disponibili:" \ '- "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":"Breve analisi in italiano..."}' \ "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) 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." else LABEL=$(echo "$JSON" | jq -r '.label // "richiesta"') COMMENT=$(echo "$JSON" | jq -r '.comment // "Classificazione automatica."') fi case "$LABEL" in bug|richiesta) ;; *) echo "WARN: Label '$LABEL' sconosciuta, default a richiesta"; LABEL="richiesta" ;; esac echo "label=$LABEL" >> "$GITHUB_OUTPUT" { echo "comment<> "$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 COMMENT_JSON=$(jq -n --arg body "$COMMENT" '{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"