diff --git a/bash/functions/infra/gitea_create_webhook.md b/bash/functions/infra/gitea_create_webhook.md new file mode 100644 index 00000000..f519e42e --- /dev/null +++ b/bash/functions/infra/gitea_create_webhook.md @@ -0,0 +1,50 @@ +--- +name: gitea_create_webhook +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "gitea_create_webhook(owner: string, repo: string, target_url: string, secret?: string) -> json" +description: "Crea un webhook de push en un repositorio Gitea. El webhook notifica a target_url en cada push." +tags: [gitea, webhook, push, deploy, ci, infra] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: owner + desc: "usuario u organización propietaria del repositorio" + - name: repo + desc: "nombre del repositorio" + - name: target_url + desc: "URL que recibirá el POST del webhook en cada push" + - name: secret + desc: "secreto compartido para firmar el payload (opcional)" +output: "JSON con webhook_id, owner, repo, target_url" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/gitea_create_webhook.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/gitea_create_webhook.sh + +export GITEA_URL="https://git.example.com" +export GITEA_TOKEN="$(pass agentes/dataforge-token)" + +# Crear webhook para auto-deploy +gitea_create_webhook "myorg" "dag_engine" "http://vps:9090/webhook/push" "mi_secreto" +# {"webhook_id":42,"owner":"myorg","repo":"dag_engine","target_url":"http://vps:9090/webhook/push"} +``` + +## Notas + +- Requiere `GITEA_URL` y `GITEA_TOKEN` como variables de entorno. +- Solo escucha eventos `push`. Para otros eventos, modificar el array `events` en el payload. +- Si el webhook ya existe para la misma URL, Gitea crea uno duplicado (no es idempotente). diff --git a/bash/functions/infra/gitea_create_webhook.sh b/bash/functions/infra/gitea_create_webhook.sh new file mode 100644 index 00000000..89abd53f --- /dev/null +++ b/bash/functions/infra/gitea_create_webhook.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# gitea_create_webhook — Crea un webhook de push en un repositorio Gitea +set -euo pipefail + +gitea_create_webhook() { + local owner="$1" + local repo="$2" + local target_url="$3" + local secret="${4:-}" + + if [[ -z "$owner" || -z "$repo" || -z "$target_url" ]]; then + echo "usage: gitea_create_webhook [secret]" >&2 + return 1 + fi + + local gitea_url="${GITEA_URL:?GITEA_URL no seteada}" + local gitea_token="${GITEA_TOKEN:?GITEA_TOKEN no seteada}" + + # Payload JSON para el webhook + local payload + payload=$(cat <&2 + return 1 + fi +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + gitea_create_webhook "$@" +fi diff --git a/bash/functions/infra/rsync_deploy.md b/bash/functions/infra/rsync_deploy.md new file mode 100644 index 00000000..6d88fa46 --- /dev/null +++ b/bash/functions/infra/rsync_deploy.md @@ -0,0 +1,52 @@ +--- +name: rsync_deploy +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "rsync_deploy(local_dir: string, ssh_alias: string, remote_dir: string) -> json" +description: "Sincroniza un directorio local a un host remoto via rsync+SSH. Excluye archivos de desarrollo y bases de datos locales. Crea el directorio remoto si no existe." +tags: [rsync, deploy, sync, ssh, remote, infra] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: local_dir + desc: "ruta al directorio local a sincronizar (ej: apps/dag_engine/)" + - name: ssh_alias + desc: "alias SSH del host destino definido en ~/.ssh/config (ej: myserver)" + - name: remote_dir + desc: "ruta absoluta del directorio destino en el host remoto (ej: /opt/apps/dag_engine)" +output: "JSON con files_transferred (int), total_size (string), ssh_alias (string), remote_dir (string)" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/rsync_deploy.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/rsync_deploy.sh + +# Deploy de una app al servidor de producción +result=$(rsync_deploy "apps/dag_engine/" "prod-server" "/opt/apps/dag_engine") +echo "$result" +# {"files_transferred": 12, "total_size": "1.23 MB", "ssh_alias": "prod-server", "remote_dir": "/opt/apps/dag_engine"} + +# Deploy con ruta absoluta local +rsync_deploy "/home/lucas/fn_registry/apps/myapp/" "myserver" "/opt/myapp" +``` + +## Notas + +- Usa `rsync -avz --delete`: archivos borrados localmente se borran también en el remoto. +- Antes del rsync crea el directorio remoto con `ssh mkdir -p` para evitar errores si no existe. +- Archivos excluidos: `.git`, `operations.db*`, `*.exe`, `node_modules`, `.venv`, `__pycache__`, `build/`, `*.db-shm`, `*.db-wal`. +- El JSON de salida va a stdout; los mensajes de progreso y errores van a stderr. +- Exit code 1 si rsync falla o si el directorio local no existe. +- El `ssh_alias` se resuelve con la configuración de `~/.ssh/config`, incluyendo host, user, identityfile y puerto. diff --git a/bash/functions/infra/rsync_deploy.sh b/bash/functions/infra/rsync_deploy.sh new file mode 100644 index 00000000..70bbe40d --- /dev/null +++ b/bash/functions/infra/rsync_deploy.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# rsync_deploy — Sincroniza un directorio local a un host remoto via rsync+SSH +set -euo pipefail + +rsync_deploy() { + local local_dir="$1" + local ssh_alias="$2" + local remote_dir="$3" + + if [[ -z "$local_dir" || -z "$ssh_alias" || -z "$remote_dir" ]]; then + echo "rsync_deploy: se requieren local_dir, ssh_alias y remote_dir" >&2 + return 1 + fi + + if [[ ! -d "$local_dir" ]]; then + echo "rsync_deploy: directorio local '$local_dir' no existe" >&2 + return 1 + fi + + # Crear directorio remoto si no existe + echo "rsync_deploy: verificando directorio remoto '$remote_dir' en '$ssh_alias'..." >&2 + if ! ssh "$ssh_alias" "mkdir -p '$remote_dir'" 2>&1; then + echo "rsync_deploy: no se pudo crear el directorio remoto '$remote_dir' en '$ssh_alias'" >&2 + return 1 + fi + + # Ejecutar rsync y capturar salida para parsear estadísticas + local rsync_output + rsync_output=$(rsync -avz --delete \ + --exclude='.git' \ + --exclude='operations.db*' \ + --exclude='*.exe' \ + --exclude='node_modules' \ + --exclude='.venv' \ + --exclude='__pycache__' \ + --exclude='build/' \ + --exclude='*.db-shm' \ + --exclude='*.db-wal' \ + -e ssh \ + "$local_dir" \ + "${ssh_alias}:${remote_dir}" 2>&1) || { + echo "rsync_deploy: rsync falló al sincronizar '$local_dir' → '${ssh_alias}:${remote_dir}'" >&2 + echo "$rsync_output" >&2 + return 1 + } + + echo "$rsync_output" >&2 + + # Parsear número de archivos transferidos + local files_transferred + files_transferred=$(echo "$rsync_output" | grep -oP 'Number of regular files transferred: \K[0-9,]+' | tr -d ',' || echo "0") + if [[ -z "$files_transferred" ]]; then + # Intentar formato alternativo de rsync + files_transferred=$(echo "$rsync_output" | grep -oP 'Number of files transferred: \K[0-9,]+' | tr -d ',' || echo "0") + fi + if [[ -z "$files_transferred" ]]; then + files_transferred="0" + fi + + # Parsear tamaño total transferido + local total_size + total_size=$(echo "$rsync_output" | grep -oP 'Total transferred file size: \K[0-9,.]+ \w+' || echo "0 bytes") + if [[ -z "$total_size" ]]; then + total_size="0 bytes" + fi + + # Emitir JSON a stdout + printf '{"files_transferred": %s, "total_size": "%s", "ssh_alias": "%s", "remote_dir": "%s"}\n' \ + "$files_transferred" \ + "$total_size" \ + "$ssh_alias" \ + "$remote_dir" +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + rsync_deploy "$@" +fi