En Windows el stdout de Python defaultea a cp1252 y crashea con
UnicodeEncodeError al imprimir literales no-ASCII (e.g. el ✓ del print
de éxito de pr-create.sh). El sintoma era que el PR se creaba OK pero
el script terminaba con exit 1 por el crash del print posterior.
Agrego export PYTHONIOENCODING=utf-8 después de set -euo pipefail en
los 10 scripts que invocan python (todos menos query.sh). Cubre tanto
las invocaciones inline como futuras sin tener que acordarse caso por
caso. Mantiene los literales unicode existentes (✓, →, ─, ⚠️).
128 lines
3.7 KiB
Bash
128 lines
3.7 KiB
Bash
#!/usr/bin/env bash
|
|
# gitea skill — listar repos de un owner (user o org).
|
|
#
|
|
# Uso:
|
|
# repo-list.sh [--owner <user|org>] [--limit N] [--sort newest|oldest|alpha|size]
|
|
#
|
|
# Default owner: el bot user ($GITEA_BOT_USER del .env).
|
|
# Default limit: 30. Default sort: newest.
|
|
#
|
|
# El endpoint cambia según el tipo de owner:
|
|
# - bot user: GET /users/{user}/repos (devuelve todos los del bot,
|
|
# incluyendo privados, porque está autenticado como ese user)
|
|
# - cualquier otro: GET /orgs/{org}/repos (devuelve los visibles según
|
|
# permisos del PAT en el org)
|
|
|
|
set -euo pipefail
|
|
|
|
# Forzar UTF-8 en stdout de Python (Windows defaultea a cp1252 y crashea con
|
|
# literales no-ASCII). Ver memoria feedback_api_utf8_encoding.md.
|
|
export PYTHONIOENCODING=utf-8
|
|
|
|
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
QUERY="$SKILL_DIR/scripts/query.sh"
|
|
ENV_FILE="$SKILL_DIR/.env"
|
|
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
echo "ERROR: $ENV_FILE no existe. Corré setup.sh primero." >&2
|
|
exit 1
|
|
fi
|
|
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
source "$ENV_FILE"
|
|
set +a
|
|
|
|
: "${GITEA_BOT_USER:?GITEA_BOT_USER no definido en .env. Re-correr setup.sh.}"
|
|
|
|
owner=""
|
|
limit=30
|
|
sort="newest"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--owner) owner="$2"; shift 2 ;;
|
|
--limit) limit="$2"; shift 2 ;;
|
|
--sort) sort="$2"; shift 2 ;;
|
|
-h|--help)
|
|
cat <<EOF
|
|
Uso: repo-list.sh [opciones]
|
|
|
|
Opciones:
|
|
--owner <user|org> Default: bot user (\$GITEA_BOT_USER, "$GITEA_BOT_USER")
|
|
--limit N Default: 30
|
|
--sort <s> newest | oldest | alpha | size (default: newest)
|
|
|
|
Ejemplos:
|
|
repo-list.sh # repos del bot
|
|
repo-list.sh --owner NucleOS # repos del org
|
|
repo-list.sh --limit 10 --sort alpha
|
|
EOF
|
|
exit 0
|
|
;;
|
|
-*) echo "ERROR: flag desconocida: $1" >&2; exit 2 ;;
|
|
*) echo "ERROR: argumento extra: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "$owner" ]] && owner="$GITEA_BOT_USER"
|
|
|
|
# Detectar user vs. org (case-insensitive contra bot user; cualquier otro = org)
|
|
shopt -s nocasematch
|
|
if [[ "$owner" == "$GITEA_BOT_USER" ]]; then
|
|
endpoint="/users/${owner}/repos"
|
|
owner_kind="user (bot)"
|
|
else
|
|
endpoint="/orgs/${owner}/repos"
|
|
owner_kind="org"
|
|
fi
|
|
shopt -u nocasematch
|
|
|
|
# Map sort → param de Gitea
|
|
case "$sort" in
|
|
newest) sort_param="updated" ;;
|
|
oldest) sort_param="oldest" ;;
|
|
alpha) sort_param="alphabetically" ;;
|
|
size) sort_param="size" ;;
|
|
*) echo "ERROR: --sort debe ser newest|oldest|alpha|size" >&2; exit 2 ;;
|
|
esac
|
|
|
|
resp="$("$QUERY" "${endpoint}?limit=${limit}&sort=${sort_param}")"
|
|
|
|
# Detectar error (objeto en vez de array)
|
|
if [[ "${resp:0:1}" == "{" ]]; then
|
|
echo "$resp" | PYTHONIOENCODING=utf-8 python -c "
|
|
import json, sys
|
|
d = json.load(sys.stdin)
|
|
print('ERROR:', d.get('message') or d, file=sys.stderr)
|
|
" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export PY_OWNER="$owner" PY_KIND="$owner_kind" PYTHONIOENCODING=utf-8
|
|
echo "$resp" | python -c '
|
|
import json, os, sys
|
|
repos = json.load(sys.stdin)
|
|
owner = os.environ.get("PY_OWNER", "?")
|
|
kind = os.environ.get("PY_KIND", "?")
|
|
print(f"{len(repos)} repo(s) en {owner} ({kind}):")
|
|
print()
|
|
for r in repos:
|
|
name = r.get("name","?")
|
|
vis = "private" if r.get("private") else "public "
|
|
archived = " [archived]" if r.get("archived") else ""
|
|
template = " [template]" if r.get("template") else ""
|
|
fork = " [fork]" if r.get("fork") else ""
|
|
size_kb = r.get("size", 0)
|
|
if size_kb < 1024:
|
|
size_str = f"{size_kb:>5}KB"
|
|
else:
|
|
size_str = f"{size_kb/1024:>5.1f}MB"
|
|
updated = (r.get("updated_at") or "")[:10]
|
|
desc = (r.get("description") or "").replace("\n", " ")
|
|
if len(desc) > 70: desc = desc[:67] + "..."
|
|
print(f" {name:<26} [{vis}] {size_str} upd {updated}{archived}{template}{fork}")
|
|
if desc:
|
|
print(f" {desc}")
|
|
'
|