#!/usr/bin/env bash # Attache des fichiers à une release Gitea, de façon idempotente (re-run friendly). # # Usage : attach-release-assets.sh # Env : RELEASE_TOKEN (token Gitea avec write:repository), GITHUB_SERVER_URL, GITHUB_REPOSITORY. # # Partagé par tous les jobs de release desktop et par le VSIX : la logique était dupliquée, et toute # correction devait être faite trois fois. set -uo pipefail tag="${1:?tag manquant}" release_name="${2:?nom de release manquant}" shift 2 # Token ABSENT : cas légitime (fork, run sans secret) → on sort proprement. # Token PRÉSENT mais refusé par l'API : anomalie, on doit ÉCHOUER. Sinon le job reste vert alors # qu'aucun asset n'est attaché et qu'aucune release n'est créée, ce qui s'est produit avec un token # expiré : trois workflows « réussis » et zéro fichier publié. if [ -z "${RELEASE_TOKEN:-}" ]; then echo "::notice::RELEASE_TOKEN absent, aucun asset attaché (les artefacts du run restent disponibles)." exit 0 fi api="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" auth="Authorization: token ${RELEASE_TOKEN}" body=$(mktemp) trap 'rm -f "$body"' EXIT # Lecture d'un champ JSON TOLÉRANTE : une réponse vide ou non-JSON (401, 403, 404) doit donner une # chaîne vide, pas une pile d'appels Node. Sans ça, deux `SyntaxError: Unexpected end of JSON input` # s'affichaient avant le vrai message d'erreur et noyaient le diagnostic. json_field() { node -e "let s='';process.stdin.on('data',(d)=>{s+=d}).on('end',()=>{try{const o=JSON.parse(s);const v=o?.[process.argv[1]];process.stdout.write(v==null?'':String(v))}catch{process.stdout.write('')}})" "$1" } # `curl` silencieux qui écrit le corps dans $body et renvoie le code HTTP sur stdout. http_call() { curl -sS -o "$body" -w '%{http_code}' "$@" } # --- résolution de la release (existante, sinon création) ------------------------------------- code=$(http_call -H "$auth" "${api}/releases/tags/${tag}") release_id=$(json_field id < "$body") if [ -z "$release_id" ]; then # 401/403 sur une simple lecture : inutile de tenter la création, le token est en cause. case "$code" in 401) echo "::error::le token de release est refusé (HTTP 401) : il est invalide, révoqué ou expiré." echo "::error::régénérer un token Gitea et mettre à jour le secret NPM_TOKEN du dépôt." exit 1 ;; 403) echo "::error::le token de release manque de droits (HTTP 403) sur ${GITHUB_REPOSITORY}." echo "::error::portées attendues : write:repository (releases et assets) et write:package (publication npm)." exit 1 ;; esac create_code=$(http_call -X POST -H "$auth" -H 'Content-Type: application/json' \ -d "{\"tag_name\":\"${tag}\",\"name\":\"${release_name}\"}" "${api}/releases") release_id=$(json_field id < "$body") if [ -z "$release_id" ]; then echo "::error::impossible de créer la release ${tag} (HTTP ${create_code})." echo "::error::réponse de l'API : $(head -c 300 "$body")" exit 1 fi echo "release ${tag} créée (id ${release_id})." else echo "release ${tag} trouvée (id ${release_id})." fi # --- attache des fichiers ---------------------------------------------------------------------- failed=0 for f in "$@"; do [ -f "$f" ] || continue name=$(basename "$f") # L'API Gitea refuse un asset de même nom : on supprime l'ancien pour que le dernier build gagne. http_call -H "$auth" "${api}/releases/${release_id}/assets" > /dev/null existing=$(node -e "let s='';process.stdin.on('data',(d)=>{s+=d}).on('end',()=>{try{const a=JSON.parse(s);const m=Array.isArray(a)?a.find((x)=>x.name===process.argv[1]):null;process.stdout.write(m?String(m.id):'')}catch{process.stdout.write('')}})" "$name" < "$body") if [ -n "$existing" ]; then echo "remplacement de $name (asset $existing)" http_call -X DELETE -H "$auth" "${api}/releases/${release_id}/assets/${existing}" > /dev/null fi upload_code=$(http_call -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${release_id}/assets?name=${name}") if [ "$upload_code" -ge 200 ] && [ "$upload_code" -lt 300 ]; then echo "attaché : $name" else echo "::error::échec de l'upload de ${name} (HTTP ${upload_code}) : $(head -c 200 "$body")" failed=1 fi done if [ "$failed" != "0" ]; then echo "::error::au moins un asset n'a pas pu être attaché à ${tag}." exit 1 fi echo "Assets attachés à la release ${tag}."