import: contenido inicial de la skill gitea
This commit is contained in:
219
scripts/repo-create.sh
Normal file
219
scripts/repo-create.sh
Normal file
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env bash
|
||||
# gitea skill — crear un repo en gitea.nucleoriofrio.com.
|
||||
#
|
||||
# Soporta dos targets:
|
||||
# - usuario autenticado (claudecode0): POST /api/v1/user/repos
|
||||
# - org (NucleOS u otra): POST /api/v1/orgs/{org}/repos
|
||||
#
|
||||
# Regla dura: cualquier repo bajo el usuario `claudecode0` (case-insensitive
|
||||
# match con $GITEA_BOT_USER) DEBE ser público. La justificación es que el
|
||||
# usuario humano necesita poder ver lo que el bot crea — sino la cuenta
|
||||
# claudecode0 sería una caja negra. Si pasás --private a un repo bajo el bot,
|
||||
# el script aborta con exit 5.
|
||||
#
|
||||
# Para repos en orgs, --public o --private es REQUERIDO (forzar decisión
|
||||
# explícita; sin default sorpresa).
|
||||
#
|
||||
# Uso:
|
||||
# repo-create.sh <name> [--owner <user|org>] [--description "..."]
|
||||
# [--public | --private] [--no-init] [--license <tpl>]
|
||||
# [--gitignore <tpl>] [--default-branch <name>] [--template]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
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.}"
|
||||
|
||||
name=""
|
||||
owner=""
|
||||
description=""
|
||||
visibility="" # "public" | "private" | ""
|
||||
auto_init=1
|
||||
license=""
|
||||
gitignore=""
|
||||
default_branch="main"
|
||||
is_template=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--owner) owner="$2"; shift 2 ;;
|
||||
--description) description="$2"; shift 2 ;;
|
||||
--public) visibility="public"; shift ;;
|
||||
--private) visibility="private"; shift ;;
|
||||
--no-init) auto_init=0; shift ;;
|
||||
--license) license="$2"; shift 2 ;;
|
||||
--gitignore) gitignore="$2"; shift 2 ;;
|
||||
--default-branch) default_branch="$2"; shift 2 ;;
|
||||
--template) is_template=1; shift ;;
|
||||
-h|--help)
|
||||
cat <<EOF
|
||||
Uso: repo-create.sh <name> [opciones]
|
||||
|
||||
Argumentos:
|
||||
<name> Nombre del repo (requerido)
|
||||
|
||||
Owner:
|
||||
--owner <user|org> Default: el usuario del bot (\$GITEA_BOT_USER, "$GITEA_BOT_USER")
|
||||
Pasale "NucleOS" para crear en el org.
|
||||
|
||||
Visibilidad:
|
||||
--public | --private Para orgs, uno es REQUERIDO (sin default).
|
||||
Para el usuario del bot, --private está
|
||||
BLOQUEADO (regla dura: todo lo del bot debe ser
|
||||
público para que el usuario humano pueda verlo).
|
||||
|
||||
Contenido:
|
||||
--description "..." Descripción del repo
|
||||
--no-init No crear README inicial (default: auto-init=true)
|
||||
--license <template> ej. "MIT", "Apache-2.0", "GPL-3.0"
|
||||
--gitignore <template> ej. "Node", "Python", "Go"
|
||||
--default-branch <name> default: main
|
||||
--template Marcar como template repo
|
||||
|
||||
Devuelve URL del repo creado (clone_url + html_url).
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
-*) echo "ERROR: flag desconocida: $1" >&2; exit 2 ;;
|
||||
*)
|
||||
if [[ -z "$name" ]]; then name="$1"
|
||||
else echo "ERROR: argumento extra: $1" >&2; exit 2
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$name" ]]; then
|
||||
echo "ERROR: pasá <name>." >&2
|
||||
echo "Uso: repo-create.sh <name> [opciones] (--help para detalles)" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Default owner = bot user
|
||||
if [[ -z "$owner" ]]; then
|
||||
owner="$GITEA_BOT_USER"
|
||||
fi
|
||||
|
||||
# ─── Detectar si owner es el bot (case-insensitive) ─────────────────────
|
||||
shopt -s nocasematch
|
||||
is_bot_owner=0
|
||||
if [[ "$owner" == "$GITEA_BOT_USER" ]]; then
|
||||
is_bot_owner=1
|
||||
fi
|
||||
shopt -u nocasematch
|
||||
|
||||
# ─── Guard: visibilidad ─────────────────────────────────────────────────
|
||||
if [[ "$is_bot_owner" -eq 1 ]]; then
|
||||
# Regla dura: bot user → siempre público
|
||||
if [[ "$visibility" == "private" ]]; then
|
||||
cat >&2 <<EOF
|
||||
ERROR: --private bloqueado para repos bajo el usuario del bot ($GITEA_BOT_USER).
|
||||
|
||||
Regla dura de la skill: todo lo que el bot crea bajo su propio usuario debe
|
||||
ser PÚBLICO para que el usuario humano pueda auditarlo. Sin esa regla, la
|
||||
cuenta del bot sería una caja negra.
|
||||
|
||||
Opciones:
|
||||
- Crearlo público (omitir --private; será público por default)
|
||||
- Crearlo en una org en vez del usuario del bot:
|
||||
repo-create.sh $name --owner NucleOS --private
|
||||
EOF
|
||||
exit 5
|
||||
fi
|
||||
# Default: público
|
||||
visibility="public"
|
||||
else
|
||||
# Org u otro user → visibilidad explícita requerida (sin default sorpresa)
|
||||
if [[ -z "$visibility" ]]; then
|
||||
cat >&2 <<EOF
|
||||
ERROR: para repos en una org (owner=$owner), --public o --private es REQUERIDO.
|
||||
|
||||
Sin default para evitar sorpresas. Pasá una flag explícita:
|
||||
repo-create.sh $name --owner $owner --public
|
||||
repo-create.sh $name --owner $owner --private
|
||||
EOF
|
||||
exit 6
|
||||
fi
|
||||
fi
|
||||
|
||||
# Convertir visibilidad → boolean private
|
||||
case "$visibility" in
|
||||
public) is_private="false" ;;
|
||||
private) is_private="true" ;;
|
||||
*) echo "ERROR interno: visibility=$visibility" >&2; exit 99 ;;
|
||||
esac
|
||||
|
||||
# ─── Construir endpoint ─────────────────────────────────────────────────
|
||||
if [[ "$is_bot_owner" -eq 1 ]]; then
|
||||
endpoint="/user/repos"
|
||||
else
|
||||
endpoint="/orgs/${owner}/repos"
|
||||
fi
|
||||
|
||||
# ─── Build body con Python (UTF-8 safe, mismo patrón que pr-create) ─────
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
BODY_JSON="$TMP_DIR/body.json"
|
||||
|
||||
PY_NAME="$name" PY_DESC="$description" PY_PRIVATE="$is_private" \
|
||||
PY_AUTO_INIT="$auto_init" PY_LICENSE="$license" PY_GITIGNORE="$gitignore" \
|
||||
PY_DEFAULT_BRANCH="$default_branch" PY_TEMPLATE="$is_template" \
|
||||
python -c '
|
||||
import json, os
|
||||
data = {
|
||||
"name": os.environ["PY_NAME"],
|
||||
"description": os.environ.get("PY_DESC", ""),
|
||||
"private": os.environ["PY_PRIVATE"] == "true",
|
||||
"auto_init": os.environ["PY_AUTO_INIT"] == "1",
|
||||
"default_branch": os.environ["PY_DEFAULT_BRANCH"],
|
||||
"template": os.environ["PY_TEMPLATE"] == "1",
|
||||
}
|
||||
if os.environ.get("PY_LICENSE"):
|
||||
data["license"] = os.environ["PY_LICENSE"]
|
||||
if os.environ.get("PY_GITIGNORE"):
|
||||
data["gitignores"] = os.environ["PY_GITIGNORE"]
|
||||
print(json.dumps(data))
|
||||
' > "$BODY_JSON"
|
||||
|
||||
# ─── POST ───────────────────────────────────────────────────────────────
|
||||
echo "→ POST $endpoint" >&2
|
||||
echo " name: $name" >&2
|
||||
echo " owner: $owner $([ "$is_bot_owner" -eq 1 ] && echo "(bot user)" || echo "(org)")" >&2
|
||||
echo " visibility: $visibility" >&2
|
||||
echo " auto_init: $auto_init default_branch: $default_branch" >&2
|
||||
[[ -n "$description" ]] && echo " description: $description" >&2
|
||||
[[ -n "$license" ]] && echo " license: $license" >&2
|
||||
[[ -n "$gitignore" ]] && echo " gitignore: $gitignore" >&2
|
||||
|
||||
resp="$("$QUERY" -X POST \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
--data-binary @"$BODY_JSON" \
|
||||
"$endpoint")"
|
||||
|
||||
echo "$resp" | PYTHONIOENCODING=utf-8 python -c "
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
if d.get('id') and d.get('full_name'):
|
||||
visibility_label = 'private' if d.get('private') else 'public'
|
||||
print(f'OK repo creado: {d[\"full_name\"]} ({visibility_label})')
|
||||
print(f' html_url: {d.get(\"html_url\")}')
|
||||
print(f' clone_url: {d.get(\"clone_url\")}')
|
||||
print(f' ssh_url: {d.get(\"ssh_url\")}')
|
||||
else:
|
||||
print('ERROR:', d.get('message') or d, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"
|
||||
Reference in New Issue
Block a user