Files
fn_registry/bash/functions/pipelines/full_git_pull.sh
T
egutierrez 2a3d780347 feat(doctor): add fn doctor CLI + 14 functions for system management
Adds `fn doctor` read-only diagnostic command with subcommands artefacts,
services, sync, uses-functions, unused, and --json flag for agents.
Each subcommand wraps a registry function in functions/infra/.

New functions:
- artefact_doctor, services_status, pc_locations_drift,
  audit_uses_functions, find_unused_functions (Go diagnostics)
- backup_sqlite_db, rotate_backups, wait_for_http, wait_for_port,
  port_kill, tail_journal, pre_commit_hook_install (bash utilities)
- notify_telegram (Go HTTP)
- backup_all pipeline (tag launcher)

Plus prior session leftovers (scan_secrets_in_dirty, append_diary_entry,
git utilities, http_session_cookie_middleware, compile/full-git pipelines).

Fixes pc_locations_drift filepath.Join bug with absolute dir_path.
Documents fn doctor in CLAUDE.md, .claude/rules/fn_doctor.md (rule 23),
docs/architecture.md, CHANGELOG.md (2026-05-07), and diary entry.

First fn doctor uses-functions run found drift in 7/12 apps (deuda
para sincronizar app.md con imports reales).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 01:42:10 +02:00

168 lines
5.7 KiB
Bash

#!/usr/bin/env bash
# Pipeline: full_git_pull — Pull automatico de fn_registry + sub-repos + submodules + fn sync
# Descubre repos locales, stashea dirty trees, hace pull --ff-only, actualiza submodules,
# regenera registry.db y ejecuta fn sync.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INFRA_DIR="$SCRIPT_DIR/../infra"
source "$INFRA_DIR/discover_git_repos.sh"
source "$INFRA_DIR/git_pull_with_stash.sh"
source "$INFRA_DIR/pass_get.sh"
full_git_pull() {
# Resolver raiz del registry
local registry_root="${FN_REGISTRY_ROOT:-/home/lucas/fn_registry}"
cd "$registry_root"
echo "=== full_git_pull: inicio ===" >&2
echo "Registry root: $registry_root" >&2
# --- Paso 1: Descubrir repos ---
echo "" >&2
echo "[1/5] Descubriendo repos git..." >&2
local repos
repos=$(discover_git_repos "$registry_root")
local n_repos
n_repos=$(echo "$repos" | grep -c . || true)
echo " Encontrados: $n_repos repos" >&2
# --- Paso 2: Pull de cada repo ---
echo "" >&2
echo "[2/5] Pullando repos..." >&2
local pull_summary=""
local diverged=()
local conflicts=()
while IFS= read -r repo; do
[[ -z "$repo" ]] && continue
local result
result=$(git_pull_with_stash "$repo" 2>/dev/null || true)
if [[ -n "$result" ]]; then
echo " $result" >&2
pull_summary="$pull_summary"$'\n'" $result"
if [[ "$result" == "[diverged]"* ]]; then
diverged+=("$repo")
elif [[ "$result" == "[stash-conflict]"* ]]; then
conflicts+=("$repo")
fi
fi
done <<< "$repos"
# --- Paso 3: Submodules del repo principal ---
echo "" >&2
echo "[3/5] Actualizando submodulos del repo principal..." >&2
local submodule_summary=" [skip] sin submodulos"
if [[ -f "$registry_root/.gitmodules" ]]; then
local sub_out
sub_out=$(git -C "$registry_root" submodule update --init --recursive 2>&1 | tail -10 || true)
echo "$sub_out" >&2
submodule_summary=" OK: $sub_out"
fi
# --- Paso 3b: Pull de ~/.password-store ---
echo "" >&2
echo "[3b] Pullando ~/.password-store..." >&2
local pass_dir="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
local pass_summary=" [skip] password-store: no encontrado"
if [[ -d "$pass_dir/.git" ]]; then
local pass_result
pass_result=$(git_pull_with_stash "$pass_dir" 2>/dev/null || true)
echo " $pass_result" >&2
pass_summary=" $pass_result"
if [[ "$pass_result" == "[diverged]"* ]]; then
diverged+=("$pass_dir")
elif [[ "$pass_result" == "[stash-conflict]"* ]]; then
conflicts+=("$pass_dir")
fi
fi
# --- Paso 4: Regenerar registry.db ---
echo "" >&2
echo "[4/5] Regenerando registry.db..." >&2
local index_summary=" [skip] fn no encontrado"
local fn_bin="$registry_root/fn"
if [[ -x "$fn_bin" ]]; then
local index_out
index_out=$(CGO_ENABLED=1 "$fn_bin" index 2>&1 | tail -3 || true)
echo "$index_out" >&2
index_summary=" OK: $index_out"
else
echo " [warn] $fn_bin no encontrado — intentando build..." >&2
if command -v go >/dev/null 2>&1; then
CGO_ENABLED=1 go build -tags fts5 -o "$fn_bin" "$registry_root/cmd/fn/" 2>&1 >&2 || true
if [[ -x "$fn_bin" ]]; then
local index_out
index_out=$(CGO_ENABLED=1 "$fn_bin" index 2>&1 | tail -3 || true)
echo "$index_out" >&2
index_summary=" OK (post-build): $index_out"
fi
fi
fi
# --- Paso 5: fn sync ---
echo "" >&2
echo "[5/5] Ejecutando fn sync..." >&2
local sync_summary=" [skip] fn sync: credenciales no disponibles"
if [[ -x "$fn_bin" ]]; then
local api_user api_pass api_token
api_user=$(pass_get registry/basicauth-user | head -n1 2>/dev/null || true)
api_pass=$(pass_get registry/basicauth-pass | head -n1 2>/dev/null || true)
api_token=$(pass_get registry/api-token | head -n1 2>/dev/null || true)
if [[ -n "$api_user" && -n "$api_pass" && -n "$api_token" ]]; then
export FN_REGISTRY_API="https://${api_user}:${api_pass}@registry.organic-machine.com"
export REGISTRY_API_TOKEN="$api_token"
local sync_out
sync_out=$("$fn_bin" sync 2>&1) && {
sync_summary=" OK: $sync_out"
} || {
sync_summary=" [error] fn sync: $sync_out"
}
echo " $sync_summary" >&2
else
echo " [warn] Credenciales registry no disponibles — omitiendo fn sync" >&2
fi
fi
# --- Resumen ---
echo ""
echo "===== RESUMEN full_git_pull ====="
echo ""
echo "Pull status por repo:"
if [[ -n "$pull_summary" ]]; then
echo "$pull_summary"
else
echo " (ninguno)"
fi
echo ""
echo "pass-secrets:"
echo "$pass_summary"
echo ""
echo "Submodulos:"
echo "$submodule_summary"
echo ""
echo "fn index:"
echo "$index_summary"
echo ""
echo "fn sync:"
echo "$sync_summary"
if [[ ${#diverged[@]} -gt 0 || ${#conflicts[@]} -gt 0 ]]; then
echo ""
echo "ATENCION — Repos que requieren intervencion manual:"
for r in "${diverged[@]+"${diverged[@]}"}"; do
echo " [diverged] $r → git rebase o git merge manual"
done
for r in "${conflicts[@]+"${conflicts[@]}"}"; do
echo " [stash-conflict] $r → resolver conflicto y git stash drop"
done
fi
echo ""
echo "================================="
}
full_git_pull "$@"