Files
fn_registry/bash/functions/shell/report_execution_json.sh
T
egutierrez d7f2c00d7b feat: externalize apps/analysis to Gitea repos, add analysis table
- Migration 007: repo_url on apps table + analysis table with FTS5
- Analysis struct, parser, CRUD, validation, hash computation
- Selective purge: remote-only apps/analysis preserved across fn index
- CLI: fn app list/clone/pull, fn analysis list/clone/pull
- search/show/list now include analysis results
- Apps removed from git tracking (content lives in Gitea repos)
- .gitkeep for apps/ and analysis/ dirs
- Bash functions: jupyter analysis pipeline, shell utilities
- Browser domain: CDP functions moved from infra to browser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 04:23:51 +02:00

211 lines
6.8 KiB
Bash

#!/usr/bin/env bash
# report_execution_json — Genera un JSON de reporte de ejecucion siguiendo el estandar fn-registry.
#
# USO (sourced):
# source report_execution_json.sh
# report_execution_json "backup_db" "partial" 2 \
# "2026-04-01T02:00:00Z" "2026-04-01T02:00:03Z" 3000 /tmp/steps.tsv
#
# USO (ejecutado directamente):
# bash report_execution_json.sh "backup_db" "partial" 2 \
# "2026-04-01T02:00:00Z" "2026-04-01T02:00:03Z" 3000 /tmp/steps.tsv
#
# FORMATO steps_file (TSV sin cabecera, 6 columnas):
# name<TAB>action<TAB>status<TAB>elapsed_ms<TAB>output<TAB>error
# Los campos output y error pueden estar vacios.
# status valido: ok | error
#
# NOTA sobre IFS y tabs: bash trata tab como whitespace en IFS y colapsa
# campos vacios consecutivos. Se usa 'cut -f N' para parsear cada columna
# de forma correcta cuando hay campos vacios entre tabs.
report_execution_json() {
local flow_name="$1"
local status="$2"
local exit_code="$3"
local started_at="$4"
local ended_at="$5"
local duration_ms="$6"
local steps_file="$7"
if [[ -z "$flow_name" || -z "$status" || -z "$exit_code" || \
-z "$started_at" || -z "$ended_at" || -z "$duration_ms" || \
-z "$steps_file" ]]; then
echo "report_execution_json: uso: report_execution_json <flow_name> <status> <exit_code> <started_at> <ended_at> <duration_ms> <steps_file>" >&2
return 1
fi
if [[ ! -f "$steps_file" ]]; then
echo "report_execution_json: archivo de pasos no encontrado: $steps_file" >&2
return 1
fi
if command -v jq >/dev/null 2>&1; then
_report_execution_json_jq \
"$flow_name" "$status" "$exit_code" \
"$started_at" "$ended_at" "$duration_ms" "$steps_file"
else
_report_execution_json_printf \
"$flow_name" "$status" "$exit_code" \
"$started_at" "$ended_at" "$duration_ms" "$steps_file"
fi
}
# --- Implementacion con jq ---
_report_execution_json_jq() {
local flow_name="$1" status="$2" exit_code="$3"
local started_at="$4" ended_at="$5" duration_ms="$6" steps_file="$7"
local steps_ok=0 steps_failed=0
local steps_json="[]"
while IFS= read -r line; do
[[ -z "$line" ]] && continue
local s_name s_action s_status s_elapsed s_output s_error
s_name=$(printf '%s' "$line" | cut -f1)
s_action=$(printf '%s' "$line" | cut -f2)
s_status=$(printf '%s' "$line" | cut -f3)
s_elapsed=$(printf '%s' "$line" | cut -f4)
s_output=$(printf '%s' "$line" | cut -f5)
s_error=$(printf '%s' "$line" | cut -f6)
[[ -z "$s_name" ]] && continue
local step_obj
step_obj=$(jq -n \
--arg name "$s_name" \
--arg action "$s_action" \
--arg st "$s_status" \
--argjson ms "${s_elapsed:-0}" \
--arg output "$s_output" \
--arg error "$s_error" \
'{name: $name, action: $action, status: $st, elapsed_ms: $ms}
+ (if $output != "" then {output: $output} else {} end)
+ (if $error != "" then {error: $error} else {} end)')
steps_json=$(printf '%s' "$steps_json" | jq --argjson step "$step_obj" '. + [$step]')
if [[ "$s_status" == "ok" ]]; then
((steps_ok++))
else
((steps_failed++))
fi
done < "$steps_file"
local steps_total=$(( steps_ok + steps_failed ))
jq -n \
--arg name "$flow_name" \
--arg st "$status" \
--argjson exit_code "$exit_code" \
--arg started_at "$started_at" \
--arg ended_at "$ended_at" \
--argjson duration_ms "$duration_ms" \
--argjson total "$steps_total" \
--argjson ok "$steps_ok" \
--argjson failed "$steps_failed" \
--argjson steps "$steps_json" \
'{
name: $name,
status: $st,
exit_code: $exit_code,
started_at: $started_at,
ended_at: $ended_at,
duration_ms: $duration_ms,
steps_total: $total,
steps_ok: $ok,
steps_failed: $failed,
steps: $steps
}'
}
# --- Implementacion con printf (fallback sin jq) ---
_json_escape_rj() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\r'/\\r}"
s="${s//$'\t'/\\t}"
printf '%s' "$s"
}
_report_execution_json_printf() {
local flow_name="$1" status="$2" exit_code="$3"
local started_at="$4" ended_at="$5" duration_ms="$6" steps_file="$7"
local steps_ok=0 steps_failed=0
local steps_parts=()
while IFS= read -r line; do
[[ -z "$line" ]] && continue
local s_name s_action s_status s_elapsed s_output s_error
s_name=$(printf '%s' "$line" | cut -f1)
s_action=$(printf '%s' "$line" | cut -f2)
s_status=$(printf '%s' "$line" | cut -f3)
s_elapsed=$(printf '%s' "$line" | cut -f4)
s_output=$(printf '%s' "$line" | cut -f5)
s_error=$(printf '%s' "$line" | cut -f6)
[[ -z "$s_name" ]] && continue
local part
part=$(printf '{"name":"%s","action":"%s","status":"%s","elapsed_ms":%s' \
"$(_json_escape_rj "$s_name")" \
"$(_json_escape_rj "$s_action")" \
"$(_json_escape_rj "$s_status")" \
"${s_elapsed:-0}")
if [[ -n "$s_output" ]]; then
part+=",\"output\":\"$(_json_escape_rj "$s_output")\""
fi
if [[ -n "$s_error" ]]; then
part+=",\"error\":\"$(_json_escape_rj "$s_error")\""
fi
part+="}"
steps_parts+=("$part")
if [[ "$s_status" == "ok" ]]; then
((steps_ok++))
else
((steps_failed++))
fi
done < "$steps_file"
local steps_total=$(( steps_ok + steps_failed ))
local steps_array="["
local first=1
for part in "${steps_parts[@]}"; do
if [[ $first -eq 1 ]]; then
steps_array+="$part"
first=0
else
steps_array+=",$part"
fi
done
steps_array+="]"
printf '{"name":"%s","status":"%s","exit_code":%s,"started_at":"%s","ended_at":"%s","duration_ms":%s,"steps_total":%s,"steps_ok":%s,"steps_failed":%s,"steps":%s}\n' \
"$(_json_escape_rj "$flow_name")" \
"$(_json_escape_rj "$status")" \
"$exit_code" \
"$(_json_escape_rj "$started_at")" \
"$(_json_escape_rj "$ended_at")" \
"$duration_ms" \
"$steps_total" \
"$steps_ok" \
"$steps_failed" \
"$steps_array"
}
# Permitir ejecucion directa (no solo sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
report_execution_json "$@"
fi